Merge "Eliminate redundant changes to hardware vsync state."
diff --git a/Android.bp b/Android.bp
index cd05b21..de9ea86 100644
--- a/Android.bp
+++ b/Android.bp
@@ -8,8 +8,15 @@
subdirs = [
"cmds/*",
+ "headers",
"libs/*",
"opengl",
"services/*",
"vulkan",
]
+
+cc_library_headers {
+ name: "libandroid_sensor_headers",
+ vendor: true,
+ export_include_dirs: ["include_sensor"],
+}
diff --git a/cmds/atrace/Android.bp b/cmds/atrace/Android.bp
index 5548699..b850390 100644
--- a/cmds/atrace/Android.bp
+++ b/cmds/atrace/Android.bp
@@ -3,6 +3,10 @@
cc_binary {
name: "atrace",
srcs: ["atrace.cpp"],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
shared_libs: [
"libbinder",
@@ -11,9 +15,13 @@
"libhidltransport",
"liblog",
"libutils",
+ "libcutils",
"libz",
"libbase",
],
+ static_libs: [
+ "libpdx_default_transport",
+ ],
init_rc: ["atrace.rc"],
diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp
index 301bb67..1b90579 100644
--- a/cmds/atrace/atrace.cpp
+++ b/cmds/atrace/atrace.cpp
@@ -40,6 +40,7 @@
#include <android/hidl/manager/1.0/IServiceManager.h>
#include <hidl/ServiceManagement.h>
+#include <pdx/default_transport/service_utility.h>
#include <utils/String8.h>
#include <utils/Timers.h>
#include <utils/Tokenizer.h>
@@ -50,6 +51,7 @@
#include <android-base/stringprintf.h>
using namespace android;
+using pdx::default_transport::ServiceUtility;
using std::string;
@@ -61,6 +63,7 @@
const char* k_traceAppsNumberProperty = "debug.atrace.app_number";
const char* k_traceAppsPropertyTemplate = "debug.atrace.app_%d";
const char* k_coreServiceCategory = "core_services";
+const char* k_pdxServiceCategory = "pdx";
const char* k_coreServicesProp = "ro.atrace.core.services";
typedef enum { OPT, REQ } requiredness ;
@@ -114,16 +117,27 @@
{ "network", "Network", ATRACE_TAG_NETWORK, { } },
{ "adb", "ADB", ATRACE_TAG_ADB, { } },
{ k_coreServiceCategory, "Core services", 0, { } },
+ { k_pdxServiceCategory, "PDX services", 0, { } },
{ "sched", "CPU Scheduling", 0, {
{ REQ, "events/sched/sched_switch/enable" },
{ REQ, "events/sched/sched_wakeup/enable" },
+ { OPT, "events/sched/sched_waking/enable" },
{ OPT, "events/sched/sched_blocked_reason/enable" },
{ OPT, "events/sched/sched_cpu_hotplug/enable" },
+ { OPT, "events/cgroup/enable" },
} },
{ "irq", "IRQ Events", 0, {
{ REQ, "events/irq/enable" },
{ OPT, "events/ipi/enable" },
} },
+ { "irqoff", "IRQ-disabled code section tracing", 0, {
+ { REQ, "events/preemptirq/irq_enable/enable" },
+ { REQ, "events/preemptirq/irq_disable/enable" },
+ } },
+ { "preemptoff", "Preempt-disabled code section tracing", 0, {
+ { REQ, "events/preemptirq/preempt_enable/enable" },
+ { REQ, "events/preemptirq/preempt_disable/enable" },
+ } },
{ "i2c", "I2C Events", 0, {
{ REQ, "events/i2c/enable" },
{ REQ, "events/i2c/i2c_read/enable" },
@@ -138,6 +152,8 @@
{ "freq", "CPU Frequency", 0, {
{ REQ, "events/power/cpu_frequency/enable" },
{ OPT, "events/power/clock_set_rate/enable" },
+ { OPT, "events/power/clock_disable/enable" },
+ { OPT, "events/power/clock_enable/enable" },
{ OPT, "events/power/cpu_frequency_limits/enable" },
} },
{ "membus", "Memory Bus Utilization", 0, {
@@ -208,6 +224,7 @@
static const char* g_outputFile = nullptr;
/* Global state */
+static bool g_tracePdx = false;
static bool g_traceAborted = false;
static bool g_categoryEnables[arraysize(k_categories)] = {};
static std::string g_traceFolder;
@@ -219,6 +236,12 @@
static const char* k_traceBufferSizePath =
"buffer_size_kb";
+#if 0
+// TODO: Re-enable after stabilization
+static const char* k_traceCmdlineSizePath =
+ "saved_cmdlines_size";
+#endif
+
static const char* k_tracingOverwriteEnablePath =
"options/overwrite";
@@ -240,9 +263,6 @@
static const char* k_funcgraphFlatPath =
"options/funcgraph-flat";
-static const char* k_funcgraphDurationPath =
- "options/funcgraph-duration";
-
static const char* k_ftraceFilterPath =
"set_ftrace_filter";
@@ -364,6 +384,10 @@
return !android::base::GetProperty(k_coreServicesProp, "").empty();
}
+ if (strcmp(category.name, k_pdxServiceCategory) == 0) {
+ return true;
+ }
+
bool ok = category.tags != 0;
for (int i = 0; i < MAX_SYS_FILES; i++) {
const char* path = category.sysfiles[i].path;
@@ -431,7 +455,6 @@
static bool setTraceBufferSizeKB(int size)
{
char str[32] = "1";
- int len;
if (size < 1) {
size = 1;
}
@@ -439,6 +462,18 @@
return writeStr(k_traceBufferSizePath, str);
}
+#if 0
+// TODO: Re-enable after stabilization
+// Set the default size of cmdline hashtable
+static bool setCmdlineSize()
+{
+ if (fileExists(k_traceCmdlineSizePath)) {
+ return writeStr(k_traceCmdlineSizePath, "8192");
+ }
+ return true;
+}
+#endif
+
// Set the clock to the best available option while tracing. Use 'boot' if it's
// available; otherwise, use 'mono'. If neither are available use 'global'.
// Any write to the trace_clock sysfs file will reset the buffer, so only
@@ -458,8 +493,8 @@
newClock = "global";
}
- size_t begin = clockStr.find("[") + 1;
- size_t end = clockStr.find("]");
+ size_t begin = clockStr.find('[') + 1;
+ size_t end = clockStr.find(']');
if (newClock.compare(0, std::string::npos, clockStr, begin, end-begin) == 0) {
return true;
}
@@ -520,7 +555,7 @@
auto listRet = sm->list([&](const auto &interfaces) {
for (size_t i = 0; i < interfaces.size(); i++) {
string fqInstanceName = interfaces[i];
- string::size_type n = fqInstanceName.find("/");
+ string::size_type n = fqInstanceName.find('/');
if (n == std::string::npos || interfaces[i].size() == n+1)
continue;
hidl_string fqInterfaceName = fqInstanceName.substr(0, n);
@@ -756,6 +791,8 @@
ok &= setCategoriesEnableFromFile(g_categoriesFile);
ok &= setTraceOverwriteEnable(g_traceOverwrite);
ok &= setTraceBufferSizeKB(g_traceBufferSizeKB);
+ // TODO: Re-enable after stabilization
+ //ok &= setCmdlineSize();
ok &= setClock();
ok &= setPrintTgidEnableIfPresent(true);
ok &= setKernelTraceFuncs(g_kernelTraceFuncs);
@@ -775,6 +812,11 @@
if (strcmp(k_categories[i].name, k_coreServiceCategory) == 0) {
coreServicesTagEnabled = g_categoryEnables[i];
}
+
+ // Set whether to poke PDX services in this session.
+ if (strcmp(k_categories[i].name, k_pdxServiceCategory) == 0) {
+ g_tracePdx = g_categoryEnables[i];
+ }
}
std::string packageList(g_debugAppCmdLine);
@@ -788,6 +830,10 @@
ok &= pokeBinderServices();
pokeHalServices();
+ if (g_tracePdx) {
+ ok &= ServiceUtility::PokeServices();
+ }
+
// Disable all the sysfs enables. This is done as a separate loop from
// the enables to allow the same enable to exist in multiple categories.
ok &= disableKernelTraceEvents();
@@ -825,6 +871,10 @@
clearAppProperties();
pokeBinderServices();
+ if (g_tracePdx) {
+ ServiceUtility::PokeServices();
+ }
+
// Set the options back to their defaults.
setTraceOverwriteEnable(true);
setTraceBufferSizeKB(1);
diff --git a/cmds/atrace/atrace.rc b/cmds/atrace/atrace.rc
index 1e0f6f8..3ea1d56 100644
--- a/cmds/atrace/atrace.rc
+++ b/cmds/atrace/atrace.rc
@@ -15,6 +15,8 @@
chown root shell /sys/kernel/tracing/options/overwrite
chown root shell /sys/kernel/debug/tracing/options/print-tgid
chown root shell /sys/kernel/tracing/options/print-tgid
+ chown root shell /sys/kernel/debug/tracing/saved_cmdlines_size
+ chown root shell /sys/kernel/tracing/saved_cmdlines_size
chown root shell /sys/kernel/debug/tracing/events/sched/sched_switch/enable
chown root shell /sys/kernel/tracing/events/sched/sched_switch/enable
chown root shell /sys/kernel/debug/tracing/events/sched/sched_wakeup/enable
@@ -23,6 +25,8 @@
chown root shell /sys/kernel/tracing/events/sched/sched_blocked_reason/enable
chown root shell /sys/kernel/debug/tracing/events/sched/sched_cpu_hotplug/enable
chown root shell /sys/kernel/tracing/events/sched/sched_cpu_hotplug/enable
+ chown root shell /sys/kernel/debug/tracing/events/cgroup/enable
+ chown root shell /sys/kernel/tracing/events/cgroup/enable
chown root shell /sys/kernel/debug/tracing/events/power/cpu_frequency/enable
chown root shell /sys/kernel/tracing/events/power/cpu_frequency/enable
chown root shell /sys/kernel/debug/tracing/events/power/cpu_idle/enable
@@ -65,6 +69,8 @@
chmod 0664 /sys/kernel/tracing/options/overwrite
chmod 0664 /sys/kernel/debug/tracing/options/print-tgid
chmod 0664 /sys/kernel/tracing/options/print-tgid
+ chmod 0664 /sys/kernel/debug/tracing/saved_cmdlines_size
+ chmod 0664 /sys/kernel/tracing/saved_cmdlines_size
chmod 0664 /sys/kernel/debug/tracing/events/sched/sched_switch/enable
chmod 0664 /sys/kernel/tracing/events/sched/sched_switch/enable
chmod 0664 /sys/kernel/debug/tracing/events/sched/sched_wakeup/enable
@@ -73,6 +79,8 @@
chmod 0664 /sys/kernel/tracing/events/sched/sched_blocked_reason/enable
chmod 0664 /sys/kernel/debug/tracing/events/sched/sched_cpu_hotplug/enable
chmod 0664 /sys/kernel/tracing/events/sched/sched_cpu_hotplug/enable
+ chmod 0664 /sys/kernel/debug/tracing/events/cgroup/enable
+ chmod 0664 /sys/kernel/tracing/events/cgroup/enable
chmod 0664 /sys/kernel/debug/tracing/events/power/cpu_frequency/enable
chmod 0664 /sys/kernel/tracing/events/power/cpu_frequency/enable
chmod 0664 /sys/kernel/debug/tracing/events/power/cpu_idle/enable
diff --git a/cmds/bugreport/Android.bp b/cmds/bugreport/Android.bp
index 139e4b2..24044a6 100644
--- a/cmds/bugreport/Android.bp
+++ b/cmds/bugreport/Android.bp
@@ -1,6 +1,6 @@
cc_binary {
name: "bugreport",
srcs: ["bugreport.cpp"],
- cflags: ["-Wall"],
+ cflags: ["-Wall", "-Werror"],
shared_libs: ["libcutils"],
}
diff --git a/cmds/cmd/cmd.cpp b/cmds/cmd/cmd.cpp
index 7e05d72..40dbbf5 100644
--- a/cmds/cmd/cmd.cpp
+++ b/cmds/cmd/cmd.cpp
@@ -35,12 +35,11 @@
#include <fcntl.h>
#include <sys/time.h>
#include <errno.h>
+#include <memory>
#include "selinux/selinux.h"
#include "selinux/android.h"
-#include <UniquePtr.h>
-
#define DEBUG 0
using namespace android;
@@ -55,14 +54,15 @@
freecon(p);
}
};
-typedef UniquePtr<char[], SecurityContext_Delete> Unique_SecurityContext;
+typedef std::unique_ptr<char[], SecurityContext_Delete> Unique_SecurityContext;
class MyShellCallback : public BnShellCallback
{
public:
bool mActive = true;
- virtual int openOutputFile(const String16& path, const String16& seLinuxContext) {
+ virtual int openFile(const String16& path, const String16& seLinuxContext,
+ const String16& mode) {
String8 path8(path);
char cwd[256];
getcwd(cwd, 256);
@@ -72,7 +72,26 @@
aerr << "Open attempt after active for: " << fullPath << endl;
return -EPERM;
}
- int fd = open(fullPath.string(), O_WRONLY|O_CREAT|O_TRUNC, S_IRWXU|S_IRWXG);
+ int flags = 0;
+ bool checkRead = false;
+ bool checkWrite = false;
+ if (mode == String16("w")) {
+ flags = O_WRONLY|O_CREAT|O_TRUNC;
+ checkWrite = true;
+ } else if (mode == String16("w+")) {
+ flags = O_RDWR|O_CREAT|O_TRUNC;
+ checkRead = checkWrite = true;
+ } else if (mode == String16("r")) {
+ flags = O_RDONLY;
+ checkRead = true;
+ } else if (mode == String16("r+")) {
+ flags = O_RDWR;
+ checkRead = checkWrite = true;
+ } else {
+ aerr << "Invalid mode requested: " << mode.string() << endl;
+ return -EINVAL;
+ }
+ int fd = open(fullPath.string(), flags, S_IRWXU|S_IRWXG);
if (fd < 0) {
return fd;
}
@@ -81,14 +100,27 @@
security_context_t tmp = NULL;
int ret = getfilecon(fullPath.string(), &tmp);
Unique_SecurityContext context(tmp);
- int accessGranted = selinux_check_access(seLinuxContext8.string(), context.get(),
- "file", "write", NULL);
- if (accessGranted != 0) {
- close(fd);
- aerr << "System server has no access to file context " << context.get()
- << " (from path " << fullPath.string() << ", context "
- << seLinuxContext8.string() << ")" << endl;
- return -EPERM;
+ if (checkWrite) {
+ int accessGranted = selinux_check_access(seLinuxContext8.string(), context.get(),
+ "file", "write", NULL);
+ if (accessGranted != 0) {
+ close(fd);
+ aerr << "System server has no access to write file context " << context.get()
+ << " (from path " << fullPath.string() << ", context "
+ << seLinuxContext8.string() << ")" << endl;
+ return -EPERM;
+ }
+ }
+ if (checkRead) {
+ int accessGranted = selinux_check_access(seLinuxContext8.string(), context.get(),
+ "file", "read", NULL);
+ if (accessGranted != 0) {
+ close(fd);
+ aerr << "System server has no access to read file context " << context.get()
+ << " (from path " << fullPath.string() << ", context "
+ << seLinuxContext8.string() << ")" << endl;
+ return -EPERM;
+ }
}
}
return fd;
diff --git a/cmds/dumpstate/Android.bp b/cmds/dumpstate/Android.bp
new file mode 100644
index 0000000..f908cbf
--- /dev/null
+++ b/cmds/dumpstate/Android.bp
@@ -0,0 +1,130 @@
+//
+// Copyright (C) 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.
+
+cc_defaults {
+ name: "dumpstate_defaults",
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wno-missing-field-initializers",
+ "-Wno-unused-variable",
+ "-Wunused-parameter",
+ ],
+}
+
+cc_library_headers {
+ name: "dumpstate_headers",
+ vendor_available: true,
+ export_include_dirs: ["."],
+ header_libs: [
+ "libbase_headers",
+ "libutils_headers",
+ ],
+ export_header_lib_headers: [
+ "libbase_headers",
+ "libutils_headers",
+ ],
+}
+
+cc_library_shared {
+ name: "libdumpstateutil",
+ defaults: ["dumpstate_defaults"],
+ vendor_available: true,
+ vndk: {
+ enabled: true,
+ },
+ header_libs: ["dumpstate_headers"],
+ export_header_lib_headers: ["dumpstate_headers"],
+ srcs: [
+ "DumpstateInternal.cpp",
+ "DumpstateUtil.cpp",
+ ],
+ shared_libs: [
+ "libbase",
+ "liblog",
+ ],
+}
+
+cc_library_shared {
+ name: "libdumpstateaidl",
+ defaults: ["dumpstate_defaults"],
+ shared_libs: [
+ "libbinder",
+ "libutils",
+ ],
+ aidl: {
+ local_include_dirs: ["binder"],
+ export_aidl_headers: true,
+ },
+ srcs: [
+ "binder/android/os/IDumpstate.aidl",
+ "binder/android/os/IDumpstateListener.aidl",
+ "binder/android/os/IDumpstateToken.aidl",
+ ],
+}
+
+cc_binary {
+ name: "dumpstate",
+ defaults: ["dumpstate_defaults"],
+ header_libs: ["dumpstate_headers"],
+ shared_libs: [
+ "android.hardware.dumpstate@1.0",
+ "libziparchive",
+ "libbase",
+ "libbinder",
+ "libcrypto",
+ "libcutils",
+ "libdebuggerd_client",
+ "libdumpstateaidl",
+ "libdumpstateutil",
+ "libhidlbase",
+ "libhidltransport",
+ "liblog",
+ "libutils",
+ ],
+ srcs: [
+ "DumpstateInternal.cpp",
+ "DumpstateService.cpp",
+ "utils.cpp",
+ "dumpstate.cpp",
+ ],
+ init_rc: ["dumpstate.rc"],
+}
+
+cc_test {
+ name: "dumpstate_test",
+ defaults: ["dumpstate_defaults"],
+ header_libs: ["dumpstate_headers"],
+ shared_libs: [
+ "libziparchive",
+ "libbase",
+ "libbinder",
+ "libcutils",
+ "libdebuggerd_client",
+ "libdumpstateaidl",
+ "libdumpstateutil",
+ "libhidlbase",
+ "libhidltransport",
+ "liblog",
+ "libutils",
+ ],
+ srcs: [
+ "DumpstateInternal.cpp",
+ "DumpstateService.cpp",
+ "utils.cpp",
+ "tests/dumpstate_test.cpp",
+ ],
+ static_libs: ["libgmock"],
+}
diff --git a/cmds/dumpstate/Android.mk b/cmds/dumpstate/Android.mk
index a1b6a51..ea5fbf1 100644
--- a/cmds/dumpstate/Android.mk
+++ b/cmds/dumpstate/Android.mk
@@ -1,137 +1,5 @@
LOCAL_PATH:= $(call my-dir)
-# ================#
-# Common settings #
-# ================#
-# ZipArchive support, the order matters here to get all symbols.
-COMMON_ZIP_LIBRARIES := libziparchive libz libcrypto
-
-# TODO: ideally the tests should depend on a shared dumpstate library, but currently libdumpstate
-# is used to define the device-specific HAL library. Instead, both dumpstate and dumpstate_test
-# shares a lot of common settings
-COMMON_LOCAL_CFLAGS := \
- -Wall -Werror -Wno-missing-field-initializers -Wno-unused-variable -Wunused-parameter
-COMMON_SRC_FILES := \
- DumpstateInternal.cpp \
- utils.cpp
-COMMON_SHARED_LIBRARIES := \
- android.hardware.dumpstate@1.0 \
- libhidlbase \
- libhidltransport \
- libbase \
- libbinder \
- libcutils \
- libdebuggerd_client \
- libdumpstateaidl \
- libdumpstateutil \
- liblog \
- libselinux \
- libutils \
- $(COMMON_ZIP_LIBRARIES)
-
-# ====================#
-# libdumpstateutil #
-# ====================#
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := libdumpstateutil
-
-LOCAL_CFLAGS := $(COMMON_LOCAL_CFLAGS)
-LOCAL_C_INCLUDES := $(LOCAL_PATH)
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
-LOCAL_SRC_FILES := \
- DumpstateInternal.cpp \
- DumpstateUtil.cpp
-LOCAL_SHARED_LIBRARIES := \
- libbase \
- liblog \
-
-include $(BUILD_SHARED_LIBRARY)
-
-# ====================#
-# libdumpstateheaders #
-# ====================#
-# TODO: this module is necessary so the device-specific libdumpstate implementations do not
-# need to add any other dependency (like libbase). Should go away once dumpstate HAL changes.
-include $(CLEAR_VARS)
-
-LOCAL_EXPORT_C_INCLUDE_DIRS = $(LOCAL_PATH)
-LOCAL_MODULE := libdumpstateheaders
-LOCAL_EXPORT_SHARED_LIBRARY_HEADERS := \
- $(COMMON_SHARED_LIBRARIES)
-LOCAL_EXPORT_STATIC_LIBRARY_HEADERS := \
- $(COMMON_STATIC_LIBRARIES)
-# Soong requires that whats is on LOCAL_EXPORTED_ is also on LOCAL_
-LOCAL_SHARED_LIBRARIES := $(LOCAL_EXPORT_SHARED_LIBRARY_HEADERS)
-LOCAL_STATIC_LIBRARIES := $(LOCAL_EXPORT_STATIC_LIBRARY_HEADERS)
-
-include $(BUILD_STATIC_LIBRARY)
-
-# ================ #
-# libdumpstateaidl #
-# =================#
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := libdumpstateaidl
-
-LOCAL_CFLAGS := $(COMMON_LOCAL_CFLAGS)
-
-LOCAL_SHARED_LIBRARIES := \
- libbinder \
- libutils
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/binder
-LOCAL_AIDL_INCLUDES := $(LOCAL_PATH)/binder
-LOCAL_C_INCLUDES := $(LOCAL_PATH)/binder
-LOCAL_SRC_FILES := \
- binder/android/os/IDumpstate.aidl \
- binder/android/os/IDumpstateListener.aidl \
- binder/android/os/IDumpstateToken.aidl
-
-include $(BUILD_SHARED_LIBRARY)
-
-# ==========#
-# dumpstate #
-# ==========#
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(COMMON_SRC_FILES) \
- DumpstateService.cpp \
- dumpstate.cpp
-
-LOCAL_MODULE := dumpstate
-
-LOCAL_SHARED_LIBRARIES := $(COMMON_SHARED_LIBRARIES)
-
-LOCAL_STATIC_LIBRARIES := $(COMMON_STATIC_LIBRARIES)
-
-LOCAL_CFLAGS += $(COMMON_LOCAL_CFLAGS)
-
-LOCAL_INIT_RC := dumpstate.rc
-
-include $(BUILD_EXECUTABLE)
-
-# ===============#
-# dumpstate_test #
-# ===============#
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := dumpstate_test
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_CFLAGS := $(COMMON_LOCAL_CFLAGS)
-
-LOCAL_SRC_FILES := $(COMMON_SRC_FILES) \
- DumpstateService.cpp \
- tests/dumpstate_test.cpp
-
-LOCAL_STATIC_LIBRARIES := $(COMMON_STATIC_LIBRARIES) \
- libgmock
-
-LOCAL_SHARED_LIBRARIES := $(COMMON_SHARED_LIBRARIES)
-
-include $(BUILD_NATIVE_TEST)
-
# =======================#
# dumpstate_test_fixture #
# =======================#
@@ -141,38 +9,14 @@
LOCAL_COMPATIBILITY_SUITE := device-tests
LOCAL_MODULE_TAGS := tests
-LOCAL_CFLAGS := $(COMMON_LOCAL_CFLAGS)
+LOCAL_CFLAGS := \
+ -Wall -Werror -Wno-missing-field-initializers -Wno-unused-variable -Wunused-parameter
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
LOCAL_SRC_FILES := \
tests/dumpstate_test_fixture.cpp
-LOCAL_MODULE_CLASS := NATIVE_TESTS
-
-dumpstate_tests_intermediates := $(local-intermediates-dir)/DATA
-dumpstate_tests_subpath_from_data := nativetest/dumpstate_test_fixture
-dumpstate_tests_root_in_device := /data/$(dumpstate_tests_subpath_from_data)
-dumpstate_tests_root_for_test_zip := $(dumpstate_tests_intermediates)/$(dumpstate_tests_subpath_from_data)
-testdata_files := $(call find-subdir-files, testdata/*)
-
-# Copy test data files to intermediates/DATA for use with LOCAL_PICKUP_FILES
-GEN := $(addprefix $(dumpstate_tests_root_for_test_zip)/, $(testdata_files))
-$(GEN): PRIVATE_PATH := $(LOCAL_PATH)
-$(GEN): PRIVATE_CUSTOM_TOOL = cp $< $@
-$(GEN): $(dumpstate_tests_root_for_test_zip)/testdata/% : $(LOCAL_PATH)/testdata/%
- $(transform-generated-source)
-LOCAL_GENERATED_SOURCES += $(GEN)
-
-# Copy test data files again to $OUT/data so the tests can be run with adb sync
-# TODO: the build system should do this automatically
-GEN := $(addprefix $(TARGET_OUT_DATA)/$(dumpstate_tests_subpath_from_data)/, $(testdata_files))
-$(GEN): PRIVATE_PATH := $(LOCAL_PATH)
-$(GEN): PRIVATE_CUSTOM_TOOL = cp $< $@
-$(GEN): $(TARGET_OUT_DATA)/$(dumpstate_tests_subpath_from_data)/testdata/% : $(LOCAL_PATH)/testdata/%
- $(transform-generated-source)
-LOCAL_GENERATED_SOURCES += $(GEN)
-
-LOCAL_PICKUP_FILES := $(dumpstate_tests_intermediates)
+LOCAL_TEST_DATA := $(call find-test-data-in-subdirs, $(LOCAL_PATH), *, tests/testdata)
include $(BUILD_NATIVE_TEST)
diff --git a/cmds/dumpstate/DumpstateInternal.cpp b/cmds/dumpstate/DumpstateInternal.cpp
index 0343277..83e30a2 100644
--- a/cmds/dumpstate/DumpstateInternal.cpp
+++ b/cmds/dumpstate/DumpstateInternal.cpp
@@ -18,6 +18,9 @@
#include "DumpstateInternal.h"
+#include <errno.h>
+#include <grp.h>
+#include <pwd.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
@@ -25,14 +28,14 @@
#include <sys/prctl.h>
#include <sys/stat.h>
#include <sys/types.h>
+#include <unistd.h>
#include <cstdint>
#include <string>
#include <vector>
#include <android-base/file.h>
-#include <cutils/log.h>
-#include <private/android_filesystem_config.h>
+#include <log/log.h>
uint64_t Nanotime() {
timespec ts;
@@ -42,7 +45,17 @@
// Switches to non-root user and group.
bool DropRootUser() {
- if (getgid() == AID_SHELL && getuid() == AID_SHELL) {
+ struct group* grp = getgrnam("shell");
+ gid_t shell_gid = grp != nullptr ? grp->gr_gid : 0;
+ struct passwd* pwd = getpwnam("shell");
+ uid_t shell_uid = pwd != nullptr ? pwd->pw_uid : 0;
+
+ if (!shell_gid || !shell_uid) {
+ MYLOGE("Unable to get AID_SHELL: %s\n", strerror(errno));
+ return false;
+ }
+
+ if (getgid() == shell_gid && getuid() == shell_uid) {
MYLOGD("drop_root_user(): already running as Shell\n");
return true;
}
@@ -52,17 +65,28 @@
return false;
}
- gid_t groups[] = {AID_LOG, AID_SDCARD_R, AID_SDCARD_RW, AID_MOUNT,
- AID_INET, AID_NET_BW_STATS, AID_READPROC, AID_BLUETOOTH};
- if (setgroups(sizeof(groups) / sizeof(groups[0]), groups) != 0) {
+ static const std::vector<std::string> group_names{
+ "log", "sdcard_r", "sdcard_rw", "mount", "inet", "net_bw_stats", "readproc", "bluetooth"};
+ std::vector<gid_t> groups(group_names.size(), 0);
+ for (size_t i = 0; i < group_names.size(); ++i) {
+ grp = getgrnam(group_names[i].c_str());
+ groups[i] = grp != nullptr ? grp->gr_gid : 0;
+ if (groups[i] == 0) {
+ MYLOGE("Unable to get required gid '%s': %s\n", group_names[i].c_str(),
+ strerror(errno));
+ return false;
+ }
+ }
+
+ if (setgroups(groups.size(), groups.data()) != 0) {
MYLOGE("Unable to setgroups, aborting: %s\n", strerror(errno));
return false;
}
- if (setgid(AID_SHELL) != 0) {
+ if (setgid(shell_gid) != 0) {
MYLOGE("Unable to setgid, aborting: %s\n", strerror(errno));
return false;
}
- if (setuid(AID_SHELL) != 0) {
+ if (setuid(shell_uid) != 0) {
MYLOGE("Unable to setuid, aborting: %s\n", strerror(errno));
return false;
}
@@ -152,7 +176,6 @@
}
}
}
- close(fd);
if (!newline) dprintf(out_fd, "\n");
if (!title.empty()) dprintf(out_fd, "\n");
diff --git a/cmds/dumpstate/DumpstateInternal.h b/cmds/dumpstate/DumpstateInternal.h
index 2f7704d..10db5d6 100644
--- a/cmds/dumpstate/DumpstateInternal.h
+++ b/cmds/dumpstate/DumpstateInternal.h
@@ -32,6 +32,12 @@
ALOGI(__VA_ARGS__);
#endif
+#ifndef MYLOGW
+#define MYLOGW(...) \
+ fprintf(stderr, __VA_ARGS__); \
+ ALOGW(__VA_ARGS__);
+#endif
+
#ifndef MYLOGE
#define MYLOGE(...) \
fprintf(stderr, __VA_ARGS__); \
diff --git a/cmds/dumpstate/DumpstateUtil.cpp b/cmds/dumpstate/DumpstateUtil.cpp
index 26702c4..ede4254 100644
--- a/cmds/dumpstate/DumpstateUtil.cpp
+++ b/cmds/dumpstate/DumpstateUtil.cpp
@@ -30,7 +30,8 @@
#include <android-base/properties.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
-#include <cutils/log.h>
+#include <android-base/unique_fd.h>
+#include <log/log.h>
#include "DumpstateInternal.h"
@@ -103,6 +104,12 @@
return *this;
}
+CommandOptions::CommandOptionsBuilder& CommandOptions::CommandOptionsBuilder::AsRootIfAvailable() {
+ if (!PropertiesHelper::IsUserBuild())
+ values.account_mode_ = SU_ROOT;
+ return *this;
+}
+
CommandOptions::CommandOptionsBuilder& CommandOptions::CommandOptionsBuilder::DropRoot() {
values.account_mode_ = DROP_ROOT;
return *this;
@@ -176,8 +183,8 @@
}
int DumpFileToFd(int out_fd, const std::string& title, const std::string& path) {
- int fd = TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY | O_NONBLOCK | O_CLOEXEC));
- if (fd < 0) {
+ android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY | O_NONBLOCK | O_CLOEXEC)));
+ if (fd.get() < 0) {
int err = errno;
if (title.empty()) {
dprintf(out_fd, "*** Error dumping %s: %s\n", path.c_str(), strerror(err));
@@ -188,7 +195,7 @@
fsync(out_fd);
return -1;
}
- return DumpFileFromFdToFd(title, path, fd, out_fd, PropertiesHelper::IsDryRun());
+ return DumpFileFromFdToFd(title, path, fd.get(), out_fd, PropertiesHelper::IsDryRun());
}
int RunCommandToFd(int fd, const std::string& title, const std::vector<std::string>& full_command,
diff --git a/cmds/dumpstate/DumpstateUtil.h b/cmds/dumpstate/DumpstateUtil.h
index 5a8ce5b..698ceff 100644
--- a/cmds/dumpstate/DumpstateUtil.h
+++ b/cmds/dumpstate/DumpstateUtil.h
@@ -89,6 +89,8 @@
CommandOptionsBuilder& Always();
/* Sets the command's PrivilegeMode as `SU_ROOT` */
CommandOptionsBuilder& AsRoot();
+ /* If !IsUserBuild(), sets the command's PrivilegeMode as `SU_ROOT` */
+ CommandOptionsBuilder& AsRootIfAvailable();
/* Sets the command's PrivilegeMode as `DROP_ROOT` */
CommandOptionsBuilder& DropRoot();
/* Sets the command's OutputMode as `REDIRECT_TO_STDERR` */
diff --git a/cmds/dumpstate/bugreport-format.md b/cmds/dumpstate/bugreport-format.md
index b995b80..dee89cf 100644
--- a/cmds/dumpstate/bugreport-format.md
+++ b/cmds/dumpstate/bugreport-format.md
@@ -56,8 +56,20 @@
- `description.txt`: whose value is a multi-line, detailed description of the problem.
## Android O versions
-On _Android O (OhMightyAndroidWhatsYourNextReleaseName?)_, the following changes were made:
-- The ANR traces are added to the `FS` folder, typically under `FS/data/anr` (version `2.0-dev-1`).
+On _Android O (Oreo)_, the following changes were made:
+- The ANR traces are added to the `FS` folder, typically under `FS/data/anr` (version `2.0-dev-split-anr`).
+
+## Android P versions
+On _Android P (PleaseMightyAndroidWhatsYourNextReleaseName?)_, the following changes were made:
+- Dumpsys sections are dumped by priority (version `2.0-dev-priority-dumps`).
+ Supported priorities can be specified when registering framework services. Section headers are
+ changed to contain priority info.
+ `DUMPSYS` -> `DUMPSYS CRITICAL/HIGH/NORMAL`
+ `DUMP OF SERVICE <servicename>` -> `DUMP OF SERVICE CRITICAL/HIGH/NORMAL <servicename>`
+ Supported Priorities:
+ - CRITICAL - services that must dump first, and fast (under 100ms). Ex: cpuinfo.
+ - HIGH - services that also must dump first, but can take longer (under 250ms) to dump. Ex: meminfo.
+ - NORMAL - services that have no rush to dump and can take a long time (under 10s).
## Intermediate versions
During development, the versions will be suffixed with _-devX_ or
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index f84d86d..201b5a3 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -21,13 +21,9 @@
#include <fcntl.h>
#include <libgen.h>
#include <limits.h>
-#include <memory>
-#include <regex>
-#include <set>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
-#include <string>
#include <string.h>
#include <sys/prctl.h>
#include <sys/resource.h>
@@ -35,6 +31,11 @@
#include <sys/time.h>
#include <sys/wait.h>
#include <unistd.h>
+#include <memory>
+#include <regex>
+#include <set>
+#include <string>
+#include <vector>
#include <android-base/file.h>
#include <android-base/properties.h>
@@ -71,6 +72,7 @@
#define PSTORE_LAST_KMSG "/sys/fs/pstore/console-ramoops"
#define ALT_PSTORE_LAST_KMSG "/sys/fs/pstore/console-ramoops-0"
+#define BLK_DEV_SYS_DIR "/sys/block"
#define RAFT_DIR "/data/misc/raft"
#define RECOVERY_DIR "/cache/recovery"
@@ -78,19 +80,29 @@
#define LOGPERSIST_DATA_DIR "/data/misc/logd"
#define PROFILE_DATA_DIR_CUR "/data/misc/profiles/cur"
#define PROFILE_DATA_DIR_REF "/data/misc/profiles/ref"
-#define TOMBSTONE_DIR "/data/tombstones"
-#define TOMBSTONE_FILE_PREFIX TOMBSTONE_DIR "/tombstone_"
-/* Can accomodate a tombstone number up to 9999. */
-#define TOMBSTONE_MAX_LEN (sizeof(TOMBSTONE_FILE_PREFIX) + 4)
-#define NUM_TOMBSTONES 10
#define WLUTIL "/vendor/xbin/wlutil"
-typedef struct {
- char name[TOMBSTONE_MAX_LEN];
- int fd;
-} tombstone_data_t;
+// TODO(narayan): Since this information has to be kept in sync
+// with tombstoned, we should just put it in a common header.
+//
+// File: system/core/debuggerd/tombstoned/tombstoned.cpp
+static const std::string TOMBSTONE_DIR = "/data/tombstones/";
+static const std::string TOMBSTONE_FILE_PREFIX = "tombstone_";
+static const std::string ANR_DIR = "/data/anr/";
+static const std::string ANR_FILE_PREFIX = "anr_";
-static tombstone_data_t tombstone_data[NUM_TOMBSTONES];
+struct DumpData {
+ std::string name;
+ int fd;
+ time_t mtime;
+};
+
+static bool operator<(const DumpData& d1, const DumpData& d2) {
+ return d1.mtime > d2.mtime;
+}
+
+static std::unique_ptr<std::vector<DumpData>> tombstone_data;
+static std::unique_ptr<std::vector<DumpData>> anr_data;
// TODO: temporary variables and functions used during C++ refactoring
static Dumpstate& ds = Dumpstate::GetInstance();
@@ -111,7 +123,13 @@
static const std::string ZIP_ROOT_DIR = "FS";
// Must be hardcoded because dumpstate HAL implementation need SELinux access to it
-static const std::string kDumpstateBoardPath = "/bugreports/dumpstate_board.txt";
+static const std::string kDumpstateBoardPath = "/bugreports/";
+static const std::string kDumpstateBoardFiles[] = {
+ "dumpstate_board.txt",
+ "dumpstate_board.bin"
+};
+static const int NUM_OF_DUMPS = arraysize(kDumpstateBoardFiles);
+
static const std::string kLsHalDebugPath = "/bugreports/dumpstate_lshal.txt";
static constexpr char PROPERTY_EXTRA_OPTIONS[] = "dumpstate.options";
@@ -122,22 +140,100 @@
static const CommandOptions AS_ROOT_20 = CommandOptions::WithTimeout(20).AsRoot().Build();
-/* gets the tombstone data, according to the bugreport type: if zipped, gets all tombstones;
- * otherwise, gets just those modified in the last half an hour. */
-static void get_tombstone_fds(tombstone_data_t data[NUM_TOMBSTONES]) {
- time_t thirty_minutes_ago = ds.now_ - 60 * 30;
- for (size_t i = 0; i < NUM_TOMBSTONES; i++) {
- snprintf(data[i].name, sizeof(data[i].name), "%s%02zu", TOMBSTONE_FILE_PREFIX, i);
- int fd = TEMP_FAILURE_RETRY(open(data[i].name,
- O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_NONBLOCK));
- struct stat st;
- if (fstat(fd, &st) == 0 && S_ISREG(st.st_mode) && st.st_size > 0 &&
- (ds.IsZipping() || st.st_mtime >= thirty_minutes_ago)) {
- data[i].fd = fd;
- } else {
- close(fd);
- data[i].fd = -1;
+/*
+ * Returns a vector of dump fds under |dir_path| with a given |file_prefix|.
+ * The returned vector is sorted by the mtimes of the dumps. If |limit_by_mtime|
+ * is set, the vector only contains files that were written in the last 30 minutes.
+ * If |limit_by_count| is set, the vector only contains the ten latest files.
+ */
+static std::vector<DumpData>* GetDumpFds(const std::string& dir_path,
+ const std::string& file_prefix,
+ bool limit_by_mtime,
+ bool limit_by_count = true) {
+ const time_t thirty_minutes_ago = ds.now_ - 60 * 30;
+
+ std::unique_ptr<std::vector<DumpData>> dump_data(new std::vector<DumpData>());
+ std::unique_ptr<DIR, decltype(&closedir)> dump_dir(opendir(dir_path.c_str()), closedir);
+
+ struct dirent* entry = nullptr;
+ while ((entry = readdir(dump_dir.get()))) {
+ if (entry->d_type != DT_REG) {
+ continue;
}
+
+ const std::string base_name(entry->d_name);
+ if (base_name.find(file_prefix) != 0) {
+ continue;
+ }
+
+ const std::string abs_path = dir_path + base_name;
+ android::base::unique_fd fd(
+ TEMP_FAILURE_RETRY(open(abs_path.c_str(), O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_NONBLOCK)));
+ if (fd == -1) {
+ MYLOGW("Unable to open dump file: %s %s\n", abs_path.c_str(), strerror(errno));
+ break;
+ }
+
+ struct stat st = {};
+ if (fstat(fd, &st) == -1) {
+ MYLOGW("Unable to stat dump file: %s %s\n", abs_path.c_str(), strerror(errno));
+ continue;
+ }
+
+ if (limit_by_mtime && st.st_mtime >= thirty_minutes_ago) {
+ MYLOGI("Excluding stale dump file: %s\n", abs_path.c_str());
+ continue;
+ }
+
+ DumpData data = {.name = abs_path, .fd = fd.release(), .mtime = st.st_mtime};
+
+ dump_data->push_back(data);
+ }
+
+ std::sort(dump_data->begin(), dump_data->end());
+
+ if (limit_by_count && dump_data->size() > 10) {
+ dump_data->erase(dump_data->begin() + 10, dump_data->end());
+ }
+
+ return dump_data.release();
+}
+
+static bool AddDumps(const std::vector<DumpData>::const_iterator start,
+ const std::vector<DumpData>::const_iterator end,
+ const char* type_name, const bool add_to_zip) {
+ bool dumped = false;
+ for (auto it = start; it != end; ++it) {
+ const std::string& name = it->name;
+ const int fd = it->fd;
+ dumped = true;
+
+ // Seek to the beginning of the file before dumping any data. A given
+ // DumpData entry might be dumped multiple times in the report.
+ //
+ // For example, the most recent ANR entry is dumped to the body of the
+ // main entry and it also shows up as a separate entry in the bugreport
+ // ZIP file.
+ if (lseek(fd, 0, SEEK_SET) != static_cast<off_t>(0)) {
+ MYLOGE("Unable to add %s to zip file, lseek failed: %s\n", name.c_str(),
+ strerror(errno));
+ }
+
+ if (ds.IsZipping() && add_to_zip) {
+ if (!ds.AddZipEntryFromFd(ZIP_ROOT_DIR + name, fd)) {
+ MYLOGE("Unable to add %s to zip file, addZipEntryFromFd failed\n", name.c_str());
+ }
+ } else {
+ dump_file_from_fd(type_name, name.c_str(), fd);
+ }
+ }
+
+ return dumped;
+}
+
+static void CloseDumpFds(const std::vector<DumpData>* dumps) {
+ for (auto it = dumps->begin(); it != dumps->end(); ++it) {
+ close(it->fd);
}
}
@@ -377,88 +473,6 @@
}
}
-/**
- * Finds the last modified file in the directory dir whose name starts with file_prefix.
- *
- * Function returns empty string when it does not find a file
- */
-static std::string GetLastModifiedFileWithPrefix(const std::string& dir,
- const std::string& file_prefix) {
- std::unique_ptr<DIR, decltype(&closedir)> d(opendir(dir.c_str()), closedir);
- if (d == nullptr) {
- MYLOGD("Error %d opening %s\n", errno, dir.c_str());
- return "";
- }
-
- // Find the newest file matching the file_prefix in dir
- struct dirent *de;
- time_t last_modified_time = 0;
- std::string last_modified_file = "";
- struct stat s;
-
- while ((de = readdir(d.get()))) {
- std::string file = std::string(de->d_name);
- if (!file_prefix.empty()) {
- if (!android::base::StartsWith(file, file_prefix.c_str())) continue;
- }
- file = dir + "/" + file;
- int ret = stat(file.c_str(), &s);
-
- if ((ret == 0) && (s.st_mtime > last_modified_time)) {
- last_modified_file = file;
- last_modified_time = s.st_mtime;
- }
- }
-
- return last_modified_file;
-}
-
-static void DumpModemLogs() {
- DurationReporter durationReporter("DUMP MODEM LOGS");
- if (PropertiesHelper::IsUserBuild()) {
- return;
- }
-
- if (!ds.IsZipping()) {
- MYLOGD("Not dumping modem logs. dumpstate is not generating a zipping bugreport\n");
- return;
- }
-
- std::string file_prefix = android::base::GetProperty("ro.radio.log_prefix", "");
-
- if(file_prefix.empty()) {
- MYLOGD("No modem log : file_prefix is empty\n");
- return;
- }
-
- // TODO: b/33820081 we need to provide a right way to dump modem logs.
- std::string radio_bugreport_dir = android::base::GetProperty("ro.radio.log_loc", "");
- if (radio_bugreport_dir.empty()) {
- radio_bugreport_dir = dirname(ds.GetPath("").c_str());
- }
-
- MYLOGD("DumpModemLogs: directory is %s and file_prefix is %s\n",
- radio_bugreport_dir.c_str(), file_prefix.c_str());
-
- std::string modem_log_file = GetLastModifiedFileWithPrefix(radio_bugreport_dir, file_prefix);
-
- struct stat s;
- if (modem_log_file.empty() || stat(modem_log_file.c_str(), &s) != 0) {
- MYLOGD("Modem log %s does not exist\n", modem_log_file.c_str());
- return;
- }
-
- std::string filename = basename(modem_log_file.c_str());
- if (!ds.AddZipEntry(filename, modem_log_file)) {
- MYLOGE("Unable to add modem log %s to zip file\n", modem_log_file.c_str());
- } else {
- MYLOGD("Modem Log %s is added to zip\n", modem_log_file.c_str());
- if (remove(modem_log_file.c_str())) {
- MYLOGE("Error removing modem log %s\n", modem_log_file.c_str());
- }
- }
-}
-
static bool skip_not_stat(const char *path) {
static const char stat[] = "/stat";
size_t len = strlen(path);
@@ -472,7 +486,6 @@
return false;
}
-static const char mmcblk0[] = "/sys/block/mmcblk0/";
unsigned long worst_write_perf = 20000; /* in KB/s */
//
@@ -586,11 +599,13 @@
return 0;
}
- if (!strncmp(path, mmcblk0, sizeof(mmcblk0) - 1)) {
- path += sizeof(mmcblk0) - 1;
+ if (!strncmp(path, BLK_DEV_SYS_DIR, sizeof(BLK_DEV_SYS_DIR) - 1)) {
+ path += sizeof(BLK_DEV_SYS_DIR) - 1;
}
- printf("%s: %s\n", path, buffer);
+ printf("%-30s:%9s%9s%9s%9s%9s%9s%9s%9s%9s%9s%9s\n%-30s:\t%s\n", "Block-Dev",
+ "R-IOs", "R-merg", "R-sect", "R-wait", "W-IOs", "W-merg", "W-sect",
+ "W-wait", "in-fli", "activ", "T-wait", path, buffer);
free(buffer);
if (fields[__STAT_IO_TICKS]) {
@@ -627,9 +642,9 @@
/ fields[__STAT_IO_TICKS];
if (!write_perf && !write_ios) {
- printf("%s: perf(ios) rd: %luKB/s(%lu/s) q: %u\n", path, read_perf, read_ios, queue);
+ printf("%-30s: perf(ios) rd: %luKB/s(%lu/s) q: %u\n", path, read_perf, read_ios, queue);
} else {
- printf("%s: perf(ios) rd: %luKB/s(%lu/s) wr: %luKB/s(%lu/s) q: %u\n", path, read_perf,
+ printf("%-30s: perf(ios) rd: %luKB/s(%lu/s) wr: %luKB/s(%lu/s) q: %u\n", path, read_perf,
read_ios, write_perf, write_ios, queue);
}
@@ -675,6 +690,7 @@
printf("Kernel: ");
DumpFileToFd(STDOUT_FILENO, "", "/proc/version");
printf("Command line: %s\n", strtok(cmdline_buf, "\n"));
+ ds.RunCommand("UPTIME", {"uptime"}, CommandOptions::DEFAULT);
printf("Bugreport format version: %s\n", version_.c_str());
printf("Dumpstate info: id=%d pid=%d dry_run=%d args=%s extra_options=%s\n", id_, pid_,
PropertiesHelper::IsDryRun(), args_.c_str(), extra_options_.c_str());
@@ -698,7 +714,7 @@
std::string valid_name = entry_name;
// Rename extension if necessary.
- size_t idx = entry_name.rfind(".");
+ size_t idx = entry_name.rfind('.');
if (idx != std::string::npos) {
std::string extension = entry_name.substr(idx);
std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower);
@@ -849,7 +865,7 @@
"-d", "*:v"});
}
-static void DumpIpTables() {
+static void DumpIpTablesAsRoot() {
RunCommand("IPTABLES", {"iptables", "-L", "-nvx"});
RunCommand("IP6TABLES", {"ip6tables", "-L", "-nvx"});
RunCommand("IPTABLES NAT", {"iptables", "-t", "nat", "-L", "-nvx"});
@@ -860,11 +876,10 @@
RunCommand("IP6TABLES RAW", {"ip6tables", "-t", "raw", "-L", "-nvx"});
}
-static void AddAnrTraceFiles() {
- bool add_to_zip = ds.IsZipping() && ds.version_ == VERSION_SPLIT_ANR;
+static void AddGlobalAnrTraceFile(const bool add_to_zip, const std::string& anr_traces_file,
+ const std::string& anr_traces_dir) {
std::string dump_traces_dir;
- /* show the traces we collected in main(), if that was done */
if (dump_traces_path != nullptr) {
if (add_to_zip) {
dump_traces_dir = dirname(dump_traces_path);
@@ -877,8 +892,6 @@
}
}
- std::string anr_traces_path = android::base::GetProperty("dalvik.vm.stack-trace-file", "");
- std::string anr_traces_dir = dirname(anr_traces_path.c_str());
// Make sure directory is not added twice.
// TODO: this is an overzealous check because it's relying on dump_traces_path - which is
@@ -888,65 +901,201 @@
// be revisited.
bool already_dumped = anr_traces_dir == dump_traces_dir;
- MYLOGD("AddAnrTraceFiles(): dump_traces_dir=%s, anr_traces_dir=%s, already_dumped=%d\n",
+ MYLOGD("AddGlobalAnrTraceFile(): dump_traces_dir=%s, anr_traces_dir=%s, already_dumped=%d\n",
dump_traces_dir.c_str(), anr_traces_dir.c_str(), already_dumped);
- if (anr_traces_path.empty()) {
- printf("*** NO VM TRACES FILE DEFINED (dalvik.vm.stack-trace-file)\n\n");
+ android::base::unique_fd fd(TEMP_FAILURE_RETRY(
+ open(anr_traces_file.c_str(), O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_NONBLOCK)));
+ if (fd.get() < 0) {
+ printf("*** NO ANR VM TRACES FILE (%s): %s\n\n", anr_traces_file.c_str(), strerror(errno));
} else {
- int fd = TEMP_FAILURE_RETRY(
- open(anr_traces_path.c_str(), O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_NONBLOCK));
- if (fd < 0) {
- printf("*** NO ANR VM TRACES FILE (%s): %s\n\n", anr_traces_path.c_str(),
- strerror(errno));
- } else {
- if (add_to_zip) {
- if (!already_dumped) {
- MYLOGD("Adding dalvik ANR traces (directory %s) to the zip file\n",
- anr_traces_dir.c_str());
- ds.AddDir(anr_traces_dir, true);
- already_dumped = true;
- }
- } else {
- MYLOGD("Dumping last ANR traces (%s) to the main bugreport entry\n",
- anr_traces_path.c_str());
- dump_file_from_fd("VM TRACES AT LAST ANR", anr_traces_path.c_str(), fd);
+ if (add_to_zip) {
+ if (!already_dumped) {
+ MYLOGD("Adding dalvik ANR traces (directory %s) to the zip file\n",
+ anr_traces_dir.c_str());
+ ds.AddDir(anr_traces_dir, true);
}
+ } else {
+ MYLOGD("Dumping last ANR traces (%s) to the main bugreport entry\n",
+ anr_traces_file.c_str());
+ dump_file_from_fd("VM TRACES AT LAST ANR", anr_traces_file.c_str(), fd.get());
+ }
+ }
+}
+
+static void AddAnrTraceDir(const bool add_to_zip, const std::string& anr_traces_dir) {
+ MYLOGD("AddAnrTraceDir(): dump_traces_file=%s, anr_traces_dir=%s\n", dump_traces_path,
+ anr_traces_dir.c_str());
+
+ // If we're here, dump_traces_path will always be a temporary file
+ // (created with mkostemp or similar) that contains dumps taken earlier
+ // on in the process.
+ if (dump_traces_path != nullptr) {
+ if (add_to_zip) {
+ ds.AddZipEntry(ZIP_ROOT_DIR + anr_traces_dir + "/traces-just-now.txt", dump_traces_path);
+ } else {
+ MYLOGD("Dumping current ANR traces (%s) to the main bugreport entry\n",
+ dump_traces_path);
+ ds.DumpFile("VM TRACES JUST NOW", dump_traces_path);
+ }
+
+ const int ret = unlink(dump_traces_path);
+ if (ret == -1) {
+ MYLOGW("Error unlinking temporary trace path %s: %s\n", dump_traces_path,
+ strerror(errno));
}
}
- if (add_to_zip && already_dumped) {
- MYLOGD("Already dumped directory %s to the zip file\n", anr_traces_dir.c_str());
+ // Add a specific message for the first ANR Dump.
+ if (anr_data->size() > 0) {
+ AddDumps(anr_data->begin(), anr_data->begin() + 1,
+ "VM TRACES AT LAST ANR", add_to_zip);
+
+ // The "last" ANR will always be included as separate entry in the zip file. In addition,
+ // it will be present in the body of the main entry if |add_to_zip| == false.
+ //
+ // Historical ANRs are always included as separate entries in the bugreport zip file.
+ AddDumps(anr_data->begin() + ((add_to_zip) ? 1 : 0), anr_data->end(),
+ "HISTORICAL ANR", true /* add_to_zip */);
+ } else {
+ printf("*** NO ANRs to dump in %s\n\n", ANR_DIR.c_str());
+ }
+}
+
+static void AddAnrTraceFiles() {
+ const bool add_to_zip = ds.IsZipping() && ds.version_ == VERSION_SPLIT_ANR;
+
+ std::string anr_traces_file;
+ std::string anr_traces_dir;
+ bool is_global_trace_file = true;
+
+ // First check whether the stack-trace-dir property is set. When it's set,
+ // each ANR trace will be written to a separate file and not to a global
+ // stack trace file.
+ anr_traces_dir = android::base::GetProperty("dalvik.vm.stack-trace-dir", "");
+ if (anr_traces_dir.empty()) {
+ anr_traces_file = android::base::GetProperty("dalvik.vm.stack-trace-file", "");
+ if (!anr_traces_file.empty()) {
+ anr_traces_dir = dirname(anr_traces_file.c_str());
+ }
+ } else {
+ is_global_trace_file = false;
+ }
+
+ // We have neither configured a global trace file nor a trace directory,
+ // there will be nothing to dump.
+ if (anr_traces_file.empty() && anr_traces_dir.empty()) {
+ printf("*** NO VM TRACES FILE DEFINED (dalvik.vm.stack-trace-file)\n\n");
return;
}
+ if (is_global_trace_file) {
+ AddGlobalAnrTraceFile(add_to_zip, anr_traces_file, anr_traces_dir);
+ } else {
+ AddAnrTraceDir(add_to_zip, anr_traces_dir);
+ }
+
/* slow traces for slow operations */
struct stat st;
- if (!anr_traces_path.empty()) {
- int tail = anr_traces_path.size() - 1;
- while (tail > 0 && anr_traces_path.at(tail) != '/') {
- tail--;
- }
+ if (!anr_traces_dir.empty()) {
int i = 0;
- while (1) {
- anr_traces_path = anr_traces_path.substr(0, tail + 1) +
- android::base::StringPrintf("slow%02d.txt", i);
- if (stat(anr_traces_path.c_str(), &st)) {
+ while (true) {
+ const std::string slow_trace_path =
+ anr_traces_dir + android::base::StringPrintf("slow%02d.txt", i);
+ if (stat(slow_trace_path.c_str(), &st)) {
// No traces file at this index, done with the files.
break;
}
- ds.DumpFile("VM TRACES WHEN SLOW", anr_traces_path.c_str());
+ ds.DumpFile("VM TRACES WHEN SLOW", slow_trace_path.c_str());
i++;
}
}
}
+static void DumpBlockStatFiles() {
+ DurationReporter duration_reporter("DUMP BLOCK STAT");
+
+ std::unique_ptr<DIR, std::function<int(DIR*)>> dirptr(opendir(BLK_DEV_SYS_DIR), closedir);
+
+ if (dirptr == nullptr) {
+ MYLOGE("Failed to open %s: %s\n", BLK_DEV_SYS_DIR, strerror(errno));
+ return;
+ }
+
+ printf("------ DUMP BLOCK STAT ------\n\n");
+ while (struct dirent *d = readdir(dirptr.get())) {
+ if ((d->d_name[0] == '.')
+ && (((d->d_name[1] == '.') && (d->d_name[2] == '\0'))
+ || (d->d_name[1] == '\0'))) {
+ continue;
+ }
+ const std::string new_path =
+ android::base::StringPrintf("%s/%s", BLK_DEV_SYS_DIR, d->d_name);
+ printf("------ BLOCK STAT (%s) ------\n", new_path.c_str());
+ dump_files("", new_path.c_str(), skip_not_stat, dump_stat_from_fd);
+ printf("\n");
+ }
+ return;
+}
+
+static void DumpPacketStats() {
+ DumpFile("NETWORK DEV INFO", "/proc/net/dev");
+ DumpFile("QTAGUID NETWORK INTERFACES INFO", "/proc/net/xt_qtaguid/iface_stat_all");
+ DumpFile("QTAGUID NETWORK INTERFACES INFO (xt)", "/proc/net/xt_qtaguid/iface_stat_fmt");
+ DumpFile("QTAGUID CTRL INFO", "/proc/net/xt_qtaguid/ctrl");
+ DumpFile("QTAGUID STATS INFO", "/proc/net/xt_qtaguid/stats");
+}
+
+static void DumpIpAddrAndRules() {
+ /* The following have a tendency to get wedged when wifi drivers/fw goes belly-up. */
+ RunCommand("NETWORK INTERFACES", {"ip", "link"});
+ RunCommand("IPv4 ADDRESSES", {"ip", "-4", "addr", "show"});
+ RunCommand("IPv6 ADDRESSES", {"ip", "-6", "addr", "show"});
+ RunCommand("IP RULES", {"ip", "rule", "show"});
+ RunCommand("IP RULES v6", {"ip", "-6", "rule", "show"});
+}
+
+// Runs dumpsys on services that must dump first and and will take less than 100ms to dump.
+static void RunDumpsysCritical() {
+ if (ds.CurrentVersionSupportsPriorityDumps()) {
+ RunDumpsys("DUMPSYS CRITICAL", {"--priority", "CRITICAL"},
+ CommandOptions::WithTimeout(5).DropRoot().Build());
+ } else {
+ RunDumpsys("DUMPSYS MEMINFO", {"meminfo", "-a"},
+ CommandOptions::WithTimeout(90).DropRoot().Build());
+ RunDumpsys("DUMPSYS CPUINFO", {"cpuinfo", "-a"},
+ CommandOptions::WithTimeout(10).DropRoot().Build());
+ }
+}
+
+// Runs dumpsys on services that must dump first but can take up to 250ms to dump.
+static void RunDumpsysHigh() {
+ if (ds.CurrentVersionSupportsPriorityDumps()) {
+ RunDumpsys("DUMPSYS HIGH", {"--priority", "HIGH"},
+ CommandOptions::WithTimeout(20).DropRoot().Build());
+ } else {
+ RunDumpsys("NETWORK DIAGNOSTICS", {"connectivity", "--diag"});
+ }
+}
+
+// Runs dumpsys on services that must dump but can take up to 10s to dump.
+static void RunDumpsysNormal() {
+ if (ds.CurrentVersionSupportsPriorityDumps()) {
+ RunDumpsys("DUMPSYS NORMAL", {"--priority", "NORMAL"},
+ CommandOptions::WithTimeout(90).DropRoot().Build());
+ } else {
+ RunDumpsys("DUMPSYS", {"--skip", "meminfo", "cpuinfo"},
+ CommandOptions::WithTimeout(90).Build(), 10);
+ }
+}
+
static void dumpstate() {
DurationReporter duration_reporter("DUMPSTATE");
dump_dev_files("TRUSTY VERSION", "/sys/bus/platform/drivers/trusty", "trusty_version");
+ /* TODO: Remove duplicate uptime call when tools use it from header */
RunCommand("UPTIME", {"uptime"});
- dump_files("UPTIME MMC PERF", mmcblk0, skip_not_stat, dump_stat_from_fd);
+ DumpBlockStatFiles();
dump_emmc_ecsd("/d/mmc0/mmc0:0001/ext_csd");
DumpFile("MEMORY INFO", "/proc/meminfo");
RunCommand("CPU INFO", {"top", "-b", "-n", "1", "-H", "-s", "6", "-o",
@@ -965,21 +1114,22 @@
DumpFile("KERNEL SYNC", "/d/sync");
RunCommand("PROCESSES AND THREADS",
- {"ps", "-A", "-T", "-Z", "-O", "pri,nice,rtprio,sched,pcy"});
+ {"ps", "-A", "-T", "-Z", "-O", "pri,nice,rtprio,sched,pcy,time"});
RunCommand("LIBRANK", {"librank"}, CommandOptions::AS_ROOT);
if (ds.IsZipping()) {
RunCommand(
"HARDWARE HALS",
{"lshal", std::string("--debug=") + kLsHalDebugPath},
- CommandOptions::AS_ROOT);
+ CommandOptions::WithTimeout(10).AsRootIfAvailable().Build());
ds.AddZipEntry("lshal-debug.txt", kLsHalDebugPath);
unlink(kLsHalDebugPath.c_str());
} else {
RunCommand(
- "HARDWARE HALS", {"lshal", "--debug"}, CommandOptions::AS_ROOT);
+ "HARDWARE HALS", {"lshal", "--debug"},
+ CommandOptions::WithTimeout(10).AsRootIfAvailable().Build());
}
RunCommand("PRINTENV", {"printenv"});
@@ -1010,62 +1160,31 @@
AddAnrTraceFiles();
- int dumped = 0;
- for (size_t i = 0; i < NUM_TOMBSTONES; i++) {
- if (tombstone_data[i].fd != -1) {
- const char *name = tombstone_data[i].name;
- int fd = tombstone_data[i].fd;
- dumped = 1;
- if (ds.IsZipping()) {
- if (!ds.AddZipEntryFromFd(ZIP_ROOT_DIR + name, fd)) {
- MYLOGE("Unable to add tombstone %s to zip file\n", name);
- }
- } else {
- dump_file_from_fd("TOMBSTONE", name, fd);
- }
- close(fd);
- tombstone_data[i].fd = -1;
- }
- }
- if (!dumped) {
- printf("*** NO TOMBSTONES to dump in %s\n\n", TOMBSTONE_DIR);
+ // NOTE: tombstones are always added as separate entries in the zip archive
+ // and are not interspersed with the main report.
+ const bool tombstones_dumped = AddDumps(tombstone_data->begin(), tombstone_data->end(),
+ "TOMBSTONE", true /* add_to_zip */);
+ if (!tombstones_dumped) {
+ printf("*** NO TOMBSTONES to dump in %s\n\n", TOMBSTONE_DIR.c_str());
}
- DumpFile("NETWORK DEV INFO", "/proc/net/dev");
- DumpFile("QTAGUID NETWORK INTERFACES INFO", "/proc/net/xt_qtaguid/iface_stat_all");
- DumpFile("QTAGUID NETWORK INTERFACES INFO (xt)", "/proc/net/xt_qtaguid/iface_stat_fmt");
- DumpFile("QTAGUID CTRL INFO", "/proc/net/xt_qtaguid/ctrl");
- DumpFile("QTAGUID STATS INFO", "/proc/net/xt_qtaguid/stats");
+ DumpPacketStats();
DoKmsg();
- /* The following have a tendency to get wedged when wifi drivers/fw goes belly-up. */
-
- RunCommand("NETWORK INTERFACES", {"ip", "link"});
-
- RunCommand("IPv4 ADDRESSES", {"ip", "-4", "addr", "show"});
- RunCommand("IPv6 ADDRESSES", {"ip", "-6", "addr", "show"});
-
- RunCommand("IP RULES", {"ip", "rule", "show"});
- RunCommand("IP RULES v6", {"ip", "-6", "rule", "show"});
+ DumpIpAddrAndRules();
dump_route_tables();
RunCommand("ARP CACHE", {"ip", "-4", "neigh", "show"});
RunCommand("IPv6 ND CACHE", {"ip", "-6", "neigh", "show"});
RunCommand("MULTICAST ADDRESSES", {"ip", "maddr"});
- RunCommand("WIFI NETWORKS", {"wpa_cli", "IFNAME=wlan0", "list_networks"},
- CommandOptions::WithTimeout(20).Build());
- RunDumpsys("NETWORK DIAGNOSTICS", {"connectivity", "--diag"},
- CommandOptions::WithTimeout(10).Build());
+ RunDumpsysHigh();
RunCommand("SYSTEM PROPERTIES", {"getprop"});
- RunCommand("VOLD DUMP", {"vdc", "dump"});
- RunCommand("SECURE CONTAINERS", {"vdc", "asec", "list"});
-
- RunCommand("STORAGED TASKIOINFO", {"storaged", "-u"}, CommandOptions::WithTimeout(10).Build());
+ RunCommand("STORAGED IO INFO", {"storaged", "-u", "-p"});
RunCommand("FILESYSTEMS & FREE SPACE", {"df"});
@@ -1111,8 +1230,7 @@
printf("== Android Framework Services\n");
printf("========================================================\n");
- RunDumpsys("DUMPSYS", {"--skip", "meminfo", "cpuinfo"}, CommandOptions::WithTimeout(90).Build(),
- 10);
+ RunDumpsysNormal();
printf("========================================================\n");
printf("== Checkins\n");
@@ -1150,11 +1268,6 @@
RunDumpsys("DROPBOX SYSTEM SERVER CRASHES", {"dropbox", "-p", "system_server_crash"});
RunDumpsys("DROPBOX SYSTEM APP CRASHES", {"dropbox", "-p", "system_app_crash"});
- // DumpModemLogs adds the modem logs if available to the bugreport.
- // Do this at the end to allow for sufficient time for the modem logs to be
- // collected.
- DumpModemLogs();
-
printf("========================================================\n");
printf("== Final progress (pid %d): %d/%d (estimated %d)\n", ds.pid_, ds.progress_->Get(),
ds.progress_->GetMax(), ds.progress_->GetInitialMax());
@@ -1163,6 +1276,46 @@
printf("========================================================\n");
}
+// This method collects dumpsys for telephony debugging only
+static void DumpstateTelephonyOnly() {
+ DurationReporter duration_reporter("DUMPSTATE");
+
+ DumpIpTablesAsRoot();
+
+ if (!DropRootUser()) {
+ return;
+ }
+
+ do_dmesg();
+ DoLogcat();
+ DumpPacketStats();
+ DoKmsg();
+ DumpIpAddrAndRules();
+ dump_route_tables();
+
+ RunDumpsys("NETWORK DIAGNOSTICS", {"connectivity", "--diag"},
+ CommandOptions::WithTimeout(10).Build());
+
+ RunCommand("SYSTEM PROPERTIES", {"getprop"});
+
+ printf("========================================================\n");
+ printf("== Android Framework Services\n");
+ printf("========================================================\n");
+
+ RunDumpsys("DUMPSYS", {"connectivity"}, CommandOptions::WithTimeout(90).Build(), 10);
+ RunDumpsys("DUMPSYS", {"carrier_config"}, CommandOptions::WithTimeout(90).Build(), 10);
+
+ printf("========================================================\n");
+ printf("== Running Application Services\n");
+ printf("========================================================\n");
+
+ RunDumpsys("TELEPHONY SERVICES", {"activity", "service", "TelephonyDebugService"});
+
+ printf("========================================================\n");
+ printf("== dumpstate: done (id %d)\n", ds.id_);
+ printf("========================================================\n");
+}
+
void Dumpstate::DumpstateBoard() {
DurationReporter duration_reporter("dumpstate_board()");
printf("========================================================\n");
@@ -1180,23 +1333,35 @@
return;
}
- std::string path = kDumpstateBoardPath;
- MYLOGI("Calling IDumpstateDevice implementation using path %s\n", path.c_str());
+ std::string path[NUM_OF_DUMPS];
+ android::base::unique_fd fd[NUM_OF_DUMPS];
+ int numFds = 0;
- int fd =
- TEMP_FAILURE_RETRY(open(path.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
- S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH));
- if (fd < 0) {
- MYLOGE("Could not open file %s: %s\n", path.c_str(), strerror(errno));
- return;
+ for (int i = 0; i < NUM_OF_DUMPS; i++) {
+ path[i] = kDumpstateBoardPath + kDumpstateBoardFiles[i];
+ MYLOGI("Calling IDumpstateDevice implementation using path %s\n", path[i].c_str());
+
+ fd[i] = android::base::unique_fd(
+ TEMP_FAILURE_RETRY(open(path[i].c_str(),
+ O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
+ S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)));
+ if (fd[i] < 0) {
+ MYLOGE("Could not open file %s: %s\n", path[i].c_str(), strerror(errno));
+ return;
+ } else {
+ numFds++;
+ }
}
- native_handle_t* handle = native_handle_create(1, 0);
+ native_handle_t *handle = native_handle_create(numFds, 0);
if (handle == nullptr) {
MYLOGE("Could not create native_handle\n");
return;
}
- handle->data[0] = fd;
+
+ for (int i = 0; i < numFds; i++) {
+ handle->data[i] = fd[i].release();
+ }
// TODO: need a timeout mechanism so dumpstate does not hang on device implementation call.
android::hardware::Return<void> status = dumpstate_device->dumpstateBoard(handle);
@@ -1207,14 +1372,26 @@
return;
}
- AddZipEntry("dumpstate-board.txt", path);
+ for (int i = 0; i < numFds; i++) {
+ struct stat s;
+ if (fstat(handle->data[i], &s) == -1) {
+ MYLOGE("Failed to fstat %s: %d\n", kDumpstateBoardFiles[i].c_str(), errno);
+ } else if (s.st_size > 0) {
+ AddZipEntry(kDumpstateBoardFiles[i], path[i]);
+ } else {
+ MYLOGE("Ignoring empty %s\n", kDumpstateBoardFiles[i].c_str());
+ }
+ }
+
printf("*** See dumpstate-board.txt entry ***\n");
native_handle_close(handle);
native_handle_delete(handle);
- if (remove(path.c_str()) != 0) {
- MYLOGE("Could not remove(%s): %s\n", path.c_str(), strerror(errno));
+ for (int i = 0; i < numFds; i++) {
+ if (remove(path[i].c_str()) != 0) {
+ MYLOGE("Could not remove(%s): %s\n", path[i].c_str(), strerror(errno));
+ }
}
}
@@ -1309,7 +1486,7 @@
return true;
}
-static std::string SHA256_file_hash(std::string filepath) {
+static std::string SHA256_file_hash(const std::string& filepath) {
android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(filepath.c_str(), O_RDONLY | O_NONBLOCK
| O_CLOEXEC | O_NOFOLLOW)));
if (fd == -1) {
@@ -1451,6 +1628,7 @@
do_fb = 0;
} else if (ds.extra_options_ == "bugreportwear") {
ds.update_progress_ = true;
+ do_zip_file = 1;
} else if (ds.extra_options_ == "bugreporttelephony") {
telephony_only = true;
} else {
@@ -1494,10 +1672,12 @@
ds.version_ = VERSION_CURRENT;
}
- if (ds.version_ != VERSION_CURRENT && ds.version_ != VERSION_SPLIT_ANR) {
- MYLOGE("invalid version requested ('%s'); suppported values are: ('%s', '%s', '%s')\n",
- ds.version_.c_str(), VERSION_DEFAULT.c_str(), VERSION_CURRENT.c_str(),
- VERSION_SPLIT_ANR.c_str());
+ if (ds.version_ != VERSION_CURRENT && ds.version_ != VERSION_SPLIT_ANR &&
+ ds.version_ != VERSION_PRIORITY_DUMPS) {
+ MYLOGE(
+ "invalid version requested ('%s'); suppported values are: ('%s', '%s', '%s', '%s')\n",
+ ds.version_.c_str(), VERSION_DEFAULT.c_str(), VERSION_CURRENT.c_str(),
+ VERSION_SPLIT_ANR.c_str(), VERSION_PRIORITY_DUMPS.c_str());
exit(1);
}
@@ -1676,15 +1856,8 @@
ds.PrintHeader();
if (telephony_only) {
- DumpIpTables();
- if (!DropRootUser()) {
- return -1;
- }
- do_dmesg();
- DoLogcat();
- DoKmsg();
+ DumpstateTelephonyOnly();
ds.DumpstateBoard();
- DumpModemLogs();
} else {
// Dumps systrace right away, otherwise it will be filled with unnecessary events.
// First try to dump anrd trace if the daemon is running. Otherwise, dump
@@ -1695,10 +1868,7 @@
// Invoking the following dumpsys calls before dump_traces() to try and
// keep the system stats as close to its initial state as possible.
- RunDumpsys("DUMPSYS MEMINFO", {"meminfo", "-a"},
- CommandOptions::WithTimeout(90).DropRoot().Build());
- RunDumpsys("DUMPSYS CPUINFO", {"cpuinfo", "-a"},
- CommandOptions::WithTimeout(10).DropRoot().Build());
+ RunDumpsysCritical();
// TODO: Drop root user and move into dumpstate() once b/28633932 is fixed.
dump_raft();
@@ -1707,7 +1877,9 @@
dump_traces_path = dump_traces();
/* Run some operations that require root. */
- get_tombstone_fds(tombstone_data);
+ tombstone_data.reset(GetDumpFds(TOMBSTONE_DIR, TOMBSTONE_FILE_PREFIX, !ds.IsZipping()));
+ anr_data.reset(GetDumpFds(ANR_DIR, ANR_FILE_PREFIX, !ds.IsZipping()));
+
ds.AddDir(RECOVERY_DIR, true);
ds.AddDir(RECOVERY_DATA_DIR, true);
ds.AddDir(LOGPERSIST_DATA_DIR, false);
@@ -1716,7 +1888,7 @@
ds.AddDir(PROFILE_DATA_DIR_REF, true);
}
add_mountinfo();
- DumpIpTables();
+ DumpIpTablesAsRoot();
// Capture any IPSec policies in play. No keys are exposed here.
RunCommand("IP XFRM POLICY", {"ip", "xfrm", "policy"},
@@ -1726,6 +1898,9 @@
RunCommand("DETAILED SOCKET STATE", {"ss", "-eionptu"},
CommandOptions::WithTimeout(10).Build());
+ // Run iotop as root to show top 100 IO threads
+ RunCommand("IOTOP", {"iotop", "-n", "1", "-m", "100"});
+
if (!DropRootUser()) {
return -1;
}
@@ -1874,5 +2049,8 @@
close(ds.control_socket_fd_);
}
+ CloseDumpFds(tombstone_data.get());
+ CloseDumpFds(anr_data.get());
+
return 0;
}
diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
index f02303b..1bfafba 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -26,10 +26,11 @@
#include <vector>
#include <android-base/macros.h>
+#include <android/os/IDumpstateListener.h>
+#include <utils/StrongPointer.h>
#include <ziparchive/zip_writer.h>
#include "DumpstateUtil.h"
-#include "android/os/BnDumpstate.h"
// Workaround for const char *args[MAX_ARGS_ARRAY_SIZE] variables until they're converted to
// std::vector<std::string>
@@ -49,6 +50,8 @@
} // namespace os
} // namespace android
+class ZipWriter;
+
// TODO: remove once moved to HAL
#ifdef __cplusplus
extern "C" {
@@ -146,9 +149,15 @@
/*
* Temporary version that adds a anr-traces.txt entry. Once tools support it, the current version
- * will be bumped to 2.0-dev-1.
+ * will be bumped to 2.0.
*/
-static std::string VERSION_SPLIT_ANR = "2.0-dev-1";
+static std::string VERSION_SPLIT_ANR = "2.0-dev-split-anr";
+
+/*
+ * Temporary version that adds priority based dumps. Once tools support it, the current version
+ * will be bumped to 2.0.
+ */
+static std::string VERSION_PRIORITY_DUMPS = "2.0-dev-priority-dumps";
/*
* "Alias" for the current version.
@@ -263,6 +272,9 @@
/* Gets the path of a bugreport file with the given suffix. */
std::string GetPath(const std::string& suffix) const;
+ /* Returns true if the current version supports priority dump feature. */
+ bool CurrentVersionSupportsPriorityDumps() const;
+
// TODO: initialize fields on constructor
// dumpstate id - unique after each device reboot.
diff --git a/cmds/dumpstate/tests/dumpstate_test.cpp b/cmds/dumpstate/tests/dumpstate_test.cpp
index 1c19268..92b0c0d 100644
--- a/cmds/dumpstate/tests/dumpstate_test.cpp
+++ b/cmds/dumpstate/tests/dumpstate_test.cpp
@@ -94,7 +94,7 @@
protected:
const std::string kTestPath = dirname(android::base::GetExecutablePath().c_str());
const std::string kFixturesPath = kTestPath + "/../dumpstate_test_fixture/";
- const std::string kTestDataPath = kFixturesPath + "/testdata/";
+ const std::string kTestDataPath = kFixturesPath + "tests/testdata/";
const std::string kSimpleCommand = kFixturesPath + "dumpstate_test_fixture";
const std::string kEchoCommand = "/system/bin/echo";
@@ -477,6 +477,48 @@
EXPECT_THAT(err, StrEq("stderr\n"));
}
+TEST_F(DumpstateTest, RunCommandAsRootIfAvailableOnUserBuild) {
+ if (!IsStandalone()) {
+ // TODO: temporarily disabled because it might cause other tests to fail after dropping
+ // to Shell - need to refactor tests to avoid this problem)
+ MYLOGE("Skipping DumpstateTest.RunCommandAsRootIfAvailableOnUserBuild() on test suite\n")
+ return;
+ }
+ if (!PropertiesHelper::IsUserBuild()) {
+ // Emulates user build if necessarily.
+ SetBuildType("user");
+ }
+
+ DropRoot();
+
+ EXPECT_EQ(0, RunCommand("", {kSimpleCommand, "--uid"},
+ CommandOptions::WithTimeout(1).AsRootIfAvailable().Build()));
+
+ EXPECT_THAT(out, StrEq("2000\nstdout\n"));
+ EXPECT_THAT(err, StrEq("stderr\n"));
+}
+
+TEST_F(DumpstateTest, RunCommandAsRootIfAvailableOnDebugBuild) {
+ if (!IsStandalone()) {
+ // TODO: temporarily disabled because it might cause other tests to fail after dropping
+ // to Shell - need to refactor tests to avoid this problem)
+ MYLOGE("Skipping DumpstateTest.RunCommandAsRootIfAvailableOnDebugBuild() on test suite\n")
+ return;
+ }
+ if (PropertiesHelper::IsUserBuild()) {
+ ALOGI("Skipping RunCommandAsRootNonUserBuild on user builds\n");
+ return;
+ }
+
+ DropRoot();
+
+ EXPECT_EQ(0, RunCommand("", {kSimpleCommand, "--uid"},
+ CommandOptions::WithTimeout(1).AsRootIfAvailable().Build()));
+
+ EXPECT_THAT(out, StrEq("0\nstdout\n"));
+ EXPECT_THAT(err, StrEq("stderr\n"));
+}
+
TEST_F(DumpstateTest, DumpFileNotFoundNoTitle) {
EXPECT_EQ(-1, DumpFile("", "/I/cant/believe/I/exist"));
EXPECT_THAT(out,
@@ -1053,6 +1095,51 @@
EXPECT_THAT(err, StrEq("stderr\n"));
}
+
+TEST_F(DumpstateUtilTest, RunCommandAsRootIfAvailableOnUserBuild) {
+ if (!IsStandalone()) {
+ // TODO: temporarily disabled because it might cause other tests to fail after dropping
+ // to Shell - need to refactor tests to avoid this problem)
+ MYLOGE("Skipping DumpstateUtilTest.RunCommandAsRootIfAvailableOnUserBuild() on test suite\n")
+ return;
+ }
+ CreateFd("RunCommandAsRootIfAvailableOnUserBuild.txt");
+ if (!PropertiesHelper::IsUserBuild()) {
+ // Emulates user build if necessarily.
+ SetBuildType("user");
+ }
+
+ DropRoot();
+
+ EXPECT_EQ(0, RunCommand("", {kSimpleCommand, "--uid"},
+ CommandOptions::WithTimeout(1).AsRootIfAvailable().Build()));
+
+ EXPECT_THAT(out, StrEq("2000\nstdout\n"));
+ EXPECT_THAT(err, StrEq("stderr\n"));
+}
+
+TEST_F(DumpstateUtilTest, RunCommandAsRootIfAvailableOnDebugBuild) {
+ if (!IsStandalone()) {
+ // TODO: temporarily disabled because it might cause other tests to fail after dropping
+ // to Shell - need to refactor tests to avoid this problem)
+ MYLOGE("Skipping DumpstateUtilTest.RunCommandAsRootIfAvailableOnDebugBuild() on test suite\n")
+ return;
+ }
+ CreateFd("RunCommandAsRootIfAvailableOnDebugBuild.txt");
+ if (PropertiesHelper::IsUserBuild()) {
+ ALOGI("Skipping RunCommandAsRootNonUserBuild on user builds\n");
+ return;
+ }
+
+ DropRoot();
+
+ EXPECT_EQ(0, RunCommand("", {kSimpleCommand, "--uid"},
+ CommandOptions::WithTimeout(1).AsRootIfAvailable().Build()));
+
+ EXPECT_THAT(out, StrEq("0\nstdout\n"));
+ EXPECT_THAT(err, StrEq("stderr\n"));
+}
+
TEST_F(DumpstateUtilTest, RunCommandDropRoot) {
if (!IsStandalone()) {
// TODO: temporarily disabled because it might cause other tests to fail after dropping
diff --git a/cmds/dumpstate/testdata/empty-file.txt b/cmds/dumpstate/tests/testdata/empty-file.txt
similarity index 100%
rename from cmds/dumpstate/testdata/empty-file.txt
rename to cmds/dumpstate/tests/testdata/empty-file.txt
diff --git a/cmds/dumpstate/testdata/multiple-lines-with-newline.txt b/cmds/dumpstate/tests/testdata/multiple-lines-with-newline.txt
similarity index 100%
rename from cmds/dumpstate/testdata/multiple-lines-with-newline.txt
rename to cmds/dumpstate/tests/testdata/multiple-lines-with-newline.txt
diff --git a/cmds/dumpstate/testdata/multiple-lines.txt b/cmds/dumpstate/tests/testdata/multiple-lines.txt
similarity index 100%
rename from cmds/dumpstate/testdata/multiple-lines.txt
rename to cmds/dumpstate/tests/testdata/multiple-lines.txt
diff --git a/cmds/dumpstate/testdata/single-line-with-newline.txt b/cmds/dumpstate/tests/testdata/single-line-with-newline.txt
similarity index 100%
rename from cmds/dumpstate/testdata/single-line-with-newline.txt
rename to cmds/dumpstate/tests/testdata/single-line-with-newline.txt
diff --git a/cmds/dumpstate/testdata/single-line.txt b/cmds/dumpstate/tests/testdata/single-line.txt
similarity index 100%
rename from cmds/dumpstate/testdata/single-line.txt
rename to cmds/dumpstate/tests/testdata/single-line.txt
diff --git a/cmds/dumpstate/testdata/stats-invalid-1st-NAN.txt b/cmds/dumpstate/tests/testdata/stats-invalid-1st-NAN.txt
similarity index 100%
rename from cmds/dumpstate/testdata/stats-invalid-1st-NAN.txt
rename to cmds/dumpstate/tests/testdata/stats-invalid-1st-NAN.txt
diff --git a/cmds/dumpstate/testdata/stats-invalid-1st-negative.txt b/cmds/dumpstate/tests/testdata/stats-invalid-1st-negative.txt
similarity index 100%
rename from cmds/dumpstate/testdata/stats-invalid-1st-negative.txt
rename to cmds/dumpstate/tests/testdata/stats-invalid-1st-negative.txt
diff --git a/cmds/dumpstate/testdata/stats-invalid-1st-too-big.txt b/cmds/dumpstate/tests/testdata/stats-invalid-1st-too-big.txt
similarity index 100%
rename from cmds/dumpstate/testdata/stats-invalid-1st-too-big.txt
rename to cmds/dumpstate/tests/testdata/stats-invalid-1st-too-big.txt
diff --git a/cmds/dumpstate/testdata/stats-invalid-2nd-NAN.txt b/cmds/dumpstate/tests/testdata/stats-invalid-2nd-NAN.txt
similarity index 100%
rename from cmds/dumpstate/testdata/stats-invalid-2nd-NAN.txt
rename to cmds/dumpstate/tests/testdata/stats-invalid-2nd-NAN.txt
diff --git a/cmds/dumpstate/testdata/stats-invalid-2nd-negative.txt b/cmds/dumpstate/tests/testdata/stats-invalid-2nd-negative.txt
similarity index 100%
rename from cmds/dumpstate/testdata/stats-invalid-2nd-negative.txt
rename to cmds/dumpstate/tests/testdata/stats-invalid-2nd-negative.txt
diff --git a/cmds/dumpstate/testdata/stats-invalid-2nd-too-big.txt b/cmds/dumpstate/tests/testdata/stats-invalid-2nd-too-big.txt
similarity index 100%
rename from cmds/dumpstate/testdata/stats-invalid-2nd-too-big.txt
rename to cmds/dumpstate/tests/testdata/stats-invalid-2nd-too-big.txt
diff --git a/cmds/dumpstate/testdata/stats-invalid-both-NAN.txt b/cmds/dumpstate/tests/testdata/stats-invalid-both-NAN.txt
similarity index 100%
rename from cmds/dumpstate/testdata/stats-invalid-both-NAN.txt
rename to cmds/dumpstate/tests/testdata/stats-invalid-both-NAN.txt
diff --git a/cmds/dumpstate/testdata/stats-one-run-no-newline.txt b/cmds/dumpstate/tests/testdata/stats-one-run-no-newline.txt
similarity index 100%
rename from cmds/dumpstate/testdata/stats-one-run-no-newline.txt
rename to cmds/dumpstate/tests/testdata/stats-one-run-no-newline.txt
diff --git a/cmds/dumpstate/testdata/stats-two-runs.txt b/cmds/dumpstate/tests/testdata/stats-two-runs.txt
similarity index 100%
rename from cmds/dumpstate/testdata/stats-two-runs.txt
rename to cmds/dumpstate/tests/testdata/stats-two-runs.txt
diff --git a/cmds/dumpstate/utils.cpp b/cmds/dumpstate/utils.cpp
index f649a5e..6ff0dae 100644
--- a/cmds/dumpstate/utils.cpp
+++ b/cmds/dumpstate/utils.cpp
@@ -38,6 +38,7 @@
#include <time.h>
#include <unistd.h>
+#include <memory>
#include <set>
#include <string>
#include <vector>
@@ -46,6 +47,7 @@
#include <android-base/properties.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
+#include <android-base/unique_fd.h>
#include <android/hidl/manager/1.0/IServiceManager.h>
#include <cutils/properties.h>
#include <cutils/sockets.h>
@@ -86,6 +88,7 @@
"/system/bin/sdcard",
"/system/bin/surfaceflinger",
"/system/bin/vehicle_network_service",
+ "/vendor/bin/hw/android.hardware.media.omx@1.0-service", // media.codec
NULL,
};
@@ -95,8 +98,9 @@
"android.hardware.bluetooth@1.0::IBluetoothHci",
"android.hardware.camera.provider@2.4::ICameraProvider",
"android.hardware.graphics.composer@2.1::IComposer",
- "android.hardware.vr@1.0::IVr",
"android.hardware.media.omx@1.0::IOmx",
+ "android.hardware.sensors@1.0::ISensors",
+ "android.hardware.vr@1.0::IVr",
NULL,
};
@@ -253,6 +257,10 @@
name_.c_str(), suffix.c_str());
}
+bool Dumpstate::CurrentVersionSupportsPriorityDumps() const {
+ return (version_ == VERSION_PRIORITY_DUMPS);
+}
+
void Dumpstate::SetProgress(std::unique_ptr<Progress> progress) {
progress_ = std::move(progress);
}
@@ -624,7 +632,7 @@
struct dirent *d;
char *newpath = NULL;
const char *slash = "/";
- int fd, retval = 0;
+ int retval = 0;
if (!title.empty()) {
printf("------ %s (%s) ------\n", title.c_str(), dir);
@@ -666,13 +674,13 @@
}
continue;
}
- fd = TEMP_FAILURE_RETRY(open(newpath, O_RDONLY | O_NONBLOCK | O_CLOEXEC));
- if (fd < 0) {
- retval = fd;
+ android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(newpath, O_RDONLY | O_NONBLOCK | O_CLOEXEC)));
+ if (fd.get() < 0) {
+ retval = -1;
printf("*** %s: %s\n", newpath, strerror(errno));
continue;
}
- (*dump_from_fd)(NULL, newpath, fd);
+ (*dump_from_fd)(NULL, newpath, fd.get());
}
closedir(dirp);
if (!title.empty()) {
@@ -691,11 +699,9 @@
int flags = fcntl(fd, F_GETFL);
if (flags == -1) {
printf("*** %s: failed to get flags on fd %d: %s\n", path, fd, strerror(errno));
- close(fd);
return -1;
} else if (!(flags & O_NONBLOCK)) {
printf("*** %s: fd must have O_NONBLOCK set.\n", path);
- close(fd);
return -1;
}
return DumpFileFromFdToFd(title, path, fd, STDOUT_FILENO, PropertiesHelper::IsDryRun());
@@ -852,15 +858,143 @@
return pids; // whether it was okay or not
}
+const char* DumpTraces(const std::string& traces_path);
+const char* DumpTracesTombstoned(const std::string& traces_dir);
+
/* dump Dalvik and native stack traces, return the trace file location (NULL if none) */
const char *dump_traces() {
DurationReporter duration_reporter("DUMP TRACES");
- const char* result = nullptr;
+ const std::string traces_dir = android::base::GetProperty("dalvik.vm.stack-trace-dir", "");
+ if (!traces_dir.empty()) {
+ return DumpTracesTombstoned(traces_dir);
+ }
- std::string traces_path = android::base::GetProperty("dalvik.vm.stack-trace-file", "");
- if (traces_path.empty()) return nullptr;
+ const std::string traces_file = android::base::GetProperty("dalvik.vm.stack-trace-file", "");
+ if (!traces_file.empty()) {
+ return DumpTraces(traces_file);
+ }
+ return nullptr;
+}
+
+static bool IsZygote(int pid) {
+ static const std::string kZygotePrefix = "zygote";
+
+ std::string cmdline;
+ if (!android::base::ReadFileToString(android::base::StringPrintf("/proc/%d/cmdline", pid),
+ &cmdline)) {
+ return true;
+ }
+
+ return (cmdline.find(kZygotePrefix) == 0);
+}
+
+const char* DumpTracesTombstoned(const std::string& traces_dir) {
+ const std::string temp_file_pattern = traces_dir + "/dumptrace_XXXXXX";
+
+ const size_t buf_size = temp_file_pattern.length() + 1;
+ std::unique_ptr<char[]> file_name_buf(new char[buf_size]);
+ memcpy(file_name_buf.get(), temp_file_pattern.c_str(), buf_size);
+
+ // Create a new, empty file to receive all trace dumps.
+ //
+ // TODO: This can be simplified once we remove support for the old style
+ // dumps. We can have a file descriptor passed in to dump_traces instead
+ // of creating a file, closing it and then reopening it again.
+ android::base::unique_fd fd(mkostemp(file_name_buf.get(), O_APPEND | O_CLOEXEC));
+ if (fd < 0) {
+ MYLOGE("mkostemp on pattern %s: %s\n", file_name_buf.get(), strerror(errno));
+ return nullptr;
+ }
+
+ // Nobody should have access to this temporary file except dumpstate, but we
+ // temporarily grant 'read' to 'others' here because this file is created
+ // when tombstoned is still running as root, but dumped after dropping. This
+ // can go away once support for old style dumping has.
+ const int chmod_ret = fchmod(fd, 0666);
+ if (chmod_ret < 0) {
+ MYLOGE("fchmod on %s failed: %s\n", file_name_buf.get(), strerror(errno));
+ return nullptr;
+ }
+
+ std::unique_ptr<DIR, decltype(&closedir)> proc(opendir("/proc"), closedir);
+ if (proc.get() == nullptr) {
+ MYLOGE("opendir /proc failed: %s\n", strerror(errno));
+ return nullptr;
+ }
+
+ // Number of times process dumping has timed out. If we encounter too many
+ // failures, we'll give up.
+ int timeout_failures = 0;
+ bool dalvik_found = false;
+
+ const std::set<int> hal_pids = get_interesting_hal_pids();
+
+ struct dirent* d;
+ while ((d = readdir(proc.get()))) {
+ int pid = atoi(d->d_name);
+ if (pid <= 0) {
+ continue;
+ }
+
+ const std::string link_name = android::base::StringPrintf("/proc/%d/exe", pid);
+ std::string exe;
+ if (!android::base::Readlink(link_name, &exe)) {
+ continue;
+ }
+
+ bool is_java_process;
+ if (exe == "/system/bin/app_process32" || exe == "/system/bin/app_process64") {
+ // Don't bother dumping backtraces for the zygote.
+ if (IsZygote(pid)) {
+ continue;
+ }
+
+ dalvik_found = true;
+ is_java_process = true;
+ } else if (should_dump_native_traces(exe.c_str()) || hal_pids.find(pid) != hal_pids.end()) {
+ is_java_process = false;
+ } else {
+ // Probably a native process we don't care about, continue.
+ continue;
+ }
+
+ // If 3 backtrace dumps fail in a row, consider debuggerd dead.
+ if (timeout_failures == 3) {
+ dprintf(fd, "ERROR: Too many stack dump failures, exiting.\n");
+ break;
+ }
+
+ const uint64_t start = Nanotime();
+ const int ret = dump_backtrace_to_file_timeout(
+ pid, is_java_process ? kDebuggerdJavaBacktrace : kDebuggerdNativeBacktrace,
+ is_java_process ? 5 : 20, fd);
+
+ if (ret == -1) {
+ dprintf(fd, "dumping failed, likely due to a timeout\n");
+ timeout_failures++;
+ continue;
+ }
+
+ // We've successfully dumped stack traces, reset the failure count
+ // and write a summary of the elapsed time to the file and continue with the
+ // next process.
+ timeout_failures = 0;
+
+ dprintf(fd, "[dump %s stack %d: %.3fs elapsed]\n", is_java_process ? "dalvik" : "native",
+ pid, (float)(Nanotime() - start) / NANOS_PER_SEC);
+ }
+
+ if (!dalvik_found) {
+ MYLOGE("Warning: no Dalvik processes found to dump stacks\n");
+ }
+
+ return file_name_buf.release();
+}
+
+const char* DumpTraces(const std::string& traces_path) {
+ const char* result = NULL;
/* move the old traces.txt (if any) out of the way temporarily */
std::string anrtraces_path = traces_path + ".anr";
if (rename(traces_path.c_str(), anrtraces_path.c_str()) && errno != ENOENT) {
@@ -973,7 +1107,8 @@
/* If 3 backtrace dumps fail in a row, consider debuggerd dead. */
if (timeout_failures == 3) {
dprintf(fd, "too many stack dump failures, skipping...\n");
- } else if (dump_backtrace_to_file_timeout(pid, fd, 20) == -1) {
+ } else if (dump_backtrace_to_file_timeout(
+ pid, kDebuggerdNativeBacktrace, 20, fd) == -1) {
dprintf(fd, "dumping failed, likely due to a timeout\n");
timeout_failures++;
} else {
diff --git a/cmds/dumpsys/Android.bp b/cmds/dumpsys/Android.bp
index 3476964..f68b862 100644
--- a/cmds/dumpsys/Android.bp
+++ b/cmds/dumpsys/Android.bp
@@ -17,6 +17,10 @@
"libbinder",
],
+ static_libs: [
+ "libserviceutils",
+ ],
+
clang: true,
}
diff --git a/cmds/dumpsys/dumpsys.cpp b/cmds/dumpsys/dumpsys.cpp
index f0e7200..c36ab08 100644
--- a/cmds/dumpsys/dumpsys.cpp
+++ b/cmds/dumpsys/dumpsys.cpp
@@ -16,6 +16,7 @@
#include <algorithm>
#include <chrono>
+#include <iomanip>
#include <thread>
#include <android-base/file.h>
@@ -24,6 +25,7 @@
#include <binder/Parcel.h>
#include <binder/ProcessState.h>
#include <binder/TextOutput.h>
+#include <serviceutils/PriorityDumper.h>
#include <utils/Log.h>
#include <utils/Vector.h>
@@ -52,13 +54,18 @@
static void usage() {
fprintf(stderr,
- "usage: dumpsys\n"
+ "usage: dumpsys\n"
" To dump all services.\n"
"or:\n"
- " dumpsys [-t TIMEOUT] [--help | -l | --skip SERVICES | SERVICE [ARGS]]\n"
+ " dumpsys [-t TIMEOUT] [--priority LEVEL] [--help | -l | --skip SERVICES | "
+ "SERVICE [ARGS]]\n"
" --help: shows this help\n"
" -l: only list services, do not dump them\n"
" -t TIMEOUT: TIMEOUT to use in seconds instead of default 10 seconds\n"
+ " --proto: filter services that support dumping data in proto format. Dumps"
+ " will be in proto format.\n"
+ " --priority LEVEL: filter services based on specified priority\n"
+ " LEVEL must be one of CRITICAL | HIGH | NORMAL\n"
" --skip SERVICES: dumps all services but SERVICES (comma-separated list)\n"
" SERVICE [ARGS]: dumps only service SERVICE, optionally passing ARGS to it\n");
}
@@ -72,18 +79,38 @@
return false;
}
+static bool ConvertPriorityTypeToBitmask(const String16& type, int& bitmask) {
+ if (type == PriorityDumper::PRIORITY_ARG_CRITICAL) {
+ bitmask = IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL;
+ return true;
+ }
+ if (type == PriorityDumper::PRIORITY_ARG_HIGH) {
+ bitmask = IServiceManager::DUMP_FLAG_PRIORITY_HIGH;
+ return true;
+ }
+ if (type == PriorityDumper::PRIORITY_ARG_NORMAL) {
+ bitmask = IServiceManager::DUMP_FLAG_PRIORITY_NORMAL;
+ return true;
+ }
+ return false;
+}
+
int Dumpsys::main(int argc, char* const argv[]) {
Vector<String16> services;
Vector<String16> args;
+ String16 priorityType;
Vector<String16> skippedServices;
+ Vector<String16> protoServices;
bool showListOnly = false;
bool skipServices = false;
+ bool filterByProto = false;
int timeoutArg = 10;
- static struct option longOptions[] = {
- {"skip", no_argument, 0, 0 },
- {"help", no_argument, 0, 0 },
- { 0, 0, 0, 0 }
- };
+ int dumpPriorityFlags = IServiceManager::DUMP_FLAG_PRIORITY_ALL;
+ static struct option longOptions[] = {{"priority", required_argument, 0, 0},
+ {"proto", no_argument, 0, 0},
+ {"skip", no_argument, 0, 0},
+ {"help", no_argument, 0, 0},
+ {0, 0, 0, 0}};
// Must reset optind, otherwise subsequent calls will fail (wouldn't happen on main.cpp, but
// happens on test cases).
@@ -102,9 +129,18 @@
case 0:
if (!strcmp(longOptions[optionIndex].name, "skip")) {
skipServices = true;
+ } else if (!strcmp(longOptions[optionIndex].name, "proto")) {
+ filterByProto = true;
} else if (!strcmp(longOptions[optionIndex].name, "help")) {
usage();
return 0;
+ } else if (!strcmp(longOptions[optionIndex].name, "priority")) {
+ priorityType = String16(String8(optarg));
+ if (!ConvertPriorityTypeToBitmask(priorityType, dumpPriorityFlags)) {
+ fprintf(stderr, "\n");
+ usage();
+ return -1;
+ }
}
break;
@@ -150,9 +186,23 @@
if (services.empty() || showListOnly) {
// gets all services
- services = sm_->listServices();
+ services = sm_->listServices(dumpPriorityFlags);
services.sort(sort_func);
- args.add(String16("-a"));
+ if (filterByProto) {
+ protoServices = sm_->listServices(IServiceManager::DUMP_FLAG_PROTO);
+ protoServices.sort(sort_func);
+ Vector<String16> intersection;
+ std::set_intersection(services.begin(), services.end(), protoServices.begin(),
+ protoServices.end(), std::back_inserter(intersection));
+ services = std::move(intersection);
+ args.insertAt(String16(PriorityDumper::PROTO_ARG), 0);
+ }
+ if (dumpPriorityFlags != IServiceManager::DUMP_FLAG_PRIORITY_ALL) {
+ args.insertAt(String16(PriorityDumper::PRIORITY_ARG), 0);
+ args.insertAt(priorityType, 1);
+ } else {
+ args.add(String16("-a"));
+ }
}
const size_t N = services.size();
@@ -176,7 +226,7 @@
}
for (size_t i = 0; i < N; i++) {
- String16 service_name = std::move(services[i]);
+ const String16& service_name = std::move(services[i]);
if (IsSkipped(skippedServices, service_name)) continue;
sp<IBinder> service = sm_->checkService(service_name);
@@ -196,7 +246,11 @@
if (N > 1) {
aout << "------------------------------------------------------------"
"-------------------" << endl;
- aout << "DUMP OF SERVICE " << service_name << ":" << endl;
+ if (dumpPriorityFlags == IServiceManager::DUMP_FLAG_PRIORITY_ALL) {
+ aout << "DUMP OF SERVICE " << service_name << ":" << endl;
+ } else {
+ aout << "DUMP OF SERVICE " << priorityType << " " << service_name << ":" << endl;
+ }
}
// dump blocks until completion, so spawn a thread..
@@ -282,7 +336,14 @@
std::chrono::duration<double> elapsed_seconds =
std::chrono::steady_clock::now() - start;
aout << StringPrintf("--------- %.3fs ", elapsed_seconds.count()).c_str()
- << "was the duration of dumpsys " << service_name << endl;
+ << "was the duration of dumpsys " << service_name;
+
+ using std::chrono::system_clock;
+ const auto finish = system_clock::to_time_t(system_clock::now());
+ std::tm finish_tm;
+ localtime_r(&finish, &finish_tm);
+ aout << ", ending at: " << std::put_time(&finish_tm, "%Y-%m-%d %H:%M:%S")
+ << endl;
}
} else {
aerr << "Can't find service: " << service_name << endl;
diff --git a/cmds/dumpsys/tests/Android.bp b/cmds/dumpsys/tests/Android.bp
index 127e0f3..e182b9d 100644
--- a/cmds/dumpsys/tests/Android.bp
+++ b/cmds/dumpsys/tests/Android.bp
@@ -4,6 +4,7 @@
test_suites: ["device-tests"],
srcs: ["dumpsys_test.cpp"],
+ cflags: ["-Wall", "-Werror"],
shared_libs: [
"libbase",
@@ -14,6 +15,7 @@
static_libs: [
"libdumpsys",
"libgmock",
+ "libserviceutils",
],
clang: true,
diff --git a/cmds/dumpsys/tests/dumpsys_test.cpp b/cmds/dumpsys/tests/dumpsys_test.cpp
index 66beb6d..18a4da9 100644
--- a/cmds/dumpsys/tests/dumpsys_test.cpp
+++ b/cmds/dumpsys/tests/dumpsys_test.cpp
@@ -22,6 +22,7 @@
#include <gtest/gtest.h>
#include <android-base/file.h>
+#include <serviceutils/PriorityDumper.h>
#include <utils/String16.h>
#include <utils/String8.h>
#include <utils/Vector.h>
@@ -35,6 +36,7 @@
using ::testing::Eq;
using ::testing::HasSubstr;
using ::testing::MakeAction;
+using ::testing::Mock;
using ::testing::Not;
using ::testing::Return;
using ::testing::StrEq;
@@ -49,8 +51,8 @@
public:
MOCK_CONST_METHOD1(getService, sp<IBinder>(const String16&));
MOCK_CONST_METHOD1(checkService, sp<IBinder>(const String16&));
- MOCK_METHOD3(addService, status_t(const String16&, const sp<IBinder>&, bool));
- MOCK_METHOD0(listServices, Vector<String16>());
+ MOCK_METHOD4(addService, status_t(const String16&, const sp<IBinder>&, bool, int));
+ MOCK_METHOD1(listServices, Vector<String16>(int));
protected:
MOCK_METHOD0(onAsBinder, IBinder*());
@@ -95,7 +97,7 @@
}
int i = 0;
std::ostringstream actual_stream, expected_stream;
- for (String16 actual : arg) {
+ for (const String16& actual : arg) {
std::string actual_str = String8(actual).c_str();
std::string expected_str = expected[i];
actual_stream << "'" << actual_str << "' ";
@@ -130,7 +132,16 @@
for (auto& service : services) {
services16.add(String16(service.c_str()));
}
- EXPECT_CALL(sm_, listServices()).WillRepeatedly(Return(services16));
+ EXPECT_CALL(sm_, listServices(IServiceManager::DUMP_FLAG_PRIORITY_ALL))
+ .WillRepeatedly(Return(services16));
+ }
+
+ void ExpectListServicesWithPriority(std::vector<std::string> services, int dumpFlags) {
+ Vector<String16> services16;
+ for (auto& service : services) {
+ services16.add(String16(service.c_str()));
+ }
+ EXPECT_CALL(sm_, listServices(dumpFlags)).WillRepeatedly(Return(services16));
}
sp<BinderMock> ExpectCheckService(const char* name, bool running = true) {
@@ -155,10 +166,11 @@
.WillRepeatedly(DoAll(WithArg<0>(WriteOnFd(output)), Return(0)));
}
- void ExpectDumpAndHang(const char* name, int timeout_s, const std::string& output) {
+ sp<BinderMock> ExpectDumpAndHang(const char* name, int timeout_s, const std::string& output) {
sp<BinderMock> binder_mock = ExpectCheckService(name);
EXPECT_CALL(*binder_mock, dump(_, _))
.WillRepeatedly(DoAll(Sleep(timeout_s), WithArg<0>(WriteOnFd(output)), Return(0)));
+ return binder_mock;
}
void CallMain(const std::vector<std::string>& args) {
@@ -177,7 +189,10 @@
}
void AssertRunningServices(const std::vector<std::string>& services) {
- std::string expected("Currently running services:\n");
+ std::string expected;
+ if (services.size() > 1) {
+ expected.append("Currently running services:\n");
+ }
for (const std::string& service : services) {
expected.append(" ").append(service).append("\n");
}
@@ -196,6 +211,13 @@
EXPECT_THAT(stdout_, HasSubstr("DUMP OF SERVICE " + service + ":\n" + dump));
}
+ void AssertDumpedWithPriority(const std::string& service, const std::string& dump,
+ const char16_t* priorityType) {
+ std::string priority = String8(priorityType).c_str();
+ EXPECT_THAT(stdout_,
+ HasSubstr("DUMP OF SERVICE " + priority + " " + service + ":\n" + dump));
+ }
+
void AssertNotDumped(const std::string& dump) {
EXPECT_THAT(stdout_, Not(HasSubstr(dump)));
}
@@ -234,6 +256,39 @@
AssertNotDumped({"Valet"});
}
+// Tests 'dumpsys -l --priority HIGH'
+TEST_F(DumpsysTest, ListAllServicesWithPriority) {
+ ExpectListServicesWithPriority({"Locksmith", "Valet"}, IServiceManager::DUMP_FLAG_PRIORITY_HIGH);
+ ExpectCheckService("Locksmith");
+ ExpectCheckService("Valet");
+
+ CallMain({"-l", "--priority", "HIGH"});
+
+ AssertRunningServices({"Locksmith", "Valet"});
+}
+
+// Tests 'dumpsys -l --priority HIGH' with and empty list
+TEST_F(DumpsysTest, ListEmptyServicesWithPriority) {
+ ExpectListServicesWithPriority({}, IServiceManager::DUMP_FLAG_PRIORITY_HIGH);
+
+ CallMain({"-l", "--priority", "HIGH"});
+
+ AssertRunningServices({});
+}
+
+// Tests 'dumpsys -l --proto'
+TEST_F(DumpsysTest, ListAllServicesWithProto) {
+ ExpectListServicesWithPriority({"Locksmith", "Valet", "Car"},
+ IServiceManager::DUMP_FLAG_PRIORITY_ALL);
+ ExpectListServicesWithPriority({"Valet", "Car"}, IServiceManager::DUMP_FLAG_PROTO);
+ ExpectCheckService("Car");
+ ExpectCheckService("Valet");
+
+ CallMain({"-l", "--proto"});
+
+ AssertRunningServices({"Car", "Valet"});
+}
+
// Tests 'dumpsys service_name' on a service is running
TEST_F(DumpsysTest, DumpRunningService) {
ExpectDump("Valet", "Here's your car");
@@ -245,15 +300,15 @@
// Tests 'dumpsys -t 1 service_name' on a service that times out after 2s
TEST_F(DumpsysTest, DumpRunningServiceTimeout) {
- ExpectDumpAndHang("Valet", 2, "Here's your car");
+ sp<BinderMock> binder_mock = ExpectDumpAndHang("Valet", 2, "Here's your car");
CallMain({"-t", "1", "Valet"});
AssertOutputContains("SERVICE 'Valet' DUMP TIMEOUT (1s) EXPIRED");
AssertNotDumped("Here's your car");
- // Must wait so binder mock is deleted, otherwise test will fail with a leaked object
- sleep(1);
+ // TODO(b/65056227): BinderMock is not destructed because thread is detached on dumpsys.cpp
+ Mock::AllowLeak(binder_mock.get());
}
// Tests 'dumpsys service_name Y U NO HAVE ARGS' on a service that is running
@@ -298,3 +353,98 @@
AssertNotDumped("dump3");
AssertNotDumped("dump5");
}
+
+// Tests 'dumpsys --skip skipped3 skipped5 --priority CRITICAL', which should skip these services
+TEST_F(DumpsysTest, DumpWithSkipAndPriority) {
+ ExpectListServicesWithPriority({"running1", "stopped2", "skipped3", "running4", "skipped5"},
+ IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL);
+ ExpectDump("running1", "dump1");
+ ExpectCheckService("stopped2", false);
+ ExpectDump("skipped3", "dump3");
+ ExpectDump("running4", "dump4");
+ ExpectDump("skipped5", "dump5");
+
+ CallMain({"--priority", "CRITICAL", "--skip", "skipped3", "skipped5"});
+
+ AssertRunningServices({"running1", "running4", "skipped3 (skipped)", "skipped5 (skipped)"});
+ AssertDumpedWithPriority("running1", "dump1", PriorityDumper::PRIORITY_ARG_CRITICAL);
+ AssertDumpedWithPriority("running4", "dump4", PriorityDumper::PRIORITY_ARG_CRITICAL);
+ AssertStopped("stopped2");
+ AssertNotDumped("dump3");
+ AssertNotDumped("dump5");
+}
+
+// Tests 'dumpsys --priority CRITICAL'
+TEST_F(DumpsysTest, DumpWithPriorityCritical) {
+ ExpectListServicesWithPriority({"runningcritical1", "runningcritical2"},
+ IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL);
+ ExpectDump("runningcritical1", "dump1");
+ ExpectDump("runningcritical2", "dump2");
+
+ CallMain({"--priority", "CRITICAL"});
+
+ AssertRunningServices({"runningcritical1", "runningcritical2"});
+ AssertDumpedWithPriority("runningcritical1", "dump1", PriorityDumper::PRIORITY_ARG_CRITICAL);
+ AssertDumpedWithPriority("runningcritical2", "dump2", PriorityDumper::PRIORITY_ARG_CRITICAL);
+}
+
+// Tests 'dumpsys --priority HIGH'
+TEST_F(DumpsysTest, DumpWithPriorityHigh) {
+ ExpectListServicesWithPriority({"runninghigh1", "runninghigh2"},
+ IServiceManager::DUMP_FLAG_PRIORITY_HIGH);
+ ExpectDump("runninghigh1", "dump1");
+ ExpectDump("runninghigh2", "dump2");
+
+ CallMain({"--priority", "HIGH"});
+
+ AssertRunningServices({"runninghigh1", "runninghigh2"});
+ AssertDumpedWithPriority("runninghigh1", "dump1", PriorityDumper::PRIORITY_ARG_HIGH);
+ AssertDumpedWithPriority("runninghigh2", "dump2", PriorityDumper::PRIORITY_ARG_HIGH);
+}
+
+// Tests 'dumpsys --priority NORMAL'
+TEST_F(DumpsysTest, DumpWithPriorityNormal) {
+ ExpectListServicesWithPriority({"runningnormal1", "runningnormal2"},
+ IServiceManager::DUMP_FLAG_PRIORITY_NORMAL);
+ ExpectDump("runningnormal1", "dump1");
+ ExpectDump("runningnormal2", "dump2");
+
+ CallMain({"--priority", "NORMAL"});
+
+ AssertRunningServices({"runningnormal1", "runningnormal2"});
+ AssertDumpedWithPriority("runningnormal1", "dump1", PriorityDumper::PRIORITY_ARG_NORMAL);
+ AssertDumpedWithPriority("runningnormal2", "dump2", PriorityDumper::PRIORITY_ARG_NORMAL);
+}
+
+// Tests 'dumpsys --proto'
+TEST_F(DumpsysTest, DumpWithProto) {
+ ExpectListServicesWithPriority({"run8", "run1", "run2", "run5"},
+ IServiceManager::DUMP_FLAG_PRIORITY_ALL);
+ ExpectListServicesWithPriority({"run3", "run2", "run4", "run8"},
+ IServiceManager::DUMP_FLAG_PROTO);
+ ExpectDump("run2", "dump1");
+ ExpectDump("run8", "dump2");
+
+ CallMain({"--proto"});
+
+ AssertRunningServices({"run2", "run8"});
+ AssertDumped("run2", "dump1");
+ AssertDumped("run8", "dump2");
+}
+
+// Tests 'dumpsys --priority HIGH --proto'
+TEST_F(DumpsysTest, DumpWithPriorityHighAndProto) {
+ ExpectListServicesWithPriority({"runninghigh1", "runninghigh2"},
+ IServiceManager::DUMP_FLAG_PRIORITY_HIGH);
+ ExpectListServicesWithPriority({"runninghigh1", "runninghigh2", "runninghigh3"},
+ IServiceManager::DUMP_FLAG_PROTO);
+
+ ExpectDump("runninghigh1", "dump1");
+ ExpectDump("runninghigh2", "dump2");
+
+ CallMain({"--priority", "HIGH", "--proto"});
+
+ AssertRunningServices({"runninghigh1", "runninghigh2"});
+ AssertDumpedWithPriority("runninghigh1", "dump1", PriorityDumper::PRIORITY_ARG_HIGH);
+ AssertDumpedWithPriority("runninghigh2", "dump2", PriorityDumper::PRIORITY_ARG_HIGH);
+}
diff --git a/cmds/flatland/Android.mk b/cmds/flatland/Android.mk
index c295167..7aa111c 100644
--- a/cmds/flatland/Android.mk
+++ b/cmds/flatland/Android.mk
@@ -8,6 +8,8 @@
Renderers.cpp \
Main.cpp \
+LOCAL_CFLAGS := -Wall -Werror
+
LOCAL_MODULE:= flatland
LOCAL_MODULE_TAGS := tests
diff --git a/cmds/flatland/GLHelper.cpp b/cmds/flatland/GLHelper.cpp
index dfc3e58..d5b3372 100644
--- a/cmds/flatland/GLHelper.cpp
+++ b/cmds/flatland/GLHelper.cpp
@@ -269,24 +269,10 @@
return false;
}
- SurfaceComposerClient::openGlobalTransaction();
- err = sc->setLayer(0x7FFFFFFF);
- if (err != NO_ERROR) {
- fprintf(stderr, "SurfaceComposer::setLayer error: %#x\n", err);
- return false;
- }
- err = sc->setMatrix(scale, 0.0f, 0.0f, scale);
- if (err != NO_ERROR) {
- fprintf(stderr, "SurfaceComposer::setMatrix error: %#x\n", err);
- return false;
- }
-
- err = sc->show();
- if (err != NO_ERROR) {
- fprintf(stderr, "SurfaceComposer::show error: %#x\n", err);
- return false;
- }
- SurfaceComposerClient::closeGlobalTransaction();
+ SurfaceComposerClient::Transaction{}.setLayer(sc, 0x7FFFFFFF)
+ .setMatrix(sc, scale, 0.0f, 0.0f, scale)
+ .show(sc)
+ .apply();
sp<ANativeWindow> anw = sc->getSurface();
EGLSurface s = eglCreateWindowSurface(mDisplay, mConfig, anw.get(), NULL);
diff --git a/cmds/flatland/Main.cpp b/cmds/flatland/Main.cpp
index ec1e543..3d7cac0 100644
--- a/cmds/flatland/Main.cpp
+++ b/cmds/flatland/Main.cpp
@@ -284,7 +284,6 @@
public:
Layer() :
- mFirstFrame(true),
mGLHelper(NULL),
mSurface(EGL_NO_SURFACE) {
}
@@ -358,8 +357,6 @@
}
private:
- bool mFirstFrame;
-
LayerDesc mDesc;
GLHelper* mGLHelper;
@@ -389,7 +386,6 @@
ATRACE_CALL();
bool result;
- EGLint resulte;
float scaleFactor = float(mDesc.runHeights[mInstance]) /
float(mDesc.height);
@@ -465,7 +461,6 @@
ATRACE_CALL();
bool result;
- status_t err;
resetColorGenerator();
diff --git a/cmds/installd/Android.bp b/cmds/installd/Android.bp
index 33db6db..56470d6 100644
--- a/cmds/installd/Android.bp
+++ b/cmds/installd/Android.bp
@@ -4,6 +4,7 @@
cflags: [
"-Wall",
"-Werror",
+ "-Wextra",
],
srcs: [
"CacheItem.cpp",
@@ -25,6 +26,17 @@
],
clang: true,
+
+ tidy: true,
+ tidy_checks: [
+ "-*",
+ "clang-analyzer-security*",
+ "cert-*",
+ "-cert-err58-cpp",
+ ],
+ tidy_flags: [
+ "-warnings-as-errors=clang-analyzer-security*,cert-*"
+ ],
}
//
diff --git a/cmds/installd/CacheTracker.cpp b/cmds/installd/CacheTracker.cpp
index e293948..ea0cd9e 100644
--- a/cmds/installd/CacheTracker.cpp
+++ b/cmds/installd/CacheTracker.cpp
@@ -60,7 +60,7 @@
ATRACE_BEGIN("loadStats tree");
cacheUsed = 0;
- for (auto path : mDataPaths) {
+ for (const auto& path : mDataPaths) {
auto cachePath = read_path_inode(path, "cache", kXattrInodeCache);
auto codeCachePath = read_path_inode(path, "code_cache", kXattrInodeCodeCache);
calculate_tree_size(cachePath, &cacheUsed);
@@ -148,6 +148,7 @@
}
// Bubble up modified time to parent
+ CHECK(p != nullptr);
switch (p->fts_info) {
case FTS_DP:
case FTS_DEFAULT:
@@ -169,7 +170,7 @@
items.clear();
ATRACE_BEGIN("loadItems");
- for (auto path : mDataPaths) {
+ for (const auto& path : mDataPaths) {
loadItemsFrom(read_path_inode(path, "cache", kXattrInodeCache));
loadItemsFrom(read_path_inode(path, "code_cache", kXattrInodeCodeCache));
}
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index a1fea8d..4246536 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -311,6 +311,7 @@
return -1;
}
+#if APPLY_HARD_QUOTAS
if ((dq.dqb_bhardlimit == 0) || (dq.dqb_ihardlimit == 0)) {
auto path = create_data_path(uuid ? uuid->c_str() : nullptr);
struct statvfs stat;
@@ -320,7 +321,8 @@
}
dq.dqb_valid = QIF_LIMITS;
- dq.dqb_bhardlimit = (((stat.f_blocks * stat.f_frsize) / 10) * 9) / QIF_DQBLKSIZE;
+ dq.dqb_bhardlimit =
+ (((static_cast<uint64_t>(stat.f_blocks) * stat.f_frsize) / 10) * 9) / QIF_DQBLKSIZE;
dq.dqb_ihardlimit = (stat.f_files / 2);
if (quotactl(QCMD(Q_SETQUOTA, USRQUOTA), device.c_str(), uid,
reinterpret_cast<char*>(&dq)) != 0) {
@@ -334,6 +336,10 @@
// Hard quota already set; assume it's reasonable
return 0;
}
+#else
+ // Hard quotas disabled
+ return 0;
+#endif
}
binder::Status InstalldNativeService::createAppData(const std::unique_ptr<std::string>& uuid,
@@ -519,6 +525,9 @@
if (access(path.c_str(), F_OK) == 0) {
if (delete_dir_contents(path) != 0) {
res = error("Failed to delete contents of " + path);
+ } else if ((flags & (FLAG_CLEAR_CACHE_ONLY | FLAG_CLEAR_CODE_CACHE_ONLY)) == 0) {
+ remove_path_xattr(path, kXattrInodeCache);
+ remove_path_xattr(path, kXattrInodeCodeCache);
}
}
}
@@ -705,6 +714,9 @@
// Ignore all other GID transitions, since they're kinda shady
LOG(WARNING) << "Ignoring " << p->fts_path << " with unexpected GID " << actual
<< " instead of " << expected;
+ if (!(flags & FLAG_FORCE)) {
+ fts_set(fts, p, FTS_SKIP);
+ }
}
}
}
@@ -915,15 +927,8 @@
return res;
}
-/* Try to ensure free_size bytes of storage are available.
- * Returns 0 on success.
- * This is rather simple-minded because doing a full LRU would
- * be potentially memory-intensive, and without atime it would
- * also require that apps constantly modify file metadata even
- * when just reading from the cache, which is pretty awful.
- */
binder::Status InstalldNativeService::freeCache(const std::unique_ptr<std::string>& uuid,
- int64_t freeStorageSize, int32_t flags) {
+ int64_t targetFreeBytes, int64_t cacheReservedBytes, int32_t flags) {
ENFORCE_UID(AID_SYSTEM);
CHECK_ARGUMENT_UUID(uuid);
std::lock_guard<std::recursive_mutex> lock(mLock);
@@ -938,11 +943,12 @@
return error("Failed to determine free space for " + data_path);
}
- int64_t needed = freeStorageSize - free;
+ int64_t cleared = 0;
+ int64_t needed = targetFreeBytes - free;
LOG(DEBUG) << "Device " << data_path << " has " << free << " free; requested "
- << freeStorageSize << "; needed " << needed;
+ << targetFreeBytes << "; needed " << needed;
- if (free >= freeStorageSize) {
+ if (free >= targetFreeBytes) {
return ok();
}
@@ -999,6 +1005,7 @@
// 2. Populate tracker stats and insert into priority queue
ATRACE_BEGIN("populate");
+ int64_t cacheTotal = 0;
auto cmp = [](std::shared_ptr<CacheTracker> left, std::shared_ptr<CacheTracker> right) {
return (left->getCacheRatio() < right->getCacheRatio());
};
@@ -1007,6 +1014,7 @@
for (const auto& it : trackers) {
it.second->loadStats();
queue.push(it.second);
+ cacheTotal += it.second->cacheUsed;
}
ATRACE_END();
@@ -1023,6 +1031,12 @@
break;
}
+ // Only keep clearing when we haven't pushed into reserved area
+ if (cacheReservedBytes > 0 && cleared >= (cacheTotal - cacheReservedBytes)) {
+ LOG(DEBUG) << "Refusing to clear cached data in reserved space";
+ break;
+ }
+
// Find the best tracker to work with; this might involve swapping
// if the active tracker is no longer the most over quota
bool nextBetter = active && !queue.empty()
@@ -1052,13 +1066,14 @@
}
active->cacheUsed -= item->size;
needed -= item->size;
+ cleared += item->size;
}
// Verify that we're actually done before bailing, since sneaky
// apps might be using hardlinks
if (needed <= 0) {
free = data_disk_free(data_path);
- needed = freeStorageSize - free;
+ needed = targetFreeBytes - free;
if (needed <= 0) {
break;
} else {
@@ -1073,11 +1088,11 @@
}
free = data_disk_free(data_path);
- if (free >= freeStorageSize) {
+ if (free >= targetFreeBytes) {
return ok();
} else {
return error(StringPrintf("Failed to free up %" PRId64 " on %s; final free space %" PRId64,
- freeStorageSize, data_path.c_str(), free));
+ targetFreeBytes, data_path.c_str(), free));
}
}
@@ -1340,7 +1355,7 @@
const std::vector<std::string>& codePaths, std::vector<int64_t>* _aidl_return) {
ENFORCE_UID(AID_SYSTEM);
CHECK_ARGUMENT_UUID(uuid);
- for (auto packageName : packageNames) {
+ for (const auto& packageName : packageNames) {
CHECK_ARGUMENT_PACKAGE_NAME(packageName);
}
// NOTE: Locking is relaxed on this method, since it's limited to
@@ -1379,7 +1394,7 @@
}
ATRACE_BEGIN("obb");
- for (auto packageName : packageNames) {
+ for (const auto& packageName : packageNames) {
auto obbCodePath = create_data_media_obb_path(uuid_, packageName.c_str());
calculate_tree_size(obbCodePath, &extStats.codeSize);
}
@@ -1387,7 +1402,7 @@
if (flags & FLAG_USE_QUOTA && appId >= AID_APP_START) {
ATRACE_BEGIN("code");
- for (auto codePath : codePaths) {
+ for (const auto& codePath : codePaths) {
calculate_tree_size(codePath, &stats.codeSize, -1,
multiuser_get_shared_gid(0, appId));
}
@@ -1398,7 +1413,7 @@
ATRACE_END();
} else {
ATRACE_BEGIN("code");
- for (auto codePath : codePaths) {
+ for (const auto& codePath : codePaths) {
calculate_tree_size(codePath, &stats.codeSize);
}
ATRACE_END();
@@ -1638,6 +1653,7 @@
int64_t videoSize = 0;
int64_t imageSize = 0;
int64_t appSize = 0;
+ int64_t obbSize = 0;
auto device = findQuotaDeviceForUuid(uuid);
if (device.empty()) {
@@ -1685,6 +1701,13 @@
#endif
imageSize = dq.dqb_curspace;
}
+ if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), device.c_str(), AID_MEDIA_OBB,
+ reinterpret_cast<char*>(&dq)) == 0) {
+#if MEASURE_DEBUG
+ LOG(DEBUG) << "quotactl() for GID " << AID_MEDIA_OBB << " " << dq.dqb_curspace;
+#endif
+ obbSize = dq.dqb_curspace;
+ }
ATRACE_END();
ATRACE_BEGIN("apps");
@@ -1695,7 +1718,7 @@
collectQuotaStats(device, userId, appId, nullptr, &extStats);
}
}
- appSize = extStats.dataSize + extStats.cacheSize;
+ appSize = extStats.dataSize;
ATRACE_END();
} else {
ATRACE_BEGIN("manual");
@@ -1741,6 +1764,11 @@
}
fts_close(fts);
ATRACE_END();
+
+ ATRACE_BEGIN("obb");
+ auto obbPath = create_data_media_obb_path(uuid_, "");
+ calculate_tree_size(obbPath, &obbSize);
+ ATRACE_END();
}
std::vector<int64_t> ret;
@@ -1749,6 +1777,7 @@
ret.push_back(videoSize);
ret.push_back(imageSize);
ret.push_back(appSize);
+ ret.push_back(obbSize);
#if MEASURE_DEBUG
LOG(DEBUG) << "Final result " << toString(ret);
#endif
@@ -1808,8 +1837,8 @@
const std::unique_ptr<std::string>& packageName, const std::string& instructionSet,
int32_t dexoptNeeded, const std::unique_ptr<std::string>& outputPath, int32_t dexFlags,
const std::string& compilerFilter, const std::unique_ptr<std::string>& uuid,
- const std::unique_ptr<std::string>& sharedLibraries,
- const std::unique_ptr<std::string>& seInfo) {
+ const std::unique_ptr<std::string>& classLoaderContext,
+ const std::unique_ptr<std::string>& seInfo, bool downgrade) {
ENFORCE_UID(AID_SYSTEM);
CHECK_ARGUMENT_UUID(uuid);
if (packageName && *packageName != "*") {
@@ -1823,10 +1852,11 @@
const char* oat_dir = outputPath ? outputPath->c_str() : nullptr;
const char* compiler_filter = compilerFilter.c_str();
const char* volume_uuid = uuid ? uuid->c_str() : nullptr;
- const char* shared_libraries = sharedLibraries ? sharedLibraries->c_str() : nullptr;
+ const char* class_loader_context = classLoaderContext ? classLoaderContext->c_str() : nullptr;
const char* se_info = seInfo ? seInfo->c_str() : nullptr;
int res = android::installd::dexopt(apk_path, uid, pkgname, instruction_set, dexoptNeeded,
- oat_dir, dexFlags, compiler_filter, volume_uuid, shared_libraries, se_info);
+ oat_dir, dexFlags, compiler_filter, volume_uuid, class_loader_context, se_info,
+ downgrade);
return res ? error(res, "Failed to dexopt") : ok();
}
@@ -1839,7 +1869,7 @@
char boot_marker_path[PKG_PATH_MAX];
sprintf(boot_marker_path,
"%s/%s/%s/.booting",
- android_data_dir.path,
+ android_data_dir.c_str(),
DALVIK_CACHE,
instruction_set);
@@ -2256,13 +2286,13 @@
}
binder::Status InstalldNativeService::deleteOdex(const std::string& apkPath,
- const std::string& instructionSet, const std::string& outputPath) {
+ const std::string& instructionSet, const std::unique_ptr<std::string>& outputPath) {
ENFORCE_UID(AID_SYSTEM);
std::lock_guard<std::recursive_mutex> lock(mLock);
const char* apk_path = apkPath.c_str();
const char* instruction_set = instructionSet.c_str();
- const char* oat_dir = outputPath.c_str();
+ const char* oat_dir = outputPath ? outputPath->c_str() : nullptr;
bool res = delete_odex(apk_path, instruction_set, oat_dir);
return res ? ok() : error();
diff --git a/cmds/installd/InstalldNativeService.h b/cmds/installd/InstalldNativeService.h
index a94223c..c8db3df 100644
--- a/cmds/installd/InstalldNativeService.h
+++ b/cmds/installd/InstalldNativeService.h
@@ -83,8 +83,8 @@
const std::unique_ptr<std::string>& packageName, const std::string& instructionSet,
int32_t dexoptNeeded, const std::unique_ptr<std::string>& outputPath, int32_t dexFlags,
const std::string& compilerFilter, const std::unique_ptr<std::string>& uuid,
- const std::unique_ptr<std::string>& sharedLibraries,
- const std::unique_ptr<std::string>& seInfo);
+ const std::unique_ptr<std::string>& classLoaderContext,
+ const std::unique_ptr<std::string>& seInfo, bool downgrade);
binder::Status rmdex(const std::string& codePath, const std::string& instructionSet);
@@ -101,8 +101,8 @@
binder::Status removeIdmap(const std::string& overlayApkPath);
binder::Status rmPackageDir(const std::string& packageDir);
binder::Status markBootComplete(const std::string& instructionSet);
- binder::Status freeCache(const std::unique_ptr<std::string>& uuid, int64_t freeStorageSize,
- int32_t flags);
+ binder::Status freeCache(const std::unique_ptr<std::string>& uuid, int64_t targetFreeBytes,
+ int64_t cacheReservedBytes, int32_t flags);
binder::Status linkNativeLibraryDirectory(const std::unique_ptr<std::string>& uuid,
const std::string& packageName, const std::string& nativeLibPath32, int32_t userId);
binder::Status createOatDir(const std::string& oatDir, const std::string& instructionSet);
@@ -111,7 +111,7 @@
binder::Status moveAb(const std::string& apkPath, const std::string& instructionSet,
const std::string& outputPath);
binder::Status deleteOdex(const std::string& apkPath, const std::string& instructionSet,
- const std::string& outputPath);
+ const std::unique_ptr<std::string>& outputPath);
binder::Status reconcileSecondaryDexFile(const std::string& dexPath,
const std::string& packageName, int32_t uid, const std::vector<std::string>& isa,
const std::unique_ptr<std::string>& volumeUuid, int32_t storage_flag, bool* _aidl_return);
diff --git a/cmds/installd/binder/android/os/IInstalld.aidl b/cmds/installd/binder/android/os/IInstalld.aidl
index efcae4f..452a2b1 100644
--- a/cmds/installd/binder/android/os/IInstalld.aidl
+++ b/cmds/installd/binder/android/os/IInstalld.aidl
@@ -51,7 +51,7 @@
@nullable @utf8InCpp String outputPath, int dexFlags,
@utf8InCpp String compilerFilter, @nullable @utf8InCpp String uuid,
@nullable @utf8InCpp String sharedLibraries,
- @nullable @utf8InCpp String seInfo);
+ @nullable @utf8InCpp String seInfo, boolean downgrade);
void rmdex(@utf8InCpp String codePath, @utf8InCpp String instructionSet);
@@ -66,7 +66,8 @@
void removeIdmap(@utf8InCpp String overlayApkPath);
void rmPackageDir(@utf8InCpp String packageDir);
void markBootComplete(@utf8InCpp String instructionSet);
- void freeCache(@nullable @utf8InCpp String uuid, long freeStorageSize, int flags);
+ void freeCache(@nullable @utf8InCpp String uuid, long targetFreeBytes,
+ long cacheReservedBytes, int flags);
void linkNativeLibraryDirectory(@nullable @utf8InCpp String uuid,
@utf8InCpp String packageName, @utf8InCpp String nativeLibPath32, int userId);
void createOatDir(@utf8InCpp String oatDir, @utf8InCpp String instructionSet);
@@ -75,7 +76,7 @@
void moveAb(@utf8InCpp String apkPath, @utf8InCpp String instructionSet,
@utf8InCpp String outputPath);
void deleteOdex(@utf8InCpp String apkPath, @utf8InCpp String instructionSet,
- @utf8InCpp String outputPath);
+ @nullable @utf8InCpp String outputPath);
boolean reconcileSecondaryDexFile(@utf8InCpp String dexPath, @utf8InCpp String pkgName,
int uid, in @utf8InCpp String[] isas, @nullable @utf8InCpp String volume_uuid,
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index 22de64e..20b7728 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -28,6 +28,7 @@
#include <unistd.h>
#include <android-base/logging.h>
+#include <android-base/properties.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <android-base/unique_fd.h>
@@ -40,6 +41,7 @@
#include <system/thread_defs.h>
#include "dexopt.h"
+#include "globals.h"
#include "installd_deps.h"
#include "otapreopt_utils.h"
#include "utils.h"
@@ -51,6 +53,15 @@
namespace android {
namespace installd {
+// Should minidebug info be included in compiled artifacts? Even if this value is
+// "true," usage might still be conditional to other constraints, e.g., system
+// property overrides.
+static constexpr bool kEnableMinidebugInfo = true;
+
+static constexpr const char* kMinidebugInfoSystemProperty = "dalvik.vm.dex2oat-minidebuginfo";
+static constexpr bool kMinidebugInfoSystemPropertyDefault = false;
+static constexpr const char* kMinidebugDex2oatFlag = "--generate-mini-debug-info";
+
// Deleter using free() for use with std::unique_ptr<>. See also UniqueCPtr<> below.
struct FreeDelete {
// NOTE: Deleting a const object is valid but free() takes a non-const pointer.
@@ -67,6 +78,14 @@
return unique_fd(-1);
}
+static bool is_debug_runtime() {
+ return android::base::GetProperty("persist.sys.dalvik.vm.lib.2", "") == "libartd.so";
+}
+
+static bool is_debuggable_build() {
+ return android::base::GetBoolProperty("ro.debuggable", false);
+}
+
static bool clear_profile(const std::string& profile) {
unique_fd ufd(open(profile.c_str(), O_WRONLY | O_NOFOLLOW | O_CLOEXEC));
if (ufd.get() < 0) {
@@ -151,7 +170,7 @@
int count = 0;
char buf[kPropertyValueMax];
- strncpy(buf, str, sizeof(buf));
+ strlcpy(buf, str, sizeof(buf));
char *pBuf = buf;
while(strtok_r(pBuf, " ", &ctx) != NULL) {
@@ -191,7 +210,8 @@
static void run_dex2oat(int zip_fd, int oat_fd, int input_vdex_fd, int output_vdex_fd, int image_fd,
const char* input_file_name, const char* output_file_name, int swap_fd,
const char* instruction_set, const char* compiler_filter,
- bool debuggable, bool post_bootcomplete, int profile_fd, const char* shared_libraries) {
+ bool debuggable, bool post_bootcomplete, bool background_job_compile, int profile_fd,
+ const char* class_loader_context) {
static const unsigned int MAX_INSTRUCTION_SET_LEN = 7;
if (strlen(instruction_set) >= MAX_INSTRUCTION_SET_LEN) {
@@ -267,7 +287,17 @@
dex2oat_large_app_threshold);
}
- static const char* DEX2OAT_BIN = "/system/bin/dex2oat";
+ // If the runtime was requested to use libartd.so, we'll run dex2oatd, otherwise dex2oat.
+ const char* dex2oat_bin = "/system/bin/dex2oat";
+ static const char* kDex2oatDebugPath = "/system/bin/dex2oatd";
+ if (is_debug_runtime() || (background_job_compile && is_debuggable_build())) {
+ DCHECK(access(kDex2oatDebugPath, X_OK) == 0);
+ dex2oat_bin = kDex2oatDebugPath;
+ }
+
+ bool generate_minidebug_info = kEnableMinidebugInfo &&
+ android::base::GetBoolProperty(kMinidebugInfoSystemProperty,
+ kMinidebugInfoSystemPropertyDefault);
static const char* RUNTIME_ARG = "--runtime-arg";
@@ -291,6 +321,12 @@
char dex2oat_swap_fd[arraysize("--swap-fd=") + MAX_INT_LEN];
bool have_dex2oat_image_fd = false;
char dex2oat_image_fd[arraysize("--app-image-fd=") + MAX_INT_LEN];
+ size_t class_loader_context_size = arraysize("--class-loader-context=") + PKG_PATH_MAX;
+ char class_loader_context_arg[class_loader_context_size];
+ if (class_loader_context != nullptr) {
+ snprintf(class_loader_context_arg, class_loader_context_size, "--class-loader-context=%s",
+ class_loader_context);
+ }
sprintf(zip_fd_arg, "--zip-fd=%d", zip_fd);
sprintf(zip_location_arg, "--zip-location=%s", relative_input_file_name);
@@ -321,7 +357,8 @@
bool have_dex2oat_compiler_filter_flag = false;
if (skip_compilation) {
- strcpy(dex2oat_compiler_filter_arg, "--compiler-filter=extract");
+ strlcpy(dex2oat_compiler_filter_arg, "--compiler-filter=extract",
+ sizeof(dex2oat_compiler_filter_arg));
have_dex2oat_compiler_filter_flag = true;
have_dex2oat_relocation_skip_flag = true;
} else if (compiler_filter != nullptr) {
@@ -370,7 +407,7 @@
}
- ALOGV("Running %s in=%s out=%s\n", DEX2OAT_BIN, relative_input_file_name, output_file_name);
+ ALOGV("Running %s in=%s out=%s\n", dex2oat_bin, relative_input_file_name, output_file_name);
const char* argv[9 // program name, mandatory arguments and the final NULL
+ (have_dex2oat_isa_variant ? 1 : 0)
@@ -387,11 +424,12 @@
+ (have_app_image_format ? 1 : 0)
+ dex2oat_flags_count
+ (profile_fd == -1 ? 0 : 1)
- + (shared_libraries != nullptr ? 4 : 0)
+ + (class_loader_context != nullptr ? 1 : 0)
+ (has_base_dir ? 1 : 0)
- + (have_dex2oat_large_app_threshold ? 1 : 0)];
+ + (have_dex2oat_large_app_threshold ? 1 : 0)
+ + (generate_minidebug_info ? 1 : 0)];
int i = 0;
- argv[i++] = DEX2OAT_BIN;
+ argv[i++] = dex2oat_bin;
argv[i++] = zip_fd_arg;
argv[i++] = zip_location_arg;
argv[i++] = input_vdex_fd_arg;
@@ -447,20 +485,21 @@
if (profile_fd != -1) {
argv[i++] = profile_arg;
}
- if (shared_libraries != nullptr) {
- argv[i++] = RUNTIME_ARG;
- argv[i++] = "-classpath";
- argv[i++] = RUNTIME_ARG;
- argv[i++] = shared_libraries;
- }
if (has_base_dir) {
argv[i++] = base_dir;
}
+ if (class_loader_context != nullptr) {
+ argv[i++] = class_loader_context_arg;
+ }
+ if (generate_minidebug_info) {
+ argv[i++] = kMinidebugDex2oatFlag;
+ }
+
// Do not add after dex2oat_flags, they should override others for debugging.
argv[i] = NULL;
- execv(DEX2OAT_BIN, (char * const *)argv);
- ALOGE("execv(%s) failed: %s\n", DEX2OAT_BIN, strerror(errno));
+ execv(dex2oat_bin, (char * const *)argv);
+ ALOGE("execv(%s) failed: %s\n", dex2oat_bin, strerror(errno));
}
/*
@@ -639,7 +678,7 @@
static void run_profman_merge(const std::vector<unique_fd>& profiles_fd,
const unique_fd& reference_profile_fd) {
static const size_t MAX_INT_LEN = 32;
- static const char* PROFMAN_BIN = "/system/bin/profman";
+ const char* profman_bin = is_debug_runtime() ? "/system/bin/profmand" : "/system/bin/profman";
std::vector<std::string> profile_args(profiles_fd.size());
char profile_buf[strlen("--profile-file-fd=") + MAX_INT_LEN];
@@ -653,7 +692,7 @@
// program name, reference profile fd, the final NULL and the profile fds
const char* argv[3 + profiles_fd.size()];
int i = 0;
- argv[i++] = PROFMAN_BIN;
+ argv[i++] = profman_bin;
argv[i++] = reference_profile_arg;
for (size_t k = 0; k < profile_args.size(); k++) {
argv[i++] = profile_args[k].c_str();
@@ -661,8 +700,8 @@
// Do not add after dex2oat_flags, they should override others for debugging.
argv[i] = NULL;
- execv(PROFMAN_BIN, (char * const *)argv);
- ALOGE("execv(%s) failed: %s\n", PROFMAN_BIN, strerror(errno));
+ execv(profman_bin, (char * const *)argv);
+ ALOGE("execv(%s) failed: %s\n", profman_bin, strerror(errno));
exit(68); /* only get here on exec failure */
}
@@ -863,6 +902,8 @@
return false;
}
+ // As a security measure we want to write the profile information with the reduced capabilities
+ // of the package user id. So we fork and drop capabilities in the child.
pid_t pid = fork();
if (pid == 0) {
/* child -- drop privileges before continuing */
@@ -900,7 +941,9 @@
if (flock(out_fd.get(), LOCK_UN) != 0) {
PLOG(WARNING) << "Error unlocking profile " << data_profile_location;
}
- exit(0);
+ // Use _exit since we don't want to run the global destructors in the child.
+ // b/62597429
+ _exit(0);
}
/* parent */
int return_code = wait_child(pid);
@@ -941,14 +984,6 @@
return replace_file_extension(oat_path, ".vdex");
}
-static bool add_extension_to_file_name(char* file_name, const char* extension) {
- if (strlen(file_name) + strlen(extension) + 1 > PKG_PATH_MAX) {
- return false;
- }
- strcat(file_name, extension);
- return true;
-}
-
static int open_output_file(const char* file_name, bool recreate, int permissions) {
int flags = O_RDWR | O_CREAT;
if (recreate) {
@@ -986,14 +1021,22 @@
return oat_dir == nullptr || oat_dir[0] == '!';
}
+// Best-effort check whether we can fit the the path into our buffers.
+// Note: the cache path will require an additional 5 bytes for ".swap", but we'll try to run
+// without a swap file, if necessary. Reference profiles file also add an extra ".prof"
+// extension to the cache path (5 bytes).
+// TODO(calin): move away from char* buffers and PKG_PATH_MAX.
+static bool validate_dex_path_size(const std::string& dex_path) {
+ if (dex_path.size() >= (PKG_PATH_MAX - 8)) {
+ LOG(ERROR) << "dex_path too long: " << dex_path;
+ return false;
+ }
+ return true;
+}
+
static bool create_oat_out_path(const char* apk_path, const char* instruction_set,
const char* oat_dir, bool is_secondary_dex, /*out*/ char* out_oat_path) {
- // Early best-effort check whether we can fit the the path into our buffers.
- // Note: the cache path will require an additional 5 bytes for ".swap", but we'll try to run
- // without a swap file, if necessary. Reference profiles file also add an extra ".prof"
- // extension to the cache path (5 bytes).
- if (strlen(apk_path) >= (PKG_PATH_MAX - 8)) {
- ALOGE("apk_path too long '%s'\n", apk_path);
+ if (!validate_dex_path_size(apk_path)) {
return false;
}
@@ -1121,10 +1164,9 @@
// (re)Creates the app image if needed.
Dex2oatFileWrapper maybe_open_app_image(const char* out_oat_path, bool profile_guided,
bool is_public, int uid, bool is_secondary_dex) {
- // Use app images only if it is enabled (by a set image format) and we are compiling
- // profile-guided (so the app image doesn't conservatively contain all classes).
- // Note that we don't create an image for secondary dex files.
- if (is_secondary_dex || !profile_guided) {
+
+ // We don't create an image for secondary dex files.
+ if (is_secondary_dex) {
return Dex2oatFileWrapper();
}
@@ -1133,6 +1175,14 @@
// Happens when the out_oat_path has an unknown extension.
return Dex2oatFileWrapper();
}
+
+ // Use app images only if it is enabled (by a set image format) and we are compiling
+ // profile-guided (so the app image doesn't conservatively contain all classes).
+ if (!profile_guided) {
+ // In case there is a stale image, remove it now. Ignore any error.
+ unlink(image_path.c_str());
+ return Dex2oatFileWrapper();
+ }
char app_image_format[kPropertyValueMax];
bool have_app_image_format =
get_property("dalvik.vm.appimageformat", app_image_format, NULL) > 0;
@@ -1169,21 +1219,16 @@
if (!ShouldUseSwapFileForDexopt()) {
return invalid_unique_fd();
}
- // Make sure there really is enough space.
- char swap_file_name[PKG_PATH_MAX];
- strcpy(swap_file_name, out_oat_path);
- if (!add_extension_to_file_name(swap_file_name, ".swap")) {
- return invalid_unique_fd();
- }
+ auto swap_file_name = std::string(out_oat_path) + ".swap";
unique_fd swap_fd(open_output_file(
- swap_file_name, /*recreate*/true, /*permissions*/0600));
+ swap_file_name.c_str(), /*recreate*/true, /*permissions*/0600));
if (swap_fd.get() < 0) {
// Could not create swap file. Optimistically go on and hope that we can compile
// without it.
- ALOGE("installd could not create '%s' for swap during dexopt\n", swap_file_name);
+ ALOGE("installd could not create '%s' for swap during dexopt\n", swap_file_name.c_str());
} else {
// Immediately unlink. We don't really want to hit flash.
- if (unlink(swap_file_name) < 0) {
+ if (unlink(swap_file_name.c_str()) < 0) {
PLOG(ERROR) << "Couldn't unlink swap file " << swap_file_name;
}
}
@@ -1212,9 +1257,9 @@
// Opens the vdex files and assigns the input fd to in_vdex_wrapper_fd and the output fd to
// out_vdex_wrapper_fd. Returns true for success or false in case of errors.
-bool open_vdex_files(const char* apk_path, const char* out_oat_path, int dexopt_needed,
+bool open_vdex_files_for_dex2oat(const char* apk_path, const char* out_oat_path, int dexopt_needed,
const char* instruction_set, bool is_public, int uid, bool is_secondary_dex,
- Dex2oatFileWrapper* in_vdex_wrapper_fd,
+ bool profile_guided, Dex2oatFileWrapper* in_vdex_wrapper_fd,
Dex2oatFileWrapper* out_vdex_wrapper_fd) {
CHECK(in_vdex_wrapper_fd != nullptr);
CHECK(out_vdex_wrapper_fd != nullptr);
@@ -1224,6 +1269,14 @@
int dexopt_action = abs(dexopt_needed);
bool is_odex_location = dexopt_needed < 0;
std::string in_vdex_path_str;
+
+ // Infer the name of the output VDEX.
+ const std::string out_vdex_path_str = create_vdex_filename(out_oat_path);
+ if (out_vdex_path_str.empty()) {
+ return false;
+ }
+
+ bool update_vdex_in_place = false;
if (dexopt_action != DEX2OAT_FROM_SCRATCH) {
// Open the possibly existing vdex. If none exist, we pass -1 to dex2oat for input-vdex-fd.
const char* path = nullptr;
@@ -1242,26 +1295,32 @@
ALOGE("installd cannot compute input vdex location for '%s'\n", path);
return false;
}
- if (dexopt_action == DEX2OAT_FOR_BOOT_IMAGE) {
- // When we dex2oat because of boot image change, we are going to update
- // in-place the vdex file.
+ // We can update in place when all these conditions are met:
+ // 1) The vdex location to write to is the same as the vdex location to read (vdex files
+ // on /system typically cannot be updated in place).
+ // 2) We dex2oat due to boot image change, because we then know the existing vdex file
+ // cannot be currently used by a running process.
+ // 3) We are not doing a profile guided compilation, because dexlayout requires two
+ // different vdex files to operate.
+ update_vdex_in_place =
+ (in_vdex_path_str == out_vdex_path_str) &&
+ (dexopt_action == DEX2OAT_FOR_BOOT_IMAGE) &&
+ !profile_guided;
+ if (update_vdex_in_place) {
+ // Open the file read-write to be able to update it.
in_vdex_wrapper_fd->reset(open(in_vdex_path_str.c_str(), O_RDWR, 0));
+ if (in_vdex_wrapper_fd->get() == -1) {
+ // If we failed to open the file, we cannot update it in place.
+ update_vdex_in_place = false;
+ }
} else {
in_vdex_wrapper_fd->reset(open(in_vdex_path_str.c_str(), O_RDONLY, 0));
}
}
- // Infer the name of the output VDEX and create it.
- const std::string out_vdex_path_str = create_vdex_filename(out_oat_path);
- if (out_vdex_path_str.empty()) {
- return false;
- }
-
- // If we are compiling because the boot image is out of date, we do not
- // need to recreate a vdex, and can use the same existing one.
- if (dexopt_action == DEX2OAT_FOR_BOOT_IMAGE &&
- in_vdex_wrapper_fd->get() != -1 &&
- in_vdex_path_str == out_vdex_path_str) {
+ // If we are updating the vdex in place, we do not need to recreate a vdex,
+ // and can use the same existing one.
+ if (update_vdex_in_place) {
// We unlink the file in case the invocation of dex2oat fails, to ensure we don't
// have bogus stale vdex files.
out_vdex_wrapper_fd->reset(
@@ -1311,6 +1370,37 @@
return wrapper_fd;
}
+// Creates RDONLY fds for oat and vdex files, if exist.
+// Returns false if it fails to create oat out path for the given apk path.
+// Note that the method returns true even if the files could not be opened.
+bool maybe_open_oat_and_vdex_file(const std::string& apk_path,
+ const std::string& oat_dir,
+ const std::string& instruction_set,
+ bool is_secondary_dex,
+ unique_fd* oat_file_fd,
+ unique_fd* vdex_file_fd) {
+ char oat_path[PKG_PATH_MAX];
+ if (!create_oat_out_path(apk_path.c_str(),
+ instruction_set.c_str(),
+ oat_dir.c_str(),
+ is_secondary_dex,
+ oat_path)) {
+ return false;
+ }
+ oat_file_fd->reset(open(oat_path, O_RDONLY));
+ if (oat_file_fd->get() < 0) {
+ PLOG(INFO) << "installd cannot open oat file during dexopt" << oat_path;
+ }
+
+ std::string vdex_filename = create_vdex_filename(oat_path);
+ vdex_file_fd->reset(open(vdex_filename.c_str(), O_RDONLY));
+ if (vdex_file_fd->get() < 0) {
+ PLOG(INFO) << "installd cannot open vdex file during dexopt" << vdex_filename;
+ }
+
+ return true;
+}
+
// Updates the access times of out_oat_path based on those from apk_path.
void update_out_oat_access_times(const char* apk_path, const char* out_oat_path) {
struct stat input_stat;
@@ -1332,40 +1422,69 @@
// The analyzer will check if the dex_file needs to be (re)compiled to match the compiler_filter.
// If this is for a profile guided compilation, profile_was_updated will tell whether or not
// the profile has changed.
-static void exec_dexoptanalyzer(const std::string& dex_file, const char* instruction_set,
- const char* compiler_filter, bool profile_was_updated) {
- static const char* DEXOPTANALYZER_BIN = "/system/bin/dexoptanalyzer";
+static void exec_dexoptanalyzer(const std::string& dex_file, int vdex_fd, int oat_fd,
+ int zip_fd, const std::string& instruction_set, const std::string& compiler_filter,
+ bool profile_was_updated, bool downgrade,
+ const char* class_loader_context) {
+ CHECK_GE(zip_fd, 0);
+ const char* dexoptanalyzer_bin =
+ is_debug_runtime()
+ ? "/system/bin/dexoptanalyzerd"
+ : "/system/bin/dexoptanalyzer";
static const unsigned int MAX_INSTRUCTION_SET_LEN = 7;
- if (strlen(instruction_set) >= MAX_INSTRUCTION_SET_LEN) {
- ALOGE("Instruction set %s longer than max length of %d",
- instruction_set, MAX_INSTRUCTION_SET_LEN);
+ if (instruction_set.size() >= MAX_INSTRUCTION_SET_LEN) {
+ LOG(ERROR) << "Instruction set " << instruction_set
+ << " longer than max length of " << MAX_INSTRUCTION_SET_LEN;
return;
}
- char dex_file_arg[strlen("--dex-file=") + PKG_PATH_MAX];
- char isa_arg[strlen("--isa=") + MAX_INSTRUCTION_SET_LEN];
- char compiler_filter_arg[strlen("--compiler-filter=") + kPropertyValueMax];
+ std::string dex_file_arg = "--dex-file=" + dex_file;
+ std::string oat_fd_arg = "--oat-fd=" + std::to_string(oat_fd);
+ std::string vdex_fd_arg = "--vdex-fd=" + std::to_string(vdex_fd);
+ std::string zip_fd_arg = "--zip-fd=" + std::to_string(zip_fd);
+ std::string isa_arg = "--isa=" + instruction_set;
+ std::string compiler_filter_arg = "--compiler-filter=" + compiler_filter;
const char* assume_profile_changed = "--assume-profile-changed";
-
- sprintf(dex_file_arg, "--dex-file=%s", dex_file.c_str());
- sprintf(isa_arg, "--isa=%s", instruction_set);
- sprintf(compiler_filter_arg, "--compiler-filter=%s", compiler_filter);
+ const char* downgrade_flag = "--downgrade";
+ std::string class_loader_context_arg = "--class-loader-context=";
+ if (class_loader_context != nullptr) {
+ class_loader_context_arg += class_loader_context;
+ }
// program name, dex file, isa, filter, the final NULL
- const char* argv[5 + (profile_was_updated ? 1 : 0)];
+ const int argc = 6 +
+ (profile_was_updated ? 1 : 0) +
+ (vdex_fd >= 0 ? 1 : 0) +
+ (oat_fd >= 0 ? 1 : 0) +
+ (downgrade ? 1 : 0) +
+ (class_loader_context != nullptr ? 1 : 0);
+ const char* argv[argc];
int i = 0;
- argv[i++] = DEXOPTANALYZER_BIN;
- argv[i++] = dex_file_arg;
- argv[i++] = isa_arg;
- argv[i++] = compiler_filter_arg;
+ argv[i++] = dexoptanalyzer_bin;
+ argv[i++] = dex_file_arg.c_str();
+ argv[i++] = isa_arg.c_str();
+ argv[i++] = compiler_filter_arg.c_str();
+ if (oat_fd >= 0) {
+ argv[i++] = oat_fd_arg.c_str();
+ }
+ if (vdex_fd >= 0) {
+ argv[i++] = vdex_fd_arg.c_str();
+ }
+ argv[i++] = zip_fd_arg.c_str();
if (profile_was_updated) {
argv[i++] = assume_profile_changed;
}
+ if (downgrade) {
+ argv[i++] = downgrade_flag;
+ }
+ if (class_loader_context != nullptr) {
+ argv[i++] = class_loader_context_arg.c_str();
+ }
argv[i] = NULL;
- execv(DEXOPTANALYZER_BIN, (char * const *)argv);
- ALOGE("execv(%s) failed: %s\n", DEXOPTANALYZER_BIN, strerror(errno));
+ execv(dexoptanalyzer_bin, (char * const *)argv);
+ ALOGE("execv(%s) failed: %s\n", dexoptanalyzer_bin, strerror(errno));
}
// Prepares the oat dir for the secondary dex files.
@@ -1442,7 +1561,8 @@
static bool process_secondary_dex_dexopt(const char* original_dex_path, const char* pkgname,
int dexopt_flags, const char* volume_uuid, int uid, const char* instruction_set,
const char* compiler_filter, bool* is_public_out, int* dexopt_needed_out,
- std::string* oat_dir_out, std::string* dex_path_out) {
+ std::string* oat_dir_out, std::string* dex_path_out, bool downgrade,
+ const char* class_loader_context) {
int storage_flag;
if ((dexopt_flags & DEXOPT_STORAGE_CE) != 0) {
@@ -1472,6 +1592,9 @@
}
}
const std::string& dex_path = *dex_path_out;
+ if (!validate_dex_path_size(dex_path)) {
+ return false;
+ }
if (!validate_secondary_dex_path(pkgname, dex_path, volume_uuid, uid, storage_flag)) {
LOG(ERROR) << "Could not validate secondary dex path " << dex_path;
return false;
@@ -1503,12 +1626,36 @@
// Analyze profiles.
bool profile_was_updated = analyze_profiles(uid, dex_path, /*is_secondary_dex*/true);
+ unique_fd oat_file_fd;
+ unique_fd vdex_file_fd;
+ unique_fd zip_fd;
+ zip_fd.reset(open(dex_path.c_str(), O_RDONLY));
+ if (zip_fd.get() < 0) {
+ PLOG(ERROR) << "installd cannot open " << dex_path << " for input during dexopt";
+ return false;
+ }
+ if (!maybe_open_oat_and_vdex_file(dex_path,
+ *oat_dir_out,
+ instruction_set,
+ true /* is_secondary_dex */,
+ &oat_file_fd,
+ &vdex_file_fd)) {
+ return false;
+ }
+
pid_t pid = fork();
if (pid == 0) {
// child -- drop privileges before continuing.
drop_capabilities(uid);
// Run dexoptanalyzer to get dexopt_needed code.
- exec_dexoptanalyzer(dex_path, instruction_set, compiler_filter, profile_was_updated);
+ exec_dexoptanalyzer(dex_path,
+ vdex_file_fd.get(),
+ oat_file_fd.get(),
+ zip_fd.get(),
+ instruction_set,
+ compiler_filter,
+ profile_was_updated,
+ downgrade, class_loader_context);
exit(DEXOPTANALYZER_BIN_EXEC_ERROR);
}
@@ -1535,18 +1682,29 @@
int dexopt(const char* dex_path, uid_t uid, const char* pkgname, const char* instruction_set,
int dexopt_needed, const char* oat_dir, int dexopt_flags, const char* compiler_filter,
- const char* volume_uuid, const char* shared_libraries, const char* se_info) {
+ const char* volume_uuid, const char* class_loader_context, const char* se_info,
+ bool downgrade) {
CHECK(pkgname != nullptr);
CHECK(pkgname[0] != 0);
if ((dexopt_flags & ~DEXOPT_MASK) != 0) {
LOG_FATAL("dexopt flags contains unknown fields\n");
}
+ if (!validate_dex_path_size(dex_path)) {
+ return -1;
+ }
+
+ if (class_loader_context != nullptr && strlen(class_loader_context) > PKG_PATH_MAX) {
+ LOG(ERROR) << "Class loader context exceeds the allowed size: " << class_loader_context;
+ return -1;
+ }
+
bool is_public = (dexopt_flags & DEXOPT_PUBLIC) != 0;
bool debuggable = (dexopt_flags & DEXOPT_DEBUGGABLE) != 0;
bool boot_complete = (dexopt_flags & DEXOPT_BOOTCOMPLETE) != 0;
bool profile_guided = (dexopt_flags & DEXOPT_PROFILE_GUIDED) != 0;
bool is_secondary_dex = (dexopt_flags & DEXOPT_SECONDARY_DEX) != 0;
+ bool background_job_compile = (dexopt_flags & DEXOPT_IDLE_BACKGROUND_JOB) != 0;
// Check if we're dealing with a secondary dex file and if we need to compile it.
std::string oat_dir_str;
@@ -1554,7 +1712,7 @@
if (is_secondary_dex) {
if (process_secondary_dex_dexopt(dex_path, pkgname, dexopt_flags, volume_uuid, uid,
instruction_set, compiler_filter, &is_public, &dexopt_needed, &oat_dir_str,
- &dex_real_path)) {
+ &dex_real_path, downgrade, class_loader_context)) {
oat_dir = oat_dir_str.c_str();
dex_path = dex_real_path.c_str();
if (dexopt_needed == NO_DEXOPT_NEEDED) {
@@ -1588,8 +1746,8 @@
// Open vdex files.
Dex2oatFileWrapper in_vdex_fd;
Dex2oatFileWrapper out_vdex_fd;
- if (!open_vdex_files(dex_path, out_oat_path, dexopt_needed, instruction_set, is_public, uid,
- is_secondary_dex, &in_vdex_fd, &out_vdex_fd)) {
+ if (!open_vdex_files_for_dex2oat(dex_path, out_oat_path, dexopt_needed, instruction_set,
+ is_public, uid, is_secondary_dex, profile_guided, &in_vdex_fd, &out_vdex_fd)) {
return -1;
}
@@ -1642,8 +1800,9 @@
compiler_filter,
debuggable,
boot_complete,
+ background_job_compile,
reference_profile_fd.get(),
- shared_libraries);
+ class_loader_context);
_exit(68); /* only get here on exec failure */
} else {
int res = wait_child(pid);
@@ -1731,14 +1890,24 @@
/*out*/bool* out_secondary_dex_exists) {
// Set out to false to start with, just in case we have validation errors.
*out_secondary_dex_exists = false;
+ if (!validate_dex_path_size(dex_path)) {
+ return false;
+ }
+
if (isas.size() == 0) {
LOG(ERROR) << "reconcile_secondary_dex_file called with empty isas vector";
return false;
}
const char* volume_uuid_cstr = volume_uuid == nullptr ? nullptr : volume_uuid->c_str();
+
+ // Note that we cannot validate the package path here because the file might not exist
+ // and we cannot call realpath to resolve system symlinks. Since /data/user/0 symlinks to
+ // /data/data/ a lot of validations will fail if we attempt to check the package path.
+ // It is still ok to be more relaxed because any file removal is done after forking and
+ // dropping capabilities.
if (!validate_secondary_dex_path(pkgname.c_str(), dex_path.c_str(), volume_uuid_cstr,
- uid, storage_flag)) {
+ uid, storage_flag, /*validate_package_path*/ false)) {
LOG(ERROR) << "Could not validate secondary dex path " << dex_path;
return false;
}
@@ -1752,37 +1921,56 @@
return false;
}
- // The secondary dex does not exist anymore. Clear any generated files.
- char oat_path[PKG_PATH_MAX];
- char oat_dir[PKG_PATH_MAX];
- char oat_isa_dir[PKG_PATH_MAX];
- bool result = true;
- for (size_t i = 0; i < isas.size(); i++) {
- if (!create_secondary_dex_oat_layout(dex_path, isas[i], oat_dir, oat_isa_dir, oat_path)) {
- LOG(ERROR) << "Could not create secondary odex layout: " << dex_path;
- result = false;
- continue;
- }
+ // As a security measure we want to unlink art artifacts with the reduced capabilities
+ // of the package user id. So we fork and drop capabilities in the child.
+ pid_t pid = fork();
+ if (pid == 0) {
+ // The secondary dex does not exist anymore. Clear any generated files.
+ char oat_path[PKG_PATH_MAX];
+ char oat_dir[PKG_PATH_MAX];
+ char oat_isa_dir[PKG_PATH_MAX];
+ bool result = true;
+ /* child -- drop privileges before continuing */
+ drop_capabilities(uid);
+ for (size_t i = 0; i < isas.size(); i++) {
+ if (!create_secondary_dex_oat_layout(dex_path,
+ isas[i],
+ oat_dir,
+ oat_isa_dir,
+ oat_path)) {
+ LOG(ERROR) << "Could not create secondary odex layout: "
+ << dex_path;
+ result = false;
+ continue;
+ }
- // Delete oat/vdex/art files.
- result = unlink_if_exists(oat_path) && result;
- result = unlink_if_exists(create_vdex_filename(oat_path)) && result;
- result = unlink_if_exists(create_image_filename(oat_path)) && result;
+ // Delete oat/vdex/art files.
+ result = unlink_if_exists(oat_path) && result;
+ result = unlink_if_exists(create_vdex_filename(oat_path)) && result;
+ result = unlink_if_exists(create_image_filename(oat_path)) && result;
- // Delete profiles.
- std::string current_profile = create_current_profile_path(
+ // Delete profiles.
+ std::string current_profile = create_current_profile_path(
multiuser_get_user_id(uid), dex_path, /*is_secondary*/true);
- std::string reference_profile = create_reference_profile_path(
+ std::string reference_profile = create_reference_profile_path(
dex_path, /*is_secondary*/true);
- result = unlink_if_exists(current_profile) && result;
- result = unlink_if_exists(reference_profile) && result;
+ result = unlink_if_exists(current_profile) && result;
+ result = unlink_if_exists(reference_profile) && result;
- // Try removing the directories as well, they might be empty.
- result = rmdir_if_empty(oat_isa_dir) && result;
- result = rmdir_if_empty(oat_dir) && result;
+ // We upgraded once the location of current profile for secondary dex files.
+ // Check for any previous left-overs and remove them as well.
+ std::string old_current_profile = dex_path + ".prof";
+ result = unlink_if_exists(old_current_profile);
+
+ // Try removing the directories as well, they might be empty.
+ result = rmdir_if_empty(oat_isa_dir) && result;
+ result = rmdir_if_empty(oat_dir) && result;
+ }
+ result ? _exit(0) : _exit(1);
}
- return result;
+ int return_code = wait_child(pid);
+ return return_code == 0;
}
// Helper for move_ab, so that we can have common failure-case cleanup.
@@ -1947,5 +2135,98 @@
return return_value_oat && return_value_art && return_value_vdex;
}
+static bool is_absolute_path(const std::string& path) {
+ if (path.find('/') != 0 || path.find("..") != std::string::npos) {
+ LOG(ERROR) << "Invalid absolute path " << path;
+ return false;
+ } else {
+ return true;
+ }
+}
+
+static bool is_valid_instruction_set(const std::string& instruction_set) {
+ // TODO: add explicit whitelisting of instruction sets
+ if (instruction_set.find('/') != std::string::npos) {
+ LOG(ERROR) << "Invalid instruction set " << instruction_set;
+ return false;
+ } else {
+ return true;
+ }
+}
+
+bool calculate_oat_file_path_default(char path[PKG_PATH_MAX], const char *oat_dir,
+ const char *apk_path, const char *instruction_set) {
+ std::string oat_dir_ = oat_dir;
+ std::string apk_path_ = apk_path;
+ std::string instruction_set_ = instruction_set;
+
+ if (!is_absolute_path(oat_dir_)) return false;
+ if (!is_absolute_path(apk_path_)) return false;
+ if (!is_valid_instruction_set(instruction_set_)) return false;
+
+ std::string::size_type end = apk_path_.rfind('.');
+ std::string::size_type start = apk_path_.rfind('/', end);
+ if (end == std::string::npos || start == std::string::npos) {
+ LOG(ERROR) << "Invalid apk_path " << apk_path_;
+ return false;
+ }
+
+ std::string res_ = oat_dir_ + '/' + instruction_set + '/'
+ + apk_path_.substr(start + 1, end - start - 1) + ".odex";
+ const char* res = res_.c_str();
+ if (strlen(res) >= PKG_PATH_MAX) {
+ LOG(ERROR) << "Result too large";
+ return false;
+ } else {
+ strlcpy(path, res, PKG_PATH_MAX);
+ return true;
+ }
+}
+
+bool calculate_odex_file_path_default(char path[PKG_PATH_MAX], const char *apk_path,
+ const char *instruction_set) {
+ std::string apk_path_ = apk_path;
+ std::string instruction_set_ = instruction_set;
+
+ if (!is_absolute_path(apk_path_)) return false;
+ if (!is_valid_instruction_set(instruction_set_)) return false;
+
+ std::string::size_type end = apk_path_.rfind('.');
+ std::string::size_type start = apk_path_.rfind('/', end);
+ if (end == std::string::npos || start == std::string::npos) {
+ LOG(ERROR) << "Invalid apk_path " << apk_path_;
+ return false;
+ }
+
+ std::string oat_dir = apk_path_.substr(0, start + 1) + "oat";
+ return calculate_oat_file_path_default(path, oat_dir.c_str(), apk_path, instruction_set);
+}
+
+bool create_cache_path_default(char path[PKG_PATH_MAX], const char *src,
+ const char *instruction_set) {
+ std::string src_ = src;
+ std::string instruction_set_ = instruction_set;
+
+ if (!is_absolute_path(src_)) return false;
+ if (!is_valid_instruction_set(instruction_set_)) return false;
+
+ for (auto it = src_.begin() + 1; it < src_.end(); ++it) {
+ if (*it == '/') {
+ *it = '@';
+ }
+ }
+
+ std::string res_ = android_data_dir + DALVIK_CACHE + '/' + instruction_set_ + src_
+ + DALVIK_CACHE_POSTFIX;
+ const char* res = res_.c_str();
+ if (strlen(res) >= PKG_PATH_MAX) {
+ LOG(ERROR) << "Result too large";
+ return false;
+ } else {
+ strlcpy(path, res, PKG_PATH_MAX);
+ return true;
+ }
+}
+
} // namespace installd
} // namespace android
diff --git a/cmds/installd/dexopt.h b/cmds/installd/dexopt.h
index d171ee5..1f41e67 100644
--- a/cmds/installd/dexopt.h
+++ b/cmds/installd/dexopt.h
@@ -17,6 +17,8 @@
#ifndef DEXOPT_H_
#define DEXOPT_H_
+#include "installd_constants.h"
+
#include <sys/types.h>
#include <cutils/multiuser.h>
@@ -63,7 +65,17 @@
int dexopt(const char *apk_path, uid_t uid, const char *pkgName, const char *instruction_set,
int dexopt_needed, const char* oat_dir, int dexopt_flags, const char* compiler_filter,
- const char* volume_uuid, const char* shared_libraries, const char* se_info);
+ const char* volume_uuid, const char* class_loader_context, const char* se_info,
+ bool downgrade);
+
+bool calculate_oat_file_path_default(char path[PKG_PATH_MAX], const char *oat_dir,
+ const char *apk_path, const char *instruction_set);
+
+bool calculate_odex_file_path_default(char path[PKG_PATH_MAX], const char *apk_path,
+ const char *instruction_set);
+
+bool create_cache_path_default(char path[PKG_PATH_MAX], const char *src,
+ const char *instruction_set);
} // namespace installd
} // namespace android
diff --git a/cmds/installd/globals.cpp b/cmds/installd/globals.cpp
index edcdb6a..b3a6daf 100644
--- a/cmds/installd/globals.cpp
+++ b/cmds/installd/globals.cpp
@@ -16,15 +16,15 @@
#define LOG_TAG "installd"
-#include <stdlib.h>
-#include <string.h>
-
-#include <log/log.h> // TODO: Move everything to base::logging.
-
#include <globals.h>
#include <installd_constants.h>
#include <utils.h>
+#include <android-base/logging.h>
+
+#include <stdlib.h>
+#include <string.h>
+
namespace android {
namespace installd {
@@ -44,106 +44,78 @@
static constexpr const char* PRIVATE_APP_SUBDIR = "app-private/"; // sub-directory under
// ANDROID_DATA
-/* Directory records that are used in execution of commands. */
-dir_rec_t android_app_dir;
-dir_rec_t android_app_ephemeral_dir;
-dir_rec_t android_app_lib_dir;
-dir_rec_t android_app_private_dir;
-dir_rec_t android_asec_dir;
-dir_rec_t android_data_dir;
-dir_rec_t android_media_dir;
-dir_rec_t android_mnt_expand_dir;
-dir_rec_t android_profiles_dir;
+std::string android_app_dir;
+std::string android_app_ephemeral_dir;
+std::string android_app_lib_dir;
+std::string android_app_private_dir;
+std::string android_asec_dir;
+std::string android_data_dir;
+std::string android_media_dir;
+std::string android_mnt_expand_dir;
+std::string android_profiles_dir;
+std::string android_root_dir;
-dir_rec_array_t android_system_dirs;
+std::vector<std::string> android_system_dirs;
-/**
- * Initialize all the global variables that are used elsewhere. Returns 0 upon
- * success and -1 on error.
- */
-void free_globals() {
- size_t i;
-
- for (i = 0; i < android_system_dirs.count; i++) {
- if (android_system_dirs.dirs[i].path != NULL) {
- free(android_system_dirs.dirs[i].path);
- }
+bool init_globals_from_data_and_root() {
+ const char* data_path = getenv("ANDROID_DATA");
+ if (data_path == nullptr) {
+ LOG(ERROR) << "Could not find ANDROID_DATA";
+ return false;
}
+ const char* root_path = getenv("ANDROID_ROOT");
+ if (root_path == nullptr) {
+ LOG(ERROR) << "Could not find ANDROID_ROOT";
+ return false;
+ }
+ return init_globals_from_data_and_root(data_path, root_path);
+}
- free(android_system_dirs.dirs);
+static std::string ensure_trailing_slash(const std::string& path) {
+ if (path.rfind('/') != path.size() - 1) {
+ return path + '/';
+ } else {
+ return path;
+ }
}
bool init_globals_from_data_and_root(const char* data, const char* root) {
// Get the android data directory.
- if (get_path_from_string(&android_data_dir, data) < 0) {
- return false;
- }
+ android_data_dir = ensure_trailing_slash(data);
+
+ // Get the android root directory.
+ android_root_dir = ensure_trailing_slash(root);
// Get the android app directory.
- if (copy_and_append(&android_app_dir, &android_data_dir, APP_SUBDIR) < 0) {
- return false;
- }
+ android_app_dir = android_data_dir + APP_SUBDIR;
// Get the android protected app directory.
- if (copy_and_append(&android_app_private_dir, &android_data_dir, PRIVATE_APP_SUBDIR) < 0) {
- return false;
- }
+ android_app_private_dir = android_data_dir + PRIVATE_APP_SUBDIR;
// Get the android ephemeral app directory.
- if (copy_and_append(&android_app_ephemeral_dir, &android_data_dir, EPHEMERAL_APP_SUBDIR) < 0) {
- return false;
- }
+ android_app_ephemeral_dir = android_data_dir + EPHEMERAL_APP_SUBDIR;
// Get the android app native library directory.
- if (copy_and_append(&android_app_lib_dir, &android_data_dir, APP_LIB_SUBDIR) < 0) {
- return false;
- }
+ android_app_lib_dir = android_data_dir + APP_LIB_SUBDIR;
// Get the sd-card ASEC mount point.
- if (get_path_from_env(&android_asec_dir, ASEC_MOUNTPOINT_ENV_NAME) < 0) {
- return false;
- }
+ android_asec_dir = ensure_trailing_slash(getenv(ASEC_MOUNTPOINT_ENV_NAME));
// Get the android media directory.
- if (copy_and_append(&android_media_dir, &android_data_dir, MEDIA_SUBDIR) < 0) {
- return false;
- }
+ android_media_dir = android_data_dir + MEDIA_SUBDIR;
// Get the android external app directory.
- if (get_path_from_string(&android_mnt_expand_dir, "/mnt/expand/") < 0) {
- return false;
- }
+ android_mnt_expand_dir = "/mnt/expand/";
// Get the android profiles directory.
- if (copy_and_append(&android_profiles_dir, &android_data_dir, PROFILES_SUBDIR) < 0) {
- return false;
- }
+ android_profiles_dir = android_data_dir + PROFILES_SUBDIR;
// Take note of the system and vendor directories.
- android_system_dirs.count = 4;
-
- android_system_dirs.dirs = (dir_rec_t*) calloc(android_system_dirs.count, sizeof(dir_rec_t));
- if (android_system_dirs.dirs == NULL) {
- ALOGE("Couldn't allocate array for dirs; aborting\n");
- return false;
- }
-
- dir_rec_t android_root_dir;
- if (get_path_from_string(&android_root_dir, root) < 0) {
- return false;
- }
-
- android_system_dirs.dirs[0].path = build_string2(android_root_dir.path, APP_SUBDIR);
- android_system_dirs.dirs[0].len = strlen(android_system_dirs.dirs[0].path);
-
- android_system_dirs.dirs[1].path = build_string2(android_root_dir.path, PRIV_APP_SUBDIR);
- android_system_dirs.dirs[1].len = strlen(android_system_dirs.dirs[1].path);
-
- android_system_dirs.dirs[2].path = strdup("/vendor/app/");
- android_system_dirs.dirs[2].len = strlen(android_system_dirs.dirs[2].path);
-
- android_system_dirs.dirs[3].path = strdup("/oem/app/");
- android_system_dirs.dirs[3].len = strlen(android_system_dirs.dirs[3].path);
+ android_system_dirs.clear();
+ android_system_dirs.push_back(android_root_dir + APP_SUBDIR);
+ android_system_dirs.push_back(android_root_dir + PRIV_APP_SUBDIR);
+ android_system_dirs.push_back("/vendor/app/");
+ android_system_dirs.push_back("/oem/app/");
return true;
}
diff --git a/cmds/installd/globals.h b/cmds/installd/globals.h
index c90beec..633e33b 100644
--- a/cmds/installd/globals.h
+++ b/cmds/installd/globals.h
@@ -19,40 +19,29 @@
#define GLOBALS_H_
#include <inttypes.h>
+#include <string>
+#include <vector>
namespace android {
namespace installd {
-/* constants */
-
// Name of the environment variable that contains the asec mountpoint.
static constexpr const char* ASEC_MOUNTPOINT_ENV_NAME = "ASEC_MOUNTPOINT";
-/* data structures */
+extern std::string android_app_dir;
+extern std::string android_app_ephemeral_dir;
+extern std::string android_app_lib_dir;
+extern std::string android_app_private_dir;
+extern std::string android_asec_dir;
+extern std::string android_data_dir;
+extern std::string android_media_dir;
+extern std::string android_mnt_expand_dir;
+extern std::string android_profiles_dir;
+extern std::string android_root_dir;
-struct dir_rec_t {
- char* path;
- size_t len;
-};
+extern std::vector<std::string> android_system_dirs;
-struct dir_rec_array_t {
- size_t count;
- dir_rec_t* dirs;
-};
-
-extern dir_rec_t android_app_dir;
-extern dir_rec_t android_app_ephemeral_dir;
-extern dir_rec_t android_app_lib_dir;
-extern dir_rec_t android_app_private_dir;
-extern dir_rec_t android_asec_dir;
-extern dir_rec_t android_data_dir;
-extern dir_rec_t android_media_dir;
-extern dir_rec_t android_mnt_expand_dir;
-extern dir_rec_t android_profiles_dir;
-
-extern dir_rec_array_t android_system_dirs;
-
-void free_globals();
+bool init_globals_from_data_and_root();
bool init_globals_from_data_and_root(const char* data, const char* root);
} // namespace installd
diff --git a/cmds/installd/installd.cpp b/cmds/installd/installd.cpp
index 35936a2..95ed2ff 100644
--- a/cmds/installd/installd.cpp
+++ b/cmds/installd/installd.cpp
@@ -30,6 +30,7 @@
#include <private/android_filesystem_config.h>
#include "InstalldNativeService.h"
+#include "dexopt.h"
#include "globals.h"
#include "installd_constants.h"
#include "installd_deps.h" // Need to fill in requirements of commands.
@@ -50,133 +51,22 @@
return property_get(key, value, default_value);
}
-// Compute the output path of
-bool calculate_oat_file_path(char path[PKG_PATH_MAX],
- const char *oat_dir,
- const char *apk_path,
- const char *instruction_set) {
- const char *file_name_start;
- const char *file_name_end;
-
- file_name_start = strrchr(apk_path, '/');
- if (file_name_start == NULL) {
- SLOGE("apk_path '%s' has no '/'s in it\n", apk_path);
- return false;
- }
- file_name_end = strrchr(apk_path, '.');
- if (file_name_end < file_name_start) {
- SLOGE("apk_path '%s' has no extension\n", apk_path);
- return false;
- }
-
- // Calculate file_name
- int file_name_len = file_name_end - file_name_start - 1;
- char file_name[file_name_len + 1];
- memcpy(file_name, file_name_start + 1, file_name_len);
- file_name[file_name_len] = '\0';
-
- // <apk_parent_dir>/oat/<isa>/<file_name>.odex
- snprintf(path, PKG_PATH_MAX, "%s/%s/%s.odex", oat_dir, instruction_set, file_name);
- return true;
+bool calculate_oat_file_path(char path[PKG_PATH_MAX], const char *oat_dir, const char *apk_path,
+ const char *instruction_set) {
+ return calculate_oat_file_path_default(path, oat_dir, apk_path, instruction_set);
}
-/*
- * Computes the odex file for the given apk_path and instruction_set.
- * /system/framework/whatever.jar -> /system/framework/oat/<isa>/whatever.odex
- *
- * Returns false if it failed to determine the odex file path.
- */
-bool calculate_odex_file_path(char path[PKG_PATH_MAX],
- const char *apk_path,
- const char *instruction_set) {
- if (strlen(apk_path) + strlen("oat/") + strlen(instruction_set)
- + strlen("/") + strlen("odex") + 1 > PKG_PATH_MAX) {
- SLOGE("apk_path '%s' may be too long to form odex file path.\n", apk_path);
- return false;
- }
-
- strcpy(path, apk_path);
- char *end = strrchr(path, '/');
- if (end == NULL) {
- SLOGE("apk_path '%s' has no '/'s in it?!\n", apk_path);
- return false;
- }
- const char *apk_end = apk_path + (end - path); // strrchr(apk_path, '/');
-
- strcpy(end + 1, "oat/"); // path = /system/framework/oat/\0
- strcat(path, instruction_set); // path = /system/framework/oat/<isa>\0
- strcat(path, apk_end); // path = /system/framework/oat/<isa>/whatever.jar\0
- end = strrchr(path, '.');
- if (end == NULL) {
- SLOGE("apk_path '%s' has no extension.\n", apk_path);
- return false;
- }
- strcpy(end + 1, "odex");
- return true;
+bool calculate_odex_file_path(char path[PKG_PATH_MAX], const char *apk_path,
+ const char *instruction_set) {
+ return calculate_odex_file_path_default(path, apk_path, instruction_set);
}
-bool create_cache_path(char path[PKG_PATH_MAX],
- const char *src,
- const char *instruction_set) {
- /* demand that we are an absolute path */
- if ((src == nullptr) || (src[0] != '/') || strstr(src,"..")) {
- return false;
- }
-
- size_t srclen = strlen(src);
-
- if (srclen > PKG_PATH_MAX) { // XXX: PKG_NAME_MAX?
- return false;
- }
-
- size_t dstlen =
- android_data_dir.len +
- strlen(DALVIK_CACHE) +
- 1 +
- strlen(instruction_set) +
- srclen +
- strlen(DALVIK_CACHE_POSTFIX) + 2;
-
- if (dstlen > PKG_PATH_MAX) {
- return false;
- }
-
- sprintf(path,"%s%s/%s/%s",
- android_data_dir.path,
- DALVIK_CACHE,
- instruction_set,
- src + 1 /* skip the leading / */);
-
- char* tmp =
- path +
- android_data_dir.len +
- strlen(DALVIK_CACHE) +
- 1 +
- strlen(instruction_set) + 1;
-
- for(; *tmp; tmp++) {
- if (*tmp == '/') {
- *tmp = '@';
- }
- }
-
- strcat(path, DALVIK_CACHE_POSTFIX);
- return true;
+bool create_cache_path(char path[PKG_PATH_MAX], const char *src, const char *instruction_set) {
+ return create_cache_path_default(path, src, instruction_set);
}
static bool initialize_globals() {
- const char* data_path = getenv("ANDROID_DATA");
- if (data_path == nullptr) {
- SLOGE("Could not find ANDROID_DATA");
- return false;
- }
- const char* root_path = getenv("ANDROID_ROOT");
- if (root_path == nullptr) {
- SLOGE("Could not find ANDROID_ROOT");
- return false;
- }
-
- return init_globals_from_data_and_root(data_path, root_path);
+ return init_globals_from_data_and_root();
}
static int initialize_directories() {
@@ -184,7 +74,7 @@
// Read current filesystem layout version to handle upgrade paths
char version_path[PATH_MAX];
- snprintf(version_path, PATH_MAX, "%s.layout_version", android_data_dir.path);
+ snprintf(version_path, PATH_MAX, "%s.layout_version", android_data_dir.c_str());
int oldVersion;
if (fs_read_atomic_int(version_path, &oldVersion) == -1) {
@@ -206,7 +96,7 @@
SLOGD("Upgrading to /data/misc/user directories");
char misc_dir[PATH_MAX];
- snprintf(misc_dir, PATH_MAX, "%smisc", android_data_dir.path);
+ snprintf(misc_dir, PATH_MAX, "%smisc", android_data_dir.c_str());
char keychain_added_dir[PATH_MAX];
snprintf(keychain_added_dir, PATH_MAX, "%s/keychain/cacerts-added", misc_dir);
@@ -227,7 +117,7 @@
if ((name[1] == '.') && (name[2] == 0)) continue;
}
- uint32_t user_id = atoi(name);
+ uint32_t user_id = std::stoi(name);
// /data/misc/user/<user_id>
if (ensure_config_user_dirs(user_id) == -1) {
@@ -281,7 +171,7 @@
return res;
}
-static int log_callback(int type, const char *fmt, ...) {
+static int log_callback(int type, const char *fmt, ...) { // NOLINT
va_list ap;
int priority;
diff --git a/cmds/installd/installd_constants.h b/cmds/installd/installd_constants.h
index 6a81cfc..b49057d 100644
--- a/cmds/installd/installd_constants.h
+++ b/cmds/installd/installd_constants.h
@@ -31,7 +31,7 @@
constexpr const char* DALVIK_CACHE_POSTFIX = "@classes.dex";
constexpr size_t PKG_NAME_MAX = 128u; /* largest allowed package name */
-constexpr size_t PKG_PATH_MAX = 256u; /* max size of any path we use */
+constexpr size_t PKG_PATH_MAX = 1024u; /* max size of any path we use */
/****************************************************************************
* IMPORTANT: These values are passed from Java code. Keep them in sync with
@@ -49,6 +49,9 @@
constexpr int DEXOPT_FORCE = 1 << 6;
constexpr int DEXOPT_STORAGE_CE = 1 << 7;
constexpr int DEXOPT_STORAGE_DE = 1 << 8;
+// Tells the compiler that it is invoked from the background service. This
+// controls whether extra debugging flags can be used (taking more compile time.)
+constexpr int DEXOPT_IDLE_BACKGROUND_JOB = 1 << 9;
/* all known values for dexopt flags */
constexpr int DEXOPT_MASK =
diff --git a/cmds/installd/otapreopt.cpp b/cmds/installd/otapreopt.cpp
index 68cb0d7..e0d23da 100644
--- a/cmds/installd/otapreopt.cpp
+++ b/cmds/installd/otapreopt.cpp
@@ -146,14 +146,13 @@
return 0;
}
// Copy in the default value.
- strncpy(value, default_value, kPropertyValueMax - 1);
+ strlcpy(value, default_value, kPropertyValueMax - 1);
value[kPropertyValueMax - 1] = 0;
return strlen(default_value);// TODO: Need to truncate?
}
- size_t size = std::min(kPropertyValueMax - 1, prop_value->length());
- strncpy(value, prop_value->data(), size);
- value[size] = 0;
- return static_cast<int>(size);
+ size_t size = std::min(kPropertyValueMax - 1, prop_value->length()) + 1;
+ strlcpy(value, prop_value->data(), size);
+ return static_cast<int>(size - 1);
}
std::string GetOTADataDirectory() const {
@@ -178,6 +177,7 @@
const char* volume_uuid;
const char* shared_libraries;
const char* se_info;
+ bool downgrade;
};
bool ReadSystemProperties() {
@@ -281,6 +281,13 @@
return true;
}
+ bool ParseBool(const char* in) {
+ if (strcmp(in, "true") == 0) {
+ return true;
+ }
+ return false;
+ }
+
bool ParseUInt(const char* in, uint32_t* out) {
char* end;
long long int result = strtoll(in, &end, 0);
@@ -349,6 +356,8 @@
switch (version) {
case 2:
return ReadArgumentsV2(argc, argv, true);
+ case 3:
+ return ReadArgumentsV3(argc, argv);
default:
LOG(ERROR) << "Unsupported version " << version;
@@ -427,6 +436,10 @@
}
}
+ // Set downgrade to false. It is only relevant when downgrading compiler
+ // filter, which is not the case during ota.
+ package_parameters_.downgrade = false;
+
if (param_index != 11) {
LOG(ERROR) << "Not enough parameters";
return false;
@@ -435,6 +448,89 @@
return true;
}
+ bool ReadArgumentsV3(int argc ATTRIBUTE_UNUSED, char** argv) {
+ size_t dexopt_index = 3;
+
+ // Check for "dexopt".
+ if (argv[dexopt_index] == nullptr) {
+ LOG(ERROR) << "Missing parameters";
+ return false;
+ }
+ if (std::string("dexopt").compare(argv[dexopt_index]) != 0) {
+ LOG(ERROR) << "Expected \"dexopt\"";
+ return false;
+ }
+
+ size_t param_index = 0;
+ for (;; ++param_index) {
+ const char* param = argv[dexopt_index + 1 + param_index];
+ if (param == nullptr) {
+ break;
+ }
+
+ switch (param_index) {
+ case 0:
+ package_parameters_.apk_path = param;
+ break;
+
+ case 1:
+ package_parameters_.uid = atoi(param);
+ break;
+
+ case 2:
+ package_parameters_.pkgName = param;
+ break;
+
+ case 3:
+ package_parameters_.instruction_set = param;
+ break;
+
+ case 4:
+ package_parameters_.dexopt_needed = atoi(param);
+ break;
+
+ case 5:
+ package_parameters_.oat_dir = param;
+ break;
+
+ case 6:
+ package_parameters_.dexopt_flags = atoi(param);
+ break;
+
+ case 7:
+ package_parameters_.compiler_filter = param;
+ break;
+
+ case 8:
+ package_parameters_.volume_uuid = ParseNull(param);
+ break;
+
+ case 9:
+ package_parameters_.shared_libraries = ParseNull(param);
+ break;
+
+ case 10:
+ package_parameters_.se_info = ParseNull(param);
+ break;
+
+ case 11:
+ package_parameters_.downgrade = ParseBool(param);
+ break;
+
+ default:
+ LOG(ERROR) << "Too many arguments, got " << param;
+ return false;
+ }
+ }
+
+ if (param_index != 12) {
+ LOG(ERROR) << "Not enough parameters";
+ return false;
+ }
+
+ return true;
+ }
+
static int ReplaceMask(int input, int old_mask, int new_mask) {
return (input & old_mask) != 0 ? new_mask : 0;
}
@@ -534,6 +630,10 @@
// receive from a v1 A side.
package_parameters_.se_info = nullptr;
+ // Set downgrade to false. It is only relevant when downgrading compiler
+ // filter, which is not the case during ota.
+ package_parameters_.downgrade = false;
+
return true;
}
@@ -753,10 +853,6 @@
}
static const char* ParseNull(const char* arg) {
- // b/38186355. Revert soon.
- if (strcmp(arg, "!null") == 0) {
- return nullptr;
- }
return (strcmp(arg, "!") == 0) ? nullptr : arg;
}
@@ -823,7 +919,8 @@
package_parameters_.compiler_filter,
package_parameters_.volume_uuid,
package_parameters_.shared_libraries,
- package_parameters_.se_info);
+ package_parameters_.se_info,
+ package_parameters_.downgrade);
}
int RunPreopt() {
diff --git a/cmds/installd/tests/Android.bp b/cmds/installd/tests/Android.bp
index 630c1f3..89c11aa 100644
--- a/cmds/installd/tests/Android.bp
+++ b/cmds/installd/tests/Android.bp
@@ -3,15 +3,16 @@
name: "installd_utils_test",
clang: true,
srcs: ["installd_utils_test.cpp"],
+ cflags: ["-Wall", "-Werror"],
shared_libs: [
"libbase",
- "liblog",
"libutils",
"libcutils",
],
static_libs: [
- "libinstalld",
"libdiskusage",
+ "libinstalld",
+ "liblog",
],
}
@@ -19,18 +20,19 @@
name: "installd_cache_test",
clang: true,
srcs: ["installd_cache_test.cpp"],
+ cflags: ["-Wall", "-Werror"],
shared_libs: [
"libbase",
"libbinder",
"libcutils",
- "liblog",
- "liblogwrap",
"libselinux",
"libutils",
],
static_libs: [
- "libinstalld",
"libdiskusage",
+ "libinstalld",
+ "liblog",
+ "liblogwrap",
],
}
@@ -38,17 +40,18 @@
name: "installd_service_test",
clang: true,
srcs: ["installd_service_test.cpp"],
+ cflags: ["-Wall", "-Werror"],
shared_libs: [
"libbase",
"libbinder",
"libcutils",
- "liblog",
- "liblogwrap",
"libselinux",
"libutils",
],
static_libs: [
- "libinstalld",
"libdiskusage",
+ "libinstalld",
+ "liblog",
+ "liblogwrap",
],
}
diff --git a/cmds/installd/tests/installd_cache_test.cpp b/cmds/installd/tests/installd_cache_test.cpp
index 174ce77..2d58515 100644
--- a/cmds/installd/tests/installd_cache_test.cpp
+++ b/cmds/installd/tests/installd_cache_test.cpp
@@ -99,7 +99,7 @@
static int64_t free() {
struct statvfs buf;
if (!statvfs("/data/local/tmp", &buf)) {
- return buf.f_bavail * buf.f_frsize;
+ return static_cast<int64_t>(buf.f_bavail) * buf.f_frsize;
} else {
PLOG(ERROR) << "Failed to statvfs";
return -1;
@@ -146,7 +146,7 @@
EXPECT_EQ(0, exists("com.example/cache/foo/one"));
EXPECT_EQ(0, exists("com.example/cache/foo/two"));
- service->freeCache(testUuid, kTbInBytes,
+ service->freeCache(testUuid, kTbInBytes, 0,
FLAG_FREE_CACHE_V2 | FLAG_FREE_CACHE_V2_DEFY_QUOTA);
EXPECT_EQ(0, exists("com.example/normal"));
@@ -163,13 +163,13 @@
touch("com.example/cache/foo/one", kMbInBytes, 60);
touch("com.example/cache/foo/two", kMbInBytes, 120);
- service->freeCache(testUuid, free() + kKbInBytes,
+ service->freeCache(testUuid, free() + kKbInBytes, 0,
FLAG_FREE_CACHE_V2 | FLAG_FREE_CACHE_V2_DEFY_QUOTA);
EXPECT_EQ(-1, exists("com.example/cache/foo/one"));
EXPECT_EQ(0, exists("com.example/cache/foo/two"));
- service->freeCache(testUuid, free() + kKbInBytes,
+ service->freeCache(testUuid, free() + kKbInBytes, 0,
FLAG_FREE_CACHE_V2 | FLAG_FREE_CACHE_V2_DEFY_QUOTA);
EXPECT_EQ(-1, exists("com.example/cache/foo/one"));
@@ -197,7 +197,7 @@
EXPECT_EQ(2 * kMbInBytes, size("com.example/cache/bar/bar1"));
EXPECT_EQ(2 * kMbInBytes, size("com.example/cache/bar/bar2"));
- service->freeCache(testUuid, kTbInBytes,
+ service->freeCache(testUuid, kTbInBytes, 0,
FLAG_FREE_CACHE_V2 | FLAG_FREE_CACHE_V2_DEFY_QUOTA);
EXPECT_EQ(-1, exists("com.example/cache/foo/foo1"));
@@ -219,7 +219,7 @@
setxattr("com.example/cache/foo", "user.cache_group");
- service->freeCache(testUuid, free() + kKbInBytes,
+ service->freeCache(testUuid, free() + kKbInBytes, 0,
FLAG_FREE_CACHE_V2 | FLAG_FREE_CACHE_V2_DEFY_QUOTA);
EXPECT_EQ(-1, exists("com.example/cache/foo/foo1"));
@@ -264,7 +264,7 @@
setxattr("com.example/cache/tomb", "user.cache_tombstone");
setxattr("com.example/cache/tomb/group", "user.cache_group");
- service->freeCache(testUuid, free() + kKbInBytes,
+ service->freeCache(testUuid, free() + kKbInBytes, 0,
FLAG_FREE_CACHE_V2 | FLAG_FREE_CACHE_V2_DEFY_QUOTA);
EXPECT_EQ(kMbInBytes, size("com.example/cache/group/file1"));
@@ -285,7 +285,7 @@
EXPECT_EQ(0, size("com.example/cache/tomb/group/dir/file1"));
EXPECT_EQ(0, size("com.example/cache/tomb/group/dir/file2"));
- service->freeCache(testUuid, free() + kKbInBytes,
+ service->freeCache(testUuid, free() + kKbInBytes, 0,
FLAG_FREE_CACHE_V2 | FLAG_FREE_CACHE_V2_DEFY_QUOTA);
EXPECT_EQ(-1, size("com.example/cache/group/file1"));
@@ -306,7 +306,7 @@
EXPECT_EQ(0, size("com.example/cache/tomb/group/dir/file1"));
EXPECT_EQ(0, size("com.example/cache/tomb/group/dir/file2"));
- service->freeCache(testUuid, kTbInBytes,
+ service->freeCache(testUuid, kTbInBytes, 0,
FLAG_FREE_CACHE_V2 | FLAG_FREE_CACHE_V2_DEFY_QUOTA);
EXPECT_EQ(-1, size("com.example/cache/group/file1"));
diff --git a/cmds/installd/tests/installd_service_test.cpp b/cmds/installd/tests/installd_service_test.cpp
index 34818f6..ca812bd 100644
--- a/cmds/installd/tests/installd_service_test.cpp
+++ b/cmds/installd/tests/installd_service_test.cpp
@@ -25,6 +25,7 @@
#include <gtest/gtest.h>
#include "InstalldNativeService.h"
+#include "dexopt.h"
#include "globals.h"
#include "utils.h"
@@ -41,25 +42,18 @@
return property_get(key, value, default_value);
}
-bool calculate_oat_file_path(char path[PKG_PATH_MAX] ATTRIBUTE_UNUSED,
- const char *oat_dir ATTRIBUTE_UNUSED,
- const char *apk_path ATTRIBUTE_UNUSED,
- const char *instruction_set ATTRIBUTE_UNUSED) {
- return false;
-}
-
-bool calculate_odex_file_path(char path[PKG_PATH_MAX] ATTRIBUTE_UNUSED,
- const char *apk_path ATTRIBUTE_UNUSED,
- const char *instruction_set ATTRIBUTE_UNUSED) {
- return false;
-}
-
-bool create_cache_path(char path[PKG_PATH_MAX],
- const char *src,
+bool calculate_oat_file_path(char path[PKG_PATH_MAX], const char *oat_dir, const char *apk_path,
const char *instruction_set) {
- // Not really a valid path but it's good enough for testing.
- sprintf(path,"/data/dalvik-cache/%s/%s", instruction_set, src);
- return true;
+ return calculate_oat_file_path_default(path, oat_dir, apk_path, instruction_set);
+}
+
+bool calculate_odex_file_path(char path[PKG_PATH_MAX], const char *apk_path,
+ const char *instruction_set) {
+ return calculate_odex_file_path_default(path, apk_path, instruction_set);
+}
+
+bool create_cache_path(char path[PKG_PATH_MAX], const char *src, const char *instruction_set) {
+ return create_cache_path_default(path, src, instruction_set);
}
static void mkdir(const char* path, uid_t owner, gid_t group, mode_t mode) {
@@ -102,6 +96,8 @@
testUuid = std::make_unique<std::string>();
*testUuid = std::string(kTestUuid);
system("mkdir -p /data/local/tmp/user/0");
+
+ init_globals_from_data_and_root();
}
virtual void TearDown() {
@@ -153,12 +149,28 @@
EXPECT_EQ(10000, stat_gid("com.example/bar/file"));
}
-TEST_F(ServiceTest, RmDexNoDalvikCache) {
- LOG(INFO) << "RmDexNoDalvikCache";
+TEST_F(ServiceTest, CalculateOat) {
+ char buf[PKG_PATH_MAX];
- // Try to remove a non existing dalvik cache dex. The call should be
- // successful because there's nothing to remove.
- EXPECT_TRUE(service->rmdex("com.example", "arm").isOk());
+ EXPECT_TRUE(calculate_oat_file_path(buf, "/path/to/oat", "/path/to/file.apk", "isa"));
+ EXPECT_EQ("/path/to/oat/isa/file.odex", std::string(buf));
+
+ EXPECT_FALSE(calculate_oat_file_path(buf, "/path/to/oat", "/path/to/file", "isa"));
+ EXPECT_FALSE(calculate_oat_file_path(buf, "/path/to/oat", "file", "isa"));
+}
+
+TEST_F(ServiceTest, CalculateOdex) {
+ char buf[PKG_PATH_MAX];
+
+ EXPECT_TRUE(calculate_odex_file_path(buf, "/path/to/file.apk", "isa"));
+ EXPECT_EQ("/path/to/oat/isa/file.odex", std::string(buf));
+}
+
+TEST_F(ServiceTest, CalculateCache) {
+ char buf[PKG_PATH_MAX];
+
+ EXPECT_TRUE(create_cache_path(buf, "/path/to/file.apk", "isa"));
+ EXPECT_EQ("/data/dalvik-cache/isa/path@to@file.apk@classes.dex", std::string(buf));
}
} // namespace installd
diff --git a/cmds/installd/tests/installd_utils_test.cpp b/cmds/installd/tests/installd_utils_test.cpp
index dab3236..2ca7ac2 100644
--- a/cmds/installd/tests/installd_utils_test.cpp
+++ b/cmds/installd/tests/installd_utils_test.cpp
@@ -17,6 +17,7 @@
#include <stdlib.h>
#include <string.h>
+#include <android-base/logging.h>
#include <gtest/gtest.h>
#include "InstalldNativeService.h"
@@ -27,6 +28,7 @@
#define LOG_TAG "utils_test"
#define TEST_DATA_DIR "/data/"
+#define TEST_ROOT_DIR "/system/"
#define TEST_APP_DIR "/data/app/"
#define TEST_APP_PRIVATE_DIR "/data/app-private/"
#define TEST_APP_EPHEMERAL_DIR "/data/app-ephemeral/"
@@ -38,55 +40,27 @@
#define TEST_PROFILE_DIR "/data/misc/profiles"
-#define REALLY_LONG_APP_NAME "com.example." \
- "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa." \
- "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa." \
- "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
-
-#define REALLY_LONG_LEAF_NAME "shared_prefs_shared_prefs_shared_prefs_shared_prefs_shared_prefs_" \
- "shared_prefs_shared_prefs_shared_prefs_shared_prefs_shared_prefs_shared_prefs_" \
- "shared_prefs_shared_prefs_shared_prefs_shared_prefs_shared_prefs_shared_prefs_" \
- "shared_prefs_shared_prefs_shared_prefs_shared_prefs_shared_prefs_shared_prefs_"
-
namespace android {
namespace installd {
class UtilsTest : public testing::Test {
protected:
virtual void SetUp() {
- android_app_dir.path = (char*) TEST_APP_DIR;
- android_app_dir.len = strlen(TEST_APP_DIR);
+ setenv("ANDROID_LOG_TAGS", "*:v", 1);
+ android::base::InitLogging(nullptr);
- android_app_private_dir.path = (char*) TEST_APP_PRIVATE_DIR;
- android_app_private_dir.len = strlen(TEST_APP_PRIVATE_DIR);
-
- android_app_ephemeral_dir.path = (char*) TEST_APP_EPHEMERAL_DIR;
- android_app_ephemeral_dir.len = strlen(TEST_APP_EPHEMERAL_DIR);
-
- android_data_dir.path = (char*) TEST_DATA_DIR;
- android_data_dir.len = strlen(TEST_DATA_DIR);
-
- android_asec_dir.path = (char*) TEST_ASEC_DIR;
- android_asec_dir.len = strlen(TEST_ASEC_DIR);
-
- android_mnt_expand_dir.path = (char*) TEST_EXPAND_DIR;
- android_mnt_expand_dir.len = strlen(TEST_EXPAND_DIR);
-
- android_system_dirs.count = 2;
-
- android_system_dirs.dirs = (dir_rec_t*) calloc(android_system_dirs.count, sizeof(dir_rec_t));
- android_system_dirs.dirs[0].path = (char*) TEST_SYSTEM_DIR1;
- android_system_dirs.dirs[0].len = strlen(TEST_SYSTEM_DIR1);
-
- android_system_dirs.dirs[1].path = (char*) TEST_SYSTEM_DIR2;
- android_system_dirs.dirs[1].len = strlen(TEST_SYSTEM_DIR2);
-
- android_profiles_dir.path = (char*) TEST_PROFILE_DIR;
- android_profiles_dir.len = strlen(TEST_PROFILE_DIR);
+ init_globals_from_data_and_root(TEST_DATA_DIR, TEST_ROOT_DIR);
}
virtual void TearDown() {
- free(android_system_dirs.dirs);
+ }
+
+ std::string create_too_long_path(const std::string& seed) {
+ std::string result = seed;
+ for (size_t i = seed.size(); i < PKG_PATH_MAX; i++) {
+ result += "a";
+ }
+ return result;
}
};
@@ -194,12 +168,6 @@
<< badasec1 << " should be rejected as a invalid path";
}
-TEST_F(UtilsTest, IsValidApkPath_DoubleSlashFail) {
- const char *badasec2 = TEST_ASEC_DIR "com.example.asec//pkg.apk";
- EXPECT_EQ(-1, validate_apk_path(badasec2))
- << badasec2 << " should be rejected as a invalid path";
-}
-
TEST_F(UtilsTest, IsValidApkPath_SubdirEscapeFail) {
const char *badasec3 = TEST_ASEC_DIR "com.example.asec/../../../pkg.apk";
EXPECT_EQ(-1, validate_apk_path(badasec3))
@@ -278,183 +246,6 @@
<< badapp2 << " should be rejected not a system path";
}
-TEST_F(UtilsTest, GetPathFromString_NullPathFail) {
- dir_rec_t test1;
- EXPECT_EQ(-1, get_path_from_string(&test1, (const char *) NULL))
- << "Should not allow NULL as a path.";
-}
-
-TEST_F(UtilsTest, GetPathFromString_EmptyPathFail) {
- dir_rec_t test1;
- EXPECT_EQ(-1, get_path_from_string(&test1, ""))
- << "Should not allow empty paths.";
-}
-
-TEST_F(UtilsTest, GetPathFromString_RelativePathFail) {
- dir_rec_t test1;
- EXPECT_EQ(-1, get_path_from_string(&test1, "mnt/asec"))
- << "Should not allow relative paths.";
-}
-
-TEST_F(UtilsTest, GetPathFromString_NonCanonical) {
- dir_rec_t test1;
-
- EXPECT_EQ(0, get_path_from_string(&test1, "/mnt/asec"))
- << "Should be able to canonicalize directory /mnt/asec";
- EXPECT_STREQ("/mnt/asec/", test1.path)
- << "/mnt/asec should be canonicalized to /mnt/asec/";
- EXPECT_EQ(10, (ssize_t) test1.len)
- << "path len should be equal to the length of /mnt/asec/ (10)";
- free(test1.path);
-}
-
-TEST_F(UtilsTest, GetPathFromString_CanonicalPath) {
- dir_rec_t test3;
- EXPECT_EQ(0, get_path_from_string(&test3, "/data/app/"))
- << "Should be able to canonicalize directory /data/app/";
- EXPECT_STREQ("/data/app/", test3.path)
- << "/data/app/ should be canonicalized to /data/app/";
- EXPECT_EQ(10, (ssize_t) test3.len)
- << "path len should be equal to the length of /data/app/ (10)";
- free(test3.path);
-}
-
-TEST_F(UtilsTest, CreatePkgPath_LongPkgNameSuccess) {
- char path[PKG_PATH_MAX];
-
- // Create long packagename of "aaaaa..."
- size_t pkgnameSize = PKG_NAME_MAX;
- char pkgname[pkgnameSize + 1];
- memset(pkgname, 'a', pkgnameSize);
- pkgname[1] = '.';
- pkgname[pkgnameSize] = '\0';
-
- EXPECT_EQ(0, create_pkg_path(path, pkgname, "", 0))
- << "Should successfully be able to create package name.";
-
- std::string prefix = std::string(TEST_DATA_DIR) + PRIMARY_USER_PREFIX;
- size_t offset = prefix.length();
-
- EXPECT_STREQ(pkgname, path + offset)
- << "Package path should be a really long string of a's";
-}
-
-TEST_F(UtilsTest, CreatePkgPath_LongPostfixFail) {
- char path[PKG_PATH_MAX];
-
- // Create long packagename of "aaaaa..."
- size_t postfixSize = PKG_PATH_MAX;
- char postfix[postfixSize + 1];
- memset(postfix, 'a', postfixSize);
- postfix[postfixSize] = '\0';
-
- EXPECT_EQ(-1, create_pkg_path(path, "com.example.package", postfix, 0))
- << "Should return error because postfix is too long.";
-}
-
-TEST_F(UtilsTest, CreatePkgPath_PrimaryUser) {
- char path[PKG_PATH_MAX];
-
- EXPECT_EQ(0, create_pkg_path(path, "com.example.package", "", 0))
- << "Should return error because postfix is too long.";
-
- std::string p = std::string(TEST_DATA_DIR)
- + PRIMARY_USER_PREFIX
- + "com.example.package";
- EXPECT_STREQ(p.c_str(), path)
- << "Package path should be in /data/data/";
-}
-
-TEST_F(UtilsTest, CreatePkgPath_SecondaryUser) {
- char path[PKG_PATH_MAX];
-
- EXPECT_EQ(0, create_pkg_path(path, "com.example.package", "", 1))
- << "Should successfully create package path.";
-
- std::string p = std::string(TEST_DATA_DIR)
- + SECONDARY_USER_PREFIX
- + "1/com.example.package";
- EXPECT_STREQ(p.c_str(), path)
- << "Package path should be in /data/user/";
-}
-
-TEST_F(UtilsTest, CreateMovePath_Primary) {
- char path[PKG_PATH_MAX];
-
- EXPECT_EQ(0, create_move_path(path, "com.android.test", "shared_prefs", 0))
- << "Should be able to create move path for primary user";
-
- EXPECT_STREQ("/data/data/com.android.test/shared_prefs", path)
- << "Primary user package directory should be created correctly";
-}
-
-TEST_F(UtilsTest, CreateMovePath_Fail_AppTooLong) {
- char path[PKG_PATH_MAX];
-
- EXPECT_EQ(-1, create_move_path(path, REALLY_LONG_APP_NAME, "shared_prefs", 0))
- << "Should fail to create move path for primary user";
-}
-
-TEST_F(UtilsTest, CreateMovePath_Fail_LeafTooLong) {
- char path[PKG_PATH_MAX];
-
- EXPECT_EQ(-1, create_move_path(path, "com.android.test", REALLY_LONG_LEAF_NAME, 0))
- << "Should fail to create move path for primary user";
-}
-
-TEST_F(UtilsTest, CopyAndAppend_Normal) {
- //int copy_and_append(dir_rec_t* dst, dir_rec_t* src, char* suffix)
- dir_rec_t dst;
- dir_rec_t src;
-
- src.path = (char*) "/data/";
- src.len = strlen(src.path);
-
- EXPECT_EQ(0, copy_and_append(&dst, &src, "app/"))
- << "Should return error because postfix is too long.";
-
- EXPECT_STREQ("/data/app/", dst.path)
- << "Appended path should be correct";
-
- EXPECT_EQ(10, (ssize_t) dst.len)
- << "Appended path should be length of '/data/app/' (10)";
-}
-
-TEST_F(UtilsTest, AppendAndIncrement_Normal) {
- size_t dst_size = 10;
- char dst[dst_size];
- char *dstp = dst;
- const char* src = "FOO";
-
- EXPECT_EQ(0, append_and_increment(&dstp, src, &dst_size))
- << "String should append successfully";
-
- EXPECT_STREQ("FOO", dst)
- << "String should append correctly";
-
- EXPECT_EQ(0, append_and_increment(&dstp, src, &dst_size))
- << "String should append successfully again";
-
- EXPECT_STREQ("FOOFOO", dst)
- << "String should append correctly again";
-}
-
-TEST_F(UtilsTest, AppendAndIncrement_TooBig) {
- size_t dst_size = 5;
- char dst[dst_size];
- char *dstp = dst;
- const char* src = "FOO";
-
- EXPECT_EQ(0, append_and_increment(&dstp, src, &dst_size))
- << "String should append successfully";
-
- EXPECT_STREQ("FOO", dst)
- << "String should append correctly";
-
- EXPECT_EQ(-1, append_and_increment(&dstp, src, &dst_size))
- << "String should fail because it's too large to fit";
-}
-
TEST_F(UtilsTest, CreateDataPath) {
EXPECT_EQ("/data", create_data_path(nullptr));
EXPECT_EQ("/mnt/expand/57f8f4bc-abf4-655f-bf67-946fc0f9f25b",
@@ -560,7 +351,7 @@
}
TEST_F(UtilsTest, CreateSecondaryCurrentProfile) {
- EXPECT_EQ("/data/user/0/com.example/secondary.dex.prof",
+ EXPECT_EQ("/data/user/0/com.example/oat/secondary.dex.cur.prof",
create_current_profile_path(/*user*/0,
"/data/user/0/com.example/secondary.dex", /*is_secondary*/true));
}
@@ -571,5 +362,112 @@
"/data/user/0/com.example/secondary.dex", /*is_secondary*/true));
}
+static void pass_secondary_dex_validation(const std::string& package_name,
+ const std::string& dex_path, int uid, int storage_flag) {
+ EXPECT_TRUE(validate_secondary_dex_path(package_name, dex_path, /*volume_uuid*/ nullptr, uid,
+ storage_flag))
+ << dex_path << " should be allowed as a valid secondary dex path";
+}
+
+static void fail_secondary_dex_validation(const std::string& package_name,
+ const std::string& dex_path, int uid, int storage_flag) {
+ EXPECT_FALSE(validate_secondary_dex_path(package_name, dex_path, /*volume_uuid*/ nullptr, uid,
+ storage_flag))
+ << dex_path << " should not be allowed as a valid secondary dex path";
+}
+
+TEST_F(UtilsTest, ValidateSecondaryDexFilesPath) {
+ std::string package_name = "com.test.app";
+ std::string app_dir_ce_user_0 = "/data/data/" + package_name;
+ std::string app_dir_ce_user_10 = "/data/user/10/" + package_name;
+
+ std::string app_dir_de_user_0 = "/data/user_de/0/" + package_name;
+ std::string app_dir_de_user_10 = "/data/user_de/10/" + package_name;
+
+ EXPECT_EQ(app_dir_ce_user_0,
+ create_data_user_ce_package_path(nullptr, 0, package_name.c_str()));
+ EXPECT_EQ(app_dir_ce_user_10,
+ create_data_user_ce_package_path(nullptr, 10, package_name.c_str()));
+
+ EXPECT_EQ(app_dir_de_user_0,
+ create_data_user_de_package_path(nullptr, 0, package_name.c_str()));
+ EXPECT_EQ(app_dir_de_user_10,
+ create_data_user_de_package_path(nullptr, 10, package_name.c_str()));
+
+ uid_t app_uid_for_user_0 = multiuser_get_uid(/*user_id*/0, /*app_id*/ 1234);
+ uid_t app_uid_for_user_10 = multiuser_get_uid(/*user_id*/10, /*app_id*/ 1234);
+
+ // Standard path for user 0 on CE storage.
+ pass_secondary_dex_validation(
+ package_name, app_dir_ce_user_0 + "/ce0.dex", app_uid_for_user_0, FLAG_STORAGE_CE);
+ // Standard path for user 10 on CE storage.
+ pass_secondary_dex_validation(
+ package_name, app_dir_ce_user_10 + "/ce10.dex", app_uid_for_user_10, FLAG_STORAGE_CE);
+
+ // Standard path for user 0 on DE storage.
+ pass_secondary_dex_validation(
+ package_name, app_dir_de_user_0 + "/de0.dex", app_uid_for_user_0, FLAG_STORAGE_DE);
+ // Standard path for user 10 on DE storage.
+ pass_secondary_dex_validation(
+ package_name, app_dir_de_user_10 + "/de0.dex", app_uid_for_user_10, FLAG_STORAGE_DE);
+
+ // Dex path for user 0 accessed from user 10.
+ fail_secondary_dex_validation(
+ package_name, app_dir_ce_user_0 + "/path0_from10.dex",
+ app_uid_for_user_10, FLAG_STORAGE_CE);
+
+ // Dex path for CE storage accessed with DE.
+ fail_secondary_dex_validation(
+ package_name, app_dir_ce_user_0 + "/ce_from_de.dex", app_uid_for_user_0, FLAG_STORAGE_DE);
+
+ // Dex path for DE storage accessed with CE.
+ fail_secondary_dex_validation(
+ package_name, app_dir_de_user_0 + "/de_from_ce.dex", app_uid_for_user_0, FLAG_STORAGE_CE);
+
+ // Location which does not start with '/'.
+ fail_secondary_dex_validation(
+ package_name, "without_slash.dex", app_uid_for_user_10, FLAG_STORAGE_DE);
+
+ // The dex file is not in the specified package directory.
+ fail_secondary_dex_validation(
+ "another.package", app_dir_ce_user_0 + "/for_another_package.dex",
+ app_uid_for_user_0, FLAG_STORAGE_DE);
+
+ // The dex path contains indirect directories.
+ fail_secondary_dex_validation(
+ package_name, app_dir_ce_user_0 + "/1/../foo.dex", app_uid_for_user_0, FLAG_STORAGE_CE);
+ fail_secondary_dex_validation(
+ package_name, app_dir_ce_user_0 + "/1/./foo.dex", app_uid_for_user_0, FLAG_STORAGE_CE);
+
+ // Super long path.
+ std::string too_long = create_too_long_path("too_long_");
+ fail_secondary_dex_validation(
+ package_name, app_dir_ce_user_10 + "/" + too_long, app_uid_for_user_10, FLAG_STORAGE_CE);
+}
+
+TEST_F(UtilsTest, ValidateApkPath) {
+ EXPECT_EQ(0, validate_apk_path("/data/app/com.example"));
+ EXPECT_EQ(0, validate_apk_path("/data/app/com.example/file"));
+ EXPECT_EQ(0, validate_apk_path("/data/app/com.example//file"));
+ EXPECT_NE(0, validate_apk_path("/data/app/com.example/dir/"));
+ EXPECT_NE(0, validate_apk_path("/data/app/com.example/dir/file"));
+ EXPECT_NE(0, validate_apk_path("/data/app/com.example/dir/dir/file"));
+ EXPECT_NE(0, validate_apk_path("/data/app/com.example/dir/dir//file"));
+ EXPECT_NE(0, validate_apk_path("/data/app/com.example/dir/dir/dir/file"));
+ EXPECT_NE(0, validate_apk_path("/data/app/com.example/dir/dir/dir//file"));
+}
+
+TEST_F(UtilsTest, ValidateApkPathSubdirs) {
+ EXPECT_EQ(0, validate_apk_path_subdirs("/data/app/com.example"));
+ EXPECT_EQ(0, validate_apk_path_subdirs("/data/app/com.example/file"));
+ EXPECT_EQ(0, validate_apk_path_subdirs("/data/app/com.example//file"));
+ EXPECT_EQ(0, validate_apk_path_subdirs("/data/app/com.example/dir/"));
+ EXPECT_EQ(0, validate_apk_path_subdirs("/data/app/com.example/dir/file"));
+ EXPECT_EQ(0, validate_apk_path_subdirs("/data/app/com.example/dir/dir/file"));
+ EXPECT_EQ(0, validate_apk_path_subdirs("/data/app/com.example/dir/dir//file"));
+ EXPECT_NE(0, validate_apk_path_subdirs("/data/app/com.example/dir/dir/dir/file"));
+ EXPECT_NE(0, validate_apk_path_subdirs("/data/app/com.example/dir/dir/dir//file"));
+}
+
} // namespace installd
} // namespace android
diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp
index 7c05417..ca0a82e 100644
--- a/cmds/installd/utils.cpp
+++ b/cmds/installd/utils.cpp
@@ -129,24 +129,6 @@
create_data_user_de_path(volume_uuid, user).c_str(), package_name);
}
-int create_pkg_path(char path[PKG_PATH_MAX], const char *pkgname,
- const char *postfix, userid_t userid) {
- if (!is_valid_package_name(pkgname)) {
- path[0] = '\0';
- return -1;
- }
-
- std::string _tmp(create_data_user_ce_package_path(nullptr, userid, pkgname) + postfix);
- const char* tmp = _tmp.c_str();
- if (strlen(tmp) >= PKG_PATH_MAX) {
- path[0] = '\0';
- return -1;
- } else {
- strcpy(path, tmp);
- return 0;
- }
-}
-
std::string create_data_path(const char* volume_uuid) {
if (volume_uuid == nullptr) {
return "/data";
@@ -213,7 +195,7 @@
}
std::string create_primary_cur_profile_dir_path(userid_t userid) {
- return StringPrintf("%s/cur/%u", android_profiles_dir.path, userid);
+ return StringPrintf("%s/cur/%u", android_profiles_dir.c_str(), userid);
}
std::string create_primary_current_profile_package_dir_path(userid_t user,
@@ -224,12 +206,12 @@
}
std::string create_primary_ref_profile_dir_path() {
- return StringPrintf("%s/ref", android_profiles_dir.path);
+ return StringPrintf("%s/ref", android_profiles_dir.c_str());
}
std::string create_primary_reference_profile_package_dir_path(const std::string& package_name) {
check_package_name(package_name.c_str());
- return StringPrintf("%s/ref/%s", android_profiles_dir.path, package_name.c_str());
+ return StringPrintf("%s/ref/%s", android_profiles_dir.c_str(), package_name.c_str());
}
std::string create_data_dalvik_cache_path() {
@@ -238,13 +220,38 @@
// Keep profile paths in sync with ActivityThread and LoadedApk.
const std::string PROFILE_EXT = ".prof";
+const std::string CURRENT_PROFILE_EXT = ".cur";
const std::string PRIMARY_PROFILE_NAME = "primary" + PROFILE_EXT;
+// 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
+// structure).
+static bool get_secondary_dex_location(const std::string& dex_path,
+ std::string* out_dir_name, std::string* out_file_name) {
+ size_t dirIndex = dex_path.rfind('/');
+ if (dirIndex == std::string::npos) {
+ return false;
+ }
+ if (dirIndex == dex_path.size() - 1) {
+ return false;
+ }
+ *out_dir_name = dex_path.substr(0, dirIndex);
+ *out_file_name = dex_path.substr(dirIndex + 1);
+
+ return true;
+}
+
std::string create_current_profile_path(userid_t user, const std::string& location,
bool is_secondary_dex) {
if (is_secondary_dex) {
- // Secondary dex profiles are stored next to the dex files using .prof extension.
- return StringPrintf("%s%s", location.c_str(), PROFILE_EXT.c_str());
+ // Secondary dex current profiles are stored next to the dex files under the oat folder.
+ std::string dex_dir;
+ std::string dex_name;
+ CHECK(get_secondary_dex_location(location, &dex_dir, &dex_name))
+ << "Unexpected dir structure for secondary dex " << location;
+ return StringPrintf("%s/oat/%s%s%s",
+ dex_dir.c_str(), dex_name.c_str(), CURRENT_PROFILE_EXT.c_str(),
+ PROFILE_EXT.c_str());
} else {
// Profiles for primary apks are under /data/misc/profiles/cur.
std::string profile_dir = create_primary_current_profile_package_dir_path(user, location);
@@ -255,12 +262,10 @@
std::string create_reference_profile_path(const std::string& location, bool is_secondary_dex) {
if (is_secondary_dex) {
// Secondary dex reference profiles are stored next to the dex files under the oat folder.
- size_t dirIndex = location.rfind('/');
- CHECK(dirIndex != std::string::npos)
+ std::string dex_dir;
+ std::string dex_name;
+ CHECK(get_secondary_dex_location(location, &dex_dir, &dex_name))
<< "Unexpected dir structure for secondary dex " << location;
-
- std::string dex_dir = location.substr(0, dirIndex);
- std::string dex_name = location.substr(dirIndex +1);
return StringPrintf("%s/oat/%s%s",
dex_dir.c_str(), dex_name.c_str(), PROFILE_EXT.c_str());
} else {
@@ -355,20 +360,6 @@
return 0;
}
-int create_move_path(char path[PKG_PATH_MAX],
- const char* pkgname,
- const char* leaf,
- userid_t userid ATTRIBUTE_UNUSED)
-{
- if ((android_data_dir.len + strlen(PRIMARY_USER_PREFIX) + strlen(pkgname) + strlen(leaf) + 1)
- >= PKG_PATH_MAX) {
- return -1;
- }
-
- sprintf(path, "%s%s%s/%s", android_data_dir.path, PRIMARY_USER_PREFIX, pkgname, leaf);
- return 0;
-}
-
/**
* Checks whether the package name is valid. Returns -1 on error and
* 0 on success.
@@ -633,7 +624,7 @@
int64_t data_disk_free(const std::string& data_path) {
struct statvfs sfs;
if (statvfs(data_path.c_str(), &sfs) == 0) {
- return sfs.f_bavail * sfs.f_frsize;
+ return static_cast<int64_t>(sfs.f_bavail) * sfs.f_frsize;
} else {
PLOG(ERROR) << "Couldn't statvfs " << data_path;
return -1;
@@ -733,27 +724,47 @@
}
}
+void remove_path_xattr(const std::string& path, const char* inode_xattr) {
+ if (removexattr(path.c_str(), inode_xattr) && errno != ENODATA) {
+ PLOG(ERROR) << "Failed to remove xattr " << inode_xattr << " at " << path;
+ }
+}
+
/**
* Validate that the path is valid in the context of the provided directory.
* The path is allowed to have at most one subdirectory and no indirections
* to top level directories (i.e. have "..").
*/
-static int validate_path(const dir_rec_t* dir, const char* path, int maxSubdirs) {
- size_t dir_len = dir->len;
- const char* subdir = strchr(path + dir_len, '/');
-
- // Only allow the path to have at most one subdirectory.
- if (subdir != NULL) {
- ++subdir;
- if ((--maxSubdirs == 0) && strchr(subdir, '/') != NULL) {
- ALOGE("invalid apk path '%s' (subdir?)\n", path);
- return -1;
- }
+static int validate_path(const std::string& dir, const std::string& path, int maxSubdirs) {
+ // Argument sanity checking
+ if (dir.find('/') != 0 || dir.rfind('/') != dir.size() - 1
+ || dir.find("..") != std::string::npos) {
+ LOG(ERROR) << "Invalid directory " << dir;
+ return -1;
+ }
+ if (path.find("..") != std::string::npos) {
+ LOG(ERROR) << "Invalid path " << path;
+ return -1;
}
- // Directories can't have a period directly after the directory markers to prevent "..".
- if ((path[dir_len] == '.') || ((subdir != NULL) && (*subdir == '.'))) {
- ALOGE("invalid apk path '%s' (trickery)\n", path);
+ if (path.compare(0, dir.size(), dir) != 0) {
+ // Common case, path isn't under directory
+ return -1;
+ }
+
+ // Count number of subdirectories
+ auto pos = path.find('/', dir.size());
+ int count = 0;
+ while (pos != std::string::npos) {
+ auto next = path.find('/', pos + 1);
+ if (next > pos + 1) {
+ count++;
+ }
+ pos = next;
+ }
+
+ if (count > maxSubdirs) {
+ LOG(ERROR) << "Invalid path depth " << path << " when tested against " << dir;
return -1;
}
@@ -765,122 +776,46 @@
* if it is a system app or -1 if it is not.
*/
int validate_system_app_path(const char* path) {
- size_t i;
-
- for (i = 0; i < android_system_dirs.count; i++) {
- const size_t dir_len = android_system_dirs.dirs[i].len;
- if (!strncmp(path, android_system_dirs.dirs[i].path, dir_len)) {
- return validate_path(android_system_dirs.dirs + i, path, 1);
+ std::string path_ = path;
+ for (const auto& dir : android_system_dirs) {
+ if (validate_path(dir, path, 1) == 0) {
+ return 0;
}
}
-
return -1;
}
bool validate_secondary_dex_path(const std::string& pkgname, const std::string& dex_path,
- const char* volume_uuid, int uid, int storage_flag) {
+ const char* volume_uuid, int uid, int storage_flag, bool validate_package_path) {
CHECK(storage_flag == FLAG_STORAGE_CE || storage_flag == FLAG_STORAGE_DE);
- std::string app_private_dir = storage_flag == FLAG_STORAGE_CE
- ? create_data_user_ce_package_path(
- volume_uuid, multiuser_get_user_id(uid), pkgname.c_str())
- : create_data_user_de_package_path(
- volume_uuid, multiuser_get_user_id(uid), pkgname.c_str());
- dir_rec_t dir;
- if (get_path_from_string(&dir, app_private_dir.c_str()) != 0) {
- LOG(WARNING) << "Could not get dir rec for " << app_private_dir;
- return false;
- }
- // Usually secondary dex files have a nested directory structure.
- // Pick at most 10 subdirectories when validating (arbitrary value).
- // If the secondary dex file is >10 directory nested then validation will
- // fail and the file will not be compiled.
- return validate_path(&dir, dex_path.c_str(), /*max_subdirs*/ 10) == 0;
-}
+ // Empty paths are not allowed.
+ if (dex_path.empty()) { return false; }
+ // First character should always be '/'. No relative paths.
+ if (dex_path[0] != '/') { return false; }
+ // The last character should not be '/'.
+ if (dex_path[dex_path.size() - 1] == '/') { return false; }
+ // There should be no '.' after the directory marker.
+ if (dex_path.find("/.") != std::string::npos) { return false; }
+ // The path should be at most PKG_PATH_MAX long.
+ if (dex_path.size() > PKG_PATH_MAX) { return false; }
-/**
- * Get the contents of a environment variable that contains a path. Caller
- * owns the string that is inserted into the directory record. Returns
- * 0 on success and -1 on error.
- */
-int get_path_from_env(dir_rec_t* rec, const char* var) {
- const char* path = getenv(var);
- int ret = get_path_from_string(rec, path);
- if (ret < 0) {
- ALOGW("Problem finding value for environment variable %s\n", var);
- }
- return ret;
-}
+ if (validate_package_path) {
+ // If we are asked to validate the package path check that
+ // the dex_path is under the app data directory.
+ std::string app_private_dir = storage_flag == FLAG_STORAGE_CE
+ ? create_data_user_ce_package_path(
+ volume_uuid, multiuser_get_user_id(uid), pkgname.c_str())
+ : create_data_user_de_package_path(
+ volume_uuid, multiuser_get_user_id(uid), pkgname.c_str());
-/**
- * Puts the string into the record as a directory. Appends '/' to the end
- * of all paths. Caller owns the string that is inserted into the directory
- * record. A null value will result in an error.
- *
- * Returns 0 on success and -1 on error.
- */
-int get_path_from_string(dir_rec_t* rec, const char* path) {
- if (path == NULL) {
- return -1;
- } else {
- const size_t path_len = strlen(path);
- if (path_len <= 0) {
- return -1;
- }
-
- // Make sure path is absolute.
- if (path[0] != '/') {
- return -1;
- }
-
- if (path[path_len - 1] == '/') {
- // Path ends with a forward slash. Make our own copy.
-
- rec->path = strdup(path);
- if (rec->path == NULL) {
- return -1;
- }
-
- rec->len = path_len;
- } else {
- // Path does not end with a slash. Generate a new string.
- char *dst;
-
- // Add space for slash and terminating null.
- size_t dst_size = path_len + 2;
-
- rec->path = (char*) malloc(dst_size);
- if (rec->path == NULL) {
- return -1;
- }
-
- dst = rec->path;
-
- if (append_and_increment(&dst, path, &dst_size) < 0
- || append_and_increment(&dst, "/", &dst_size)) {
- ALOGE("Error canonicalizing path");
- return -1;
- }
-
- rec->len = dst - rec->path;
+ if (strncmp(dex_path.c_str(), app_private_dir.c_str(), app_private_dir.size()) != 0) {
+ return false;
}
}
- return 0;
-}
-int copy_and_append(dir_rec_t* dst, const dir_rec_t* src, const char* suffix) {
- dst->len = src->len + strlen(suffix);
- const size_t dstSize = dst->len + 1;
- dst->path = (char*) malloc(dstSize);
-
- if (dst->path == NULL
- || snprintf(dst->path, dstSize, "%s%s", src->path, suffix)
- != (ssize_t) dst->len) {
- ALOGE("Could not allocate memory to hold appended path; aborting\n");
- return -1;
- }
-
- return 0;
+ // If we got here we have a valid path.
+ return true;
}
/**
@@ -890,25 +825,20 @@
* is encountered.
*/
static int validate_apk_path_internal(const char *path, int maxSubdirs) {
- const dir_rec_t* dir = NULL;
- if (!strncmp(path, android_app_dir.path, android_app_dir.len)) {
- dir = &android_app_dir;
- } else if (!strncmp(path, android_app_private_dir.path, android_app_private_dir.len)) {
- dir = &android_app_private_dir;
- } else if (!strncmp(path, android_app_ephemeral_dir.path, android_app_ephemeral_dir.len)) {
- dir = &android_app_ephemeral_dir;
- } else if (!strncmp(path, android_asec_dir.path, android_asec_dir.len)) {
- dir = &android_asec_dir;
- } else if (!strncmp(path, android_mnt_expand_dir.path, android_mnt_expand_dir.len)) {
- dir = &android_mnt_expand_dir;
- if (maxSubdirs < 2) {
- maxSubdirs = 2;
- }
+ std::string path_ = path;
+ if (validate_path(android_app_dir, path_, maxSubdirs) == 0) {
+ return 0;
+ } else if (validate_path(android_app_private_dir, path_, maxSubdirs) == 0) {
+ return 0;
+ } else if (validate_path(android_app_ephemeral_dir, path_, maxSubdirs) == 0) {
+ return 0;
+ } else if (validate_path(android_asec_dir, path_, maxSubdirs) == 0) {
+ return 0;
+ } else if (validate_path(android_mnt_expand_dir, path_, std::max(maxSubdirs, 2)) == 0) {
+ return 0;
} else {
return -1;
}
-
- return validate_path(dir, path, maxSubdirs);
}
int validate_apk_path(const char* path) {
@@ -919,48 +849,6 @@
return validate_apk_path_internal(path, 3 /* maxSubdirs */);
}
-int append_and_increment(char** dst, const char* src, size_t* dst_size) {
- ssize_t ret = strlcpy(*dst, src, *dst_size);
- if (ret < 0 || (size_t) ret >= *dst_size) {
- return -1;
- }
- *dst += ret;
- *dst_size -= ret;
- return 0;
-}
-
-char *build_string2(const char *s1, const char *s2) {
- if (s1 == NULL || s2 == NULL) return NULL;
-
- int len_s1 = strlen(s1);
- int len_s2 = strlen(s2);
- int len = len_s1 + len_s2 + 1;
- char *result = (char *) malloc(len);
- if (result == NULL) return NULL;
-
- strcpy(result, s1);
- strcpy(result + len_s1, s2);
-
- return result;
-}
-
-char *build_string3(const char *s1, const char *s2, const char *s3) {
- if (s1 == NULL || s2 == NULL || s3 == NULL) return NULL;
-
- int len_s1 = strlen(s1);
- int len_s2 = strlen(s2);
- int len_s3 = strlen(s3);
- int len = len_s1 + len_s2 + len_s3 + 1;
- char *result = (char *) malloc(len);
- if (result == NULL) return NULL;
-
- strcpy(result, s1);
- strcpy(result + len_s1, s2);
- strcpy(result + len_s1 + len_s2, s3);
-
- return result;
-}
-
int ensure_config_user_dirs(userid_t userid) {
// writable by system, readable by any app within the same user
const int uid = multiuser_get_uid(userid, AID_SYSTEM);
@@ -1033,7 +921,7 @@
} else {
// Mismatched GID/mode is recoverable; fall through to update
LOG(DEBUG) << "Mismatched cache GID/mode at " << path << ": found " << st.st_gid
- << " but expected " << gid;
+ << "/" << actual_mode << " but expected " << gid << "/" << target_mode;
}
// Directory is owned correctly, but GID or mode mismatch means it's
diff --git a/cmds/installd/utils.h b/cmds/installd/utils.h
index 070da84..3e04af9 100644
--- a/cmds/installd/utils.h
+++ b/cmds/installd/utils.h
@@ -36,21 +36,16 @@
#define BYPASS_QUOTA 0
#define BYPASS_SDCARDFS 0
+#define APPLY_HARD_QUOTAS 1
+
namespace android {
namespace installd {
-struct dir_rec_t;
-
constexpr const char* kXattrInodeCache = "user.inode_cache";
constexpr const char* kXattrInodeCodeCache = "user.inode_code_cache";
constexpr const char* kXattrCacheGroup = "user.cache_group";
constexpr const char* kXattrCacheTombstone = "user.cache_tombstone";
-int create_pkg_path(char path[PKG_PATH_MAX],
- const char *pkgname,
- const char *postfix,
- userid_t userid);
-
std::string create_data_path(const char* volume_uuid);
std::string create_data_app_path(const char* volume_uuid);
@@ -94,11 +89,6 @@
int create_user_config_path(char path[PKG_PATH_MAX], userid_t userid);
-int create_move_path(char path[PKG_PATH_MAX],
- const char* pkgname,
- const char* leaf,
- userid_t userid);
-
bool is_valid_filename(const std::string& name);
bool is_valid_package_name(const std::string& packageName);
@@ -120,25 +110,15 @@
int write_path_inode(const std::string& parent, const char* name, const char* inode_xattr);
std::string read_path_inode(const std::string& parent, const char* name, const char* inode_xattr);
+void remove_path_xattr(const std::string& path, const char* inode_xattr);
int validate_system_app_path(const char* path);
bool validate_secondary_dex_path(const std::string& pkgname, const std::string& dex_path,
- const char* volume_uuid, int uid, int storage_flag);
-
-int get_path_from_env(dir_rec_t* rec, const char* var);
-
-int get_path_from_string(dir_rec_t* rec, const char* path);
-
-int copy_and_append(dir_rec_t* dst, const dir_rec_t* src, const char* suffix);
+ const char* volume_uuid, int uid, int storage_flag, bool validate_package_path = true);
int validate_apk_path(const char *path);
int validate_apk_path_subdirs(const char *path);
-int append_and_increment(char** dst, const char* src, size_t* dst_size);
-
-char *build_string2(const char *s1, const char *s2);
-char *build_string3(const char *s1, const char *s2, const char *s3);
-
int ensure_config_user_dirs(userid_t userid);
int wait_child(pid_t pid);
diff --git a/cmds/ip-up-vpn/Android.mk b/cmds/ip-up-vpn/Android.mk
index 36bbdf5..e1e2204 100644
--- a/cmds/ip-up-vpn/Android.mk
+++ b/cmds/ip-up-vpn/Android.mk
@@ -18,6 +18,7 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES := ip-up-vpn.c
+LOCAL_CFLAGS := -Wall -Werror
LOCAL_SHARED_LIBRARIES := libcutils liblog
LOCAL_MODULE := ip-up-vpn
LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/ppp
diff --git a/cmds/lshal/Android.bp b/cmds/lshal/Android.bp
index 67b5b46..409c206 100644
--- a/cmds/lshal/Android.bp
+++ b/cmds/lshal/Android.bp
@@ -20,16 +20,24 @@
"libutils",
"libhidlbase",
"libhidltransport",
+ "libhidl-gen-hash",
"libhidl-gen-utils",
"libvintf",
],
srcs: [
"DebugCommand.cpp",
+ "HelpCommand.cpp",
"Lshal.cpp",
"ListCommand.cpp",
"PipeRelay.cpp",
+ "TableEntry.cpp",
+ "TextTable.cpp",
"utils.cpp",
],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
}
cc_defaults {
@@ -40,7 +48,8 @@
"libhidltransport",
"liblshal",
"libutils",
- ]
+ ],
+ cflags: ["-Wall", "-Werror"],
}
cc_binary {
@@ -59,6 +68,7 @@
"libgmock"
],
shared_libs: [
+ "libvintf",
"android.hardware.tests.baz@1.0"
],
srcs: [
diff --git a/cmds/lshal/Command.h b/cmds/lshal/Command.h
new file mode 100644
index 0000000..4f128ab
--- /dev/null
+++ b/cmds/lshal/Command.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef FRAMEWORK_NATIVE_CMDS_LSHAL_COMMAND_H_
+#define FRAMEWORK_NATIVE_CMDS_LSHAL_COMMAND_H_
+
+#include "utils.h"
+
+namespace android {
+namespace lshal {
+
+class Lshal;
+
+// Base class for all *Commands
+class Command {
+public:
+ Command(Lshal& lshal) : mLshal(lshal) {}
+ virtual ~Command() = default;
+ // Expect optind to be set by Lshal::main and points to the next argument
+ // to process.
+ virtual Status main(const Arg &arg) = 0;
+
+ virtual void usage() const = 0;
+
+ // e.g. "list"
+ virtual std::string getName() const = 0;
+
+ // e.g. "list HALs"
+ virtual std::string getSimpleDescription() const = 0;
+
+protected:
+ Lshal& mLshal;
+};
+
+
+} // namespace lshal
+} // namespace android
+
+#endif // FRAMEWORK_NATIVE_CMDS_LSHAL_LIST_COMMAND_H_
diff --git a/cmds/lshal/DebugCommand.cpp b/cmds/lshal/DebugCommand.cpp
index 672cad6..622f866 100644
--- a/cmds/lshal/DebugCommand.cpp
+++ b/cmds/lshal/DebugCommand.cpp
@@ -21,12 +21,16 @@
namespace android {
namespace lshal {
-DebugCommand::DebugCommand(Lshal &lshal) : mLshal(lshal) {
+std::string DebugCommand::getName() const {
+ return "debug";
}
-Status DebugCommand::parseArgs(const std::string &command, const Arg &arg) {
+std::string DebugCommand::getSimpleDescription() const {
+ return "Debug a specified HAL.";
+}
+
+Status DebugCommand::parseArgs(const Arg &arg) {
if (optind >= arg.argc) {
- mLshal.usage(command);
return USAGE;
}
mInterfaceName = arg.argv[optind];
@@ -37,8 +41,8 @@
return OK;
}
-Status DebugCommand::main(const std::string &command, const Arg &arg) {
- Status status = parseArgs(command, arg);
+Status DebugCommand::main(const Arg &arg) {
+ Status status = parseArgs(arg);
if (status != OK) {
return status;
}
@@ -49,6 +53,19 @@
mLshal.err());
}
+void DebugCommand::usage() const {
+
+ static const std::string debug =
+ "debug:\n"
+ " lshal debug <interface> [options [options [...]]] \n"
+ " Print debug information of a specified interface.\n"
+ " <inteface>: Format is `android.hardware.foo@1.0::IFoo/default`.\n"
+ " If instance name is missing `default` is used.\n"
+ " options: space separated options to IBase::debug.\n";
+
+ mLshal.err() << debug;
+}
+
} // namespace lshal
} // namespace android
diff --git a/cmds/lshal/DebugCommand.h b/cmds/lshal/DebugCommand.h
index fa0f0fa..9b91084 100644
--- a/cmds/lshal/DebugCommand.h
+++ b/cmds/lshal/DebugCommand.h
@@ -21,6 +21,7 @@
#include <android-base/macros.h>
+#include "Command.h"
#include "utils.h"
namespace android {
@@ -28,14 +29,17 @@
class Lshal;
-class DebugCommand {
+class DebugCommand : public Command {
public:
- DebugCommand(Lshal &lshal);
- Status main(const std::string &command, const Arg &arg);
+ DebugCommand(Lshal &lshal) : Command(lshal) {}
+ ~DebugCommand() = default;
+ Status main(const Arg &arg) override;
+ void usage() const override;
+ std::string getSimpleDescription() const override;
+ std::string getName() const override;
private:
- Status parseArgs(const std::string &command, const Arg &arg);
+ Status parseArgs(const Arg &arg);
- Lshal &mLshal;
std::string mInterfaceName;
std::vector<std::string> mOptions;
diff --git a/cmds/lshal/HelpCommand.cpp b/cmds/lshal/HelpCommand.cpp
new file mode 100644
index 0000000..6773ace
--- /dev/null
+++ b/cmds/lshal/HelpCommand.cpp
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 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 "HelpCommand.h"
+
+#include "Lshal.h"
+
+namespace android {
+namespace lshal {
+
+std::string HelpCommand::GetName() {
+ return "help";
+}
+
+std::string HelpCommand::getSimpleDescription() const {
+ return "Print help message.";
+}
+
+Status HelpCommand::main(const Arg &arg) {
+ if (optind >= arg.argc) {
+ // `lshal help` prints global usage.
+ mLshal.usage();
+ return OK;
+ }
+ (void)usageOfCommand(arg.argv[optind]);
+ return OK;
+}
+
+Status HelpCommand::usageOfCommand(const std::string& c) const {
+ if (c.empty()) {
+ mLshal.usage();
+ return USAGE;
+ }
+ auto command = mLshal.selectCommand(c);
+ if (command == nullptr) {
+ // from HelpCommand::main, `lshal help unknown`
+ mLshal.usage();
+ return USAGE;
+ }
+
+ command->usage();
+ return USAGE;
+
+}
+
+void HelpCommand::usage() const {
+ mLshal.err()
+ << "help:" << std::endl
+ << " lshal -h" << std::endl
+ << " lshal --help" << std::endl
+ << " lshal help" << std::endl
+ << " Print this help message" << std::endl;
+ mLshal.forEachCommand([&](const Command* e) {
+ mLshal.err() << " lshal help " << e->getName() << std::endl
+ << " Print help message for " << e->getName() << std::endl;
+ });
+
+}
+
+} // namespace lshal
+} // namespace android
+
diff --git a/cmds/lshal/HelpCommand.h b/cmds/lshal/HelpCommand.h
new file mode 100644
index 0000000..cc709f8
--- /dev/null
+++ b/cmds/lshal/HelpCommand.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef FRAMEWORK_NATIVE_CMDS_LSHAL_HELP_COMMAND_H_
+#define FRAMEWORK_NATIVE_CMDS_LSHAL_HELP_COMMAND_H_
+
+#include <string>
+
+#include <android-base/macros.h>
+
+#include "Command.h"
+#include "utils.h"
+
+namespace android {
+namespace lshal {
+
+class Lshal;
+
+class HelpCommand : public Command {
+public:
+ HelpCommand(Lshal &lshal) : Command(lshal) {}
+ ~HelpCommand() = default;
+ Status main(const Arg &arg) override;
+ void usage() const override;
+ std::string getSimpleDescription() const override;
+ std::string getName() const override { return GetName(); }
+ static std::string GetName();
+ Status usageOfCommand(const std::string& c) const;
+};
+
+
+} // namespace lshal
+} // namespace android
+
+#endif // FRAMEWORK_NATIVE_CMDS_LSHAL_HELP_COMMAND_H_
diff --git a/cmds/lshal/ListCommand.cpp b/cmds/lshal/ListCommand.cpp
index 87b9104..7399692 100644
--- a/cmds/lshal/ListCommand.cpp
+++ b/cmds/lshal/ListCommand.cpp
@@ -27,6 +27,7 @@
#include <android-base/parseint.h>
#include <android/hidl/manager/1.0/IServiceManager.h>
+#include <hidl-hash/Hash.h>
#include <hidl-util/FQName.h>
#include <private/android_filesystem_config.h>
#include <sys/stat.h>
@@ -39,15 +40,30 @@
#include "utils.h"
using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hidl::base::V1_0::DebugInfo;
+using ::android::hidl::base::V1_0::IBase;
using ::android::hidl::manager::V1_0::IServiceManager;
namespace android {
namespace lshal {
-ListCommand::ListCommand(Lshal &lshal) : mLshal(lshal), mErr(lshal.err()), mOut(lshal.out()) {
+NullableOStream<std::ostream> ListCommand::out() const {
+ return mLshal.out();
}
-std::string getCmdline(pid_t pid) {
+NullableOStream<std::ostream> ListCommand::err() const {
+ return mLshal.err();
+}
+
+std::string ListCommand::GetName() {
+ return "list";
+}
+std::string ListCommand::getSimpleDescription() const {
+ return "List HALs.";
+}
+
+std::string ListCommand::parseCmdline(pid_t pid) const {
std::ifstream ifs("/proc/" + std::to_string(pid) + "/cmdline");
std::string cmdline;
if (!ifs.is_open()) {
@@ -62,7 +78,7 @@
if (pair != mCmdlines.end()) {
return pair->second;
}
- mCmdlines[pid] = ::android::lshal::getCmdline(pid);
+ mCmdlines[pid] = parseCmdline(pid);
return mCmdlines[pid];
}
@@ -73,7 +89,7 @@
}), pids->end());
}
-bool scanBinderContext(pid_t pid,
+static bool scanBinderContext(pid_t pid,
const std::string &contextName,
std::function<void(const std::string&)> eachLine) {
std::ifstream ifs("/d/binder/proc/" + std::to_string(pid));
@@ -113,7 +129,7 @@
uint64_t ptr;
if (!::android::base::ParseUint(ptrString.c_str(), &ptr)) {
// Should not reach here, but just be tolerant.
- mErr << "Could not parse number " << ptrString << std::endl;
+ err() << "Could not parse number " << ptrString << std::endl;
return;
}
const std::string proc = " proc ";
@@ -122,7 +138,7 @@
for (const std::string &pidStr : split(line.substr(pos + proc.size()), ' ')) {
int32_t pid;
if (!::android::base::ParseInt(pidStr, &pid)) {
- mErr << "Could not parse number " << pidStr << std::endl;
+ err() << "Could not parse number " << pidStr << std::endl;
return;
}
pidInfo->refPids[ptr].push_back(pid);
@@ -159,6 +175,16 @@
});
}
+const PidInfo* ListCommand::getPidInfoCached(pid_t serverPid) {
+ auto pair = mCachedPidInfos.insert({serverPid, PidInfo{}});
+ if (pair.second /* did insertion take place? */) {
+ if (!getPidInfo(serverPid, &pair.first->second)) {
+ return nullptr;
+ }
+ }
+ return &pair.first->second;
+}
+
// Must process hwbinder services first, then passthrough services.
void ListCommand::forEachTable(const std::function<void(Table &)> &f) {
f(mServicesTable);
@@ -204,55 +230,42 @@
}
}
}
+
+ mServicesTable.setDescription(
+ "All binderized services (registered services through hwservicemanager)");
+ mPassthroughRefTable.setDescription(
+ "All interfaces that getService() has ever return as a passthrough interface;\n"
+ "PIDs / processes shown below might be inaccurate because the process\n"
+ "might have relinquished the interface or might have died.\n"
+ "The Server / Server CMD column can be ignored.\n"
+ "The Clients / Clients CMD column shows all process that have ever dlopen'ed \n"
+ "the library and successfully fetched the passthrough implementation.");
+ mImplementationsTable.setDescription(
+ "All available passthrough implementations (all -impl.so files)");
}
-void ListCommand::printLine(
- const std::string &interfaceName,
- const std::string &transport,
- const std::string &arch,
- const std::string &threadUsage,
- const std::string &server,
- const std::string &serverCmdline,
- const std::string &address,
- const std::string &clients,
- const std::string &clientCmdlines) const {
- if (mSelectedColumns & ENABLE_INTERFACE_NAME)
- mOut << std::setw(80) << interfaceName << "\t";
- if (mSelectedColumns & ENABLE_TRANSPORT)
- mOut << std::setw(10) << transport << "\t";
- if (mSelectedColumns & ENABLE_ARCH)
- mOut << std::setw(5) << arch << "\t";
- if (mSelectedColumns & ENABLE_THREADS) {
- mOut << std::setw(8) << threadUsage << "\t";
- }
- if (mSelectedColumns & ENABLE_SERVER_PID) {
- if (mEnableCmdlines) {
- mOut << std::setw(15) << serverCmdline << "\t";
- } else {
- mOut << std::setw(5) << server << "\t";
+static inline bool findAndBumpVersion(vintf::ManifestHal* hal, const vintf::Version& version) {
+ for (vintf::Version& v : hal->versions) {
+ if (v.majorVer == version.majorVer) {
+ v.minorVer = std::max(v.minorVer, version.minorVer);
+ return true;
}
}
- if (mSelectedColumns & ENABLE_SERVER_ADDR)
- mOut << std::setw(16) << address << "\t";
- if (mSelectedColumns & ENABLE_CLIENT_PIDS) {
- if (mEnableCmdlines) {
- mOut << std::setw(0) << clientCmdlines;
- } else {
- mOut << std::setw(0) << clients;
- }
- }
- mOut << std::endl;
+ return false;
}
-void ListCommand::dumpVintf() const {
- mOut << "<!-- " << std::endl
+void ListCommand::dumpVintf(const NullableOStream<std::ostream>& out) const {
+ using vintf::operator|=;
+ out << "<!-- " << std::endl
<< " This is a skeleton device manifest. Notes: " << std::endl
<< " 1. android.hidl.*, android.frameworks.*, android.system.* are not included." << std::endl
<< " 2. If a HAL is supported in both hwbinder and passthrough transport, " << std::endl
<< " only hwbinder is shown." << std::endl
<< " 3. It is likely that HALs in passthrough transport does not have" << std::endl
<< " <interface> declared; users will have to write them by hand." << std::endl
- << " 4. sepolicy version is set to 0.0. It is recommended that the entry" << std::endl
+ << " 4. A HAL with lower minor version can be overridden by a HAL with" << std::endl
+ << " higher minor version if they have the same name and major version." << std::endl
+ << " 5. sepolicy version is set to 0.0. It is recommended that the entry" << std::endl
<< " is removed from the manifest file and written by assemble_vintf" << std::endl
<< " at build time." << std::endl
<< "-->" << std::endl;
@@ -270,7 +283,7 @@
auto splittedFqInstanceName = splitFirst(fqInstanceName, '/');
FQName fqName(splittedFqInstanceName.first);
if (!fqName.isValid()) {
- mErr << "Warning: '" << splittedFqInstanceName.first
+ err() << "Warning: '" << splittedFqInstanceName.first
<< "' is not a valid FQName." << std::endl;
continue;
}
@@ -303,12 +316,12 @@
arch = vintf::Arch::ARCH_32_64; break;
case lshal::ARCH_UNKNOWN: // fallthrough
default:
- mErr << "Warning: '" << fqName.package()
+ err() << "Warning: '" << fqName.package()
<< "' doesn't have bitness info, assuming 32+64." << std::endl;
arch = vintf::Arch::ARCH_32_64;
}
} else {
- mErr << "Warning: '" << entry.transport << "' is not a valid transport." << std::endl;
+ err() << "Warning: '" << entry.transport << "' is not a valid transport." << std::endl;
continue;
}
@@ -316,17 +329,19 @@
for (vintf::ManifestHal *hal : manifest.getHals(fqName.package())) {
if (hal->transport() != transport) {
if (transport != vintf::Transport::PASSTHROUGH) {
- mErr << "Fatal: should not reach here. Generated result may be wrong."
+ err() << "Fatal: should not reach here. Generated result may be wrong for '"
+ << hal->name << "'."
<< std::endl;
}
done = true;
break;
}
- if (hal->hasVersion(version)) {
+ if (findAndBumpVersion(hal, version)) {
if (&table != &mImplementationsTable) {
hal->interfaces[interfaceName].name = interfaceName;
hal->interfaces[interfaceName].instances.insert(instanceName);
}
+ hal->transportArch.arch |= arch;
done = true;
break;
}
@@ -345,29 +360,11 @@
.versions = {version},
.transportArch = {transport, arch},
.interfaces = interfaces})) {
- mErr << "Warning: cannot add hal '" << fqInstanceName << "'" << std::endl;
+ err() << "Warning: cannot add hal '" << fqInstanceName << "'" << std::endl;
}
}
});
- mOut << vintf::gHalManifestConverter(manifest);
-}
-
-static const std::string &getArchString(Architecture arch) {
- static const std::string sStr64 = "64";
- static const std::string sStr32 = "32";
- static const std::string sStrBoth = "32+64";
- static const std::string sStrUnknown = "";
- switch (arch) {
- case ARCH64:
- return sStr64;
- case ARCH32:
- return sStr32;
- case ARCH_BOTH:
- return sStrBoth;
- case ARCH_UNKNOWN: // fall through
- default:
- return sStrUnknown;
- }
+ out << vintf::gHalManifestConverter(manifest);
}
static Architecture fromBaseArchitecture(::android::hidl::base::V1_0::DebugInfo::Architecture a) {
@@ -382,68 +379,54 @@
}
}
-void ListCommand::dumpTable() {
- mServicesTable.description =
- "All binderized services (registered services through hwservicemanager)";
- mPassthroughRefTable.description =
- "All interfaces that getService() has ever return as a passthrough interface;\n"
- "PIDs / processes shown below might be inaccurate because the process\n"
- "might have relinquished the interface or might have died.\n"
- "The Server / Server CMD column can be ignored.\n"
- "The Clients / Clients CMD column shows all process that have ever dlopen'ed \n"
- "the library and successfully fetched the passthrough implementation.";
- mImplementationsTable.description =
- "All available passthrough implementations (all -impl.so files)";
- forEachTable([this] (const Table &table) {
- if (!mNeat) {
- mOut << table.description << std::endl;
- }
- mOut << std::left;
- if (!mNeat) {
- printLine("Interface", "Transport", "Arch", "Thread Use", "Server",
- "Server CMD", "PTR", "Clients", "Clients CMD");
- }
+void ListCommand::dumpTable(const NullableOStream<std::ostream>& out) const {
+ if (mNeat) {
+ MergedTable({&mServicesTable, &mPassthroughRefTable, &mImplementationsTable})
+ .createTextTable().dump(out.buf());
+ return;
+ }
- for (const auto &entry : table) {
- printLine(entry.interfaceName,
- entry.transport,
- getArchString(entry.arch),
- entry.getThreadUsage(),
- entry.serverPid == NO_PID ? "N/A" : std::to_string(entry.serverPid),
- entry.serverCmdline,
- entry.serverObjectAddress == NO_PTR ? "N/A" : toHexString(entry.serverObjectAddress),
- join(entry.clientPids, " "),
- join(entry.clientCmdlines, ";"));
+ forEachTable([this, &out](const Table &table) {
- // We're only interested in dumping debug info for already
- // instantiated services. There's little value in dumping the
- // debug info for a service we create on the fly, so we only operate
- // on the "mServicesTable".
- if (mEmitDebugInfo && &table == &mServicesTable) {
- auto pair = splitFirst(entry.interfaceName, '/');
- mLshal.emitDebugInfo(pair.first, pair.second, {}, mOut.buf(),
- NullableOStream<std::ostream>(nullptr));
- }
+ // We're only interested in dumping debug info for already
+ // instantiated services. There's little value in dumping the
+ // debug info for a service we create on the fly, so we only operate
+ // on the "mServicesTable".
+ std::function<std::string(const std::string&)> emitDebugInfo = nullptr;
+ if (mEmitDebugInfo && &table == &mServicesTable) {
+ emitDebugInfo = [this](const auto& iName) {
+ std::stringstream ss;
+ auto pair = splitFirst(iName, '/');
+ mLshal.emitDebugInfo(pair.first, pair.second, {}, ss,
+ NullableOStream<std::ostream>(nullptr));
+ return ss.str();
+ };
}
- if (!mNeat) {
- mOut << std::endl;
- }
+ table.createTextTable(mNeat, emitDebugInfo).dump(out.buf());
+ out << std::endl;
});
-
}
-void ListCommand::dump() {
- if (mVintf) {
- dumpVintf();
- if (!!mFileOutput) {
- mFileOutput.buf().close();
- delete &mFileOutput.buf();
- mFileOutput = nullptr;
- }
- mOut = std::cout;
- } else {
- dumpTable();
+Status ListCommand::dump() {
+ auto dump = mVintf ? &ListCommand::dumpVintf : &ListCommand::dumpTable;
+
+ if (mFileOutputPath.empty()) {
+ (*this.*dump)(out());
+ return OK;
}
+
+ std::ofstream fileOutput(mFileOutputPath);
+ if (!fileOutput.is_open()) {
+ err() << "Could not open file '" << mFileOutputPath << "'." << std::endl;
+ return IO_ERROR;
+ }
+ chown(mFileOutputPath.c_str(), AID_SHELL, AID_SHELL);
+
+ (*this.*dump)(NullableOStream<std::ostream>(fileOutput));
+
+ fileOutput.flush();
+ fileOutput.close();
+ return OK;
}
void ListCommand::putEntry(TableEntrySource source, TableEntry &&entry) {
@@ -456,10 +439,10 @@
case LIST_DLLIB :
table = &mImplementationsTable; break;
default:
- mErr << "Error: Unknown source of entry " << source << std::endl;
+ err() << "Error: Unknown source of entry " << source << std::endl;
}
if (table) {
- table->entries.push_back(std::forward<TableEntry>(entry));
+ table->add(std::forward<TableEntry>(entry));
}
}
@@ -476,10 +459,7 @@
entries.emplace(interfaceName, TableEntry{
.interfaceName = interfaceName,
.transport = "passthrough",
- .serverPid = NO_PID,
- .serverObjectAddress = NO_PTR,
.clientPids = info.clientPids,
- .arch = ARCH_UNKNOWN
}).first->second.arch |= fromBaseArchitecture(info.arch);
}
for (auto &&pair : entries) {
@@ -487,7 +467,7 @@
}
});
if (!ret.isOk()) {
- mErr << "Error: Failed to call list on getPassthroughServiceManager(): "
+ err() << "Error: Failed to call list on getPassthroughServiceManager(): "
<< ret.description() << std::endl;
return DUMP_ALL_LIBS_ERROR;
}
@@ -510,14 +490,13 @@
std::string{info.instanceName.c_str()},
.transport = "passthrough",
.serverPid = info.clientPids.size() == 1 ? info.clientPids[0] : NO_PID,
- .serverObjectAddress = NO_PTR,
.clientPids = info.clientPids,
.arch = fromBaseArchitecture(info.arch)
});
}
});
if (!ret.isOk()) {
- mErr << "Error: Failed to call debugDump on defaultServiceManager(): "
+ err() << "Error: Failed to call debugDump on defaultServiceManager(): "
<< ret.description() << std::endl;
return DUMP_PASSTHROUGH_ERROR;
}
@@ -525,10 +504,6 @@
}
Status ListCommand::fetchBinderized(const sp<IServiceManager> &manager) {
- using namespace ::std;
- using namespace ::android::hardware;
- using namespace ::android::hidl::manager::V1_0;
- using namespace ::android::hidl::base::V1_0;
const std::string mode = "hwbinder";
hidl_vec<hidl_string> fqInstanceNames;
@@ -537,86 +512,123 @@
fqInstanceNames = names;
});
if (!listRet.isOk()) {
- mErr << "Error: Failed to list services for " << mode << ": "
+ err() << "Error: Failed to list services for " << mode << ": "
<< listRet.description() << std::endl;
return DUMP_BINDERIZED_ERROR;
}
Status status = OK;
- // server pid, .ptr value of binder object, child pids
- std::map<std::string, DebugInfo> allDebugInfos;
- std::map<pid_t, PidInfo> allPids;
+ std::map<std::string, TableEntry> allTableEntries;
for (const auto &fqInstanceName : fqInstanceNames) {
- const auto pair = splitFirst(fqInstanceName, '/');
- const auto &serviceName = pair.first;
- const auto &instanceName = pair.second;
- auto getRet = timeoutIPC(manager, &IServiceManager::get, serviceName, instanceName);
- if (!getRet.isOk()) {
- mErr << "Warning: Skipping \"" << fqInstanceName << "\": "
- << "cannot be fetched from service manager:"
- << getRet.description() << std::endl;
- status |= DUMP_BINDERIZED_ERROR;
- continue;
- }
- sp<IBase> service = getRet;
- if (service == nullptr) {
- mErr << "Warning: Skipping \"" << fqInstanceName << "\": "
- << "cannot be fetched from service manager (null)"
- << std::endl;
- status |= DUMP_BINDERIZED_ERROR;
- continue;
- }
- auto debugRet = timeoutIPC(service, &IBase::getDebugInfo, [&] (const auto &debugInfo) {
- allDebugInfos[fqInstanceName] = debugInfo;
- if (debugInfo.pid >= 0) {
- allPids[static_cast<pid_t>(debugInfo.pid)] = PidInfo();
- }
+ // create entry and default assign all fields.
+ TableEntry& entry = allTableEntries[fqInstanceName];
+ entry.interfaceName = fqInstanceName;
+ entry.transport = mode;
+
+ status |= fetchBinderizedEntry(manager, &entry);
+ }
+
+ for (auto& pair : allTableEntries) {
+ putEntry(HWSERVICEMANAGER_LIST, std::move(pair.second));
+ }
+ return status;
+}
+
+Status ListCommand::fetchBinderizedEntry(const sp<IServiceManager> &manager,
+ TableEntry *entry) {
+ Status status = OK;
+ const auto handleError = [&](Status additionalError, const std::string& msg) {
+ err() << "Warning: Skipping \"" << entry->interfaceName << "\": " << msg << std::endl;
+ status |= DUMP_BINDERIZED_ERROR | additionalError;
+ };
+
+ const auto pair = splitFirst(entry->interfaceName, '/');
+ const auto &serviceName = pair.first;
+ const auto &instanceName = pair.second;
+ auto getRet = timeoutIPC(manager, &IServiceManager::get, serviceName, instanceName);
+ if (!getRet.isOk()) {
+ handleError(TRANSACTION_ERROR,
+ "cannot be fetched from service manager:" + getRet.description());
+ return status;
+ }
+ sp<IBase> service = getRet;
+ if (service == nullptr) {
+ handleError(NO_INTERFACE, "cannot be fetched from service manager (null)");
+ return status;
+ }
+
+ // getDebugInfo
+ do {
+ DebugInfo debugInfo;
+ auto debugRet = timeoutIPC(service, &IBase::getDebugInfo, [&] (const auto &received) {
+ debugInfo = received;
});
if (!debugRet.isOk()) {
- mErr << "Warning: Skipping \"" << fqInstanceName << "\": "
- << "debugging information cannot be retrieved:"
- << debugRet.description() << std::endl;
- status |= DUMP_BINDERIZED_ERROR;
+ handleError(TRANSACTION_ERROR,
+ "debugging information cannot be retrieved: " + debugRet.description());
+ break; // skip getPidInfo
}
- }
- for (auto &pair : allPids) {
- pid_t serverPid = pair.first;
- if (!getPidInfo(serverPid, &allPids[serverPid])) {
- mErr << "Warning: no information for PID " << serverPid
- << ", are you root?" << std::endl;
- status |= DUMP_BINDERIZED_ERROR;
- }
- }
- for (const auto &fqInstanceName : fqInstanceNames) {
- auto it = allDebugInfos.find(fqInstanceName);
- if (it == allDebugInfos.end()) {
- putEntry(HWSERVICEMANAGER_LIST, {
- .interfaceName = fqInstanceName,
- .transport = mode,
- .serverPid = NO_PID,
- .serverObjectAddress = NO_PTR,
- .clientPids = {},
- .threadUsage = 0,
- .threadCount = 0,
- .arch = ARCH_UNKNOWN
- });
- continue;
- }
- const DebugInfo &info = it->second;
- bool writePidInfo = info.pid != NO_PID && info.ptr != NO_PTR;
+ entry->serverPid = debugInfo.pid;
+ entry->serverObjectAddress = debugInfo.ptr;
+ entry->arch = fromBaseArchitecture(debugInfo.arch);
- putEntry(HWSERVICEMANAGER_LIST, {
- .interfaceName = fqInstanceName,
- .transport = mode,
- .serverPid = info.pid,
- .serverObjectAddress = info.ptr,
- .clientPids = writePidInfo ? allPids[info.pid].refPids[info.ptr] : Pids{},
- .threadUsage = writePidInfo ? allPids[info.pid].threadUsage : 0,
- .threadCount = writePidInfo ? allPids[info.pid].threadCount : 0,
- .arch = fromBaseArchitecture(info.arch),
+ if (debugInfo.pid != NO_PID) {
+ const PidInfo* pidInfo = getPidInfoCached(debugInfo.pid);
+ if (pidInfo == nullptr) {
+ handleError(IO_ERROR,
+ "no information for PID " + std::to_string(debugInfo.pid) +
+ ", are you root?");
+ break;
+ }
+ if (debugInfo.ptr != NO_PTR) {
+ auto it = pidInfo->refPids.find(debugInfo.ptr);
+ if (it != pidInfo->refPids.end()) {
+ entry->clientPids = it->second;
+ }
+ }
+ entry->threadUsage = pidInfo->threadUsage;
+ entry->threadCount = pidInfo->threadCount;
+ }
+ } while (0);
+
+ // hash
+ do {
+ ssize_t hashIndex = -1;
+ auto ifaceChainRet = timeoutIPC(service, &IBase::interfaceChain, [&] (const auto& c) {
+ for (size_t i = 0; i < c.size(); ++i) {
+ if (serviceName == c[i]) {
+ hashIndex = static_cast<ssize_t>(i);
+ break;
+ }
+ }
});
- }
+ if (!ifaceChainRet.isOk()) {
+ handleError(TRANSACTION_ERROR,
+ "interfaceChain fails: " + ifaceChainRet.description());
+ break; // skip getHashChain
+ }
+ if (hashIndex < 0) {
+ handleError(BAD_IMPL, "Interface name does not exist in interfaceChain.");
+ break; // skip getHashChain
+ }
+ auto hashRet = timeoutIPC(service, &IBase::getHashChain, [&] (const auto& hashChain) {
+ if (static_cast<size_t>(hashIndex) >= hashChain.size()) {
+ handleError(BAD_IMPL,
+ "interfaceChain indicates position " + std::to_string(hashIndex) +
+ " but getHashChain returns " + std::to_string(hashChain.size()) +
+ " hashes");
+ return;
+ }
+
+ auto&& hashArray = hashChain[hashIndex];
+ std::vector<uint8_t> hashVec{hashArray.data(), hashArray.data() + hashArray.size()};
+ entry->hash = Hash::hexString(hashVec);
+ });
+ if (!hashRet.isOk()) {
+ handleError(TRANSACTION_ERROR, "getHashChain failed: " + hashRet.description());
+ }
+ } while (0);
return status;
}
@@ -624,7 +636,7 @@
Status status = OK;
auto bManager = mLshal.serviceManager();
if (bManager == nullptr) {
- mErr << "Failed to get defaultServiceManager()!" << std::endl;
+ err() << "Failed to get defaultServiceManager()!" << std::endl;
status |= NO_BINDERIZED_MANAGER;
} else {
status |= fetchBinderized(bManager);
@@ -634,7 +646,7 @@
auto pManager = mLshal.passthroughManager();
if (pManager == nullptr) {
- mErr << "Failed to get getPassthroughServiceManager()!" << std::endl;
+ err() << "Failed to get getPassthroughServiceManager()!" << std::endl;
status |= NO_PASSTHROUGH_MANAGER;
} else {
status |= fetchAllLibraries(pManager);
@@ -642,139 +654,270 @@
return status;
}
-Status ListCommand::parseArgs(const std::string &command, const Arg &arg) {
- static struct option longOptions[] = {
- // long options with short alternatives
- {"help", no_argument, 0, 'h' },
- {"interface", no_argument, 0, 'i' },
- {"transport", no_argument, 0, 't' },
- {"arch", no_argument, 0, 'r' },
- {"pid", no_argument, 0, 'p' },
- {"address", no_argument, 0, 'a' },
- {"clients", no_argument, 0, 'c' },
- {"threads", no_argument, 0, 'e' },
- {"cmdline", no_argument, 0, 'm' },
- {"debug", optional_argument, 0, 'd' },
+void ListCommand::registerAllOptions() {
+ int v = mOptions.size();
+ // A list of acceptable command line options
+ // key: value returned by getopt_long
+ // long options with short alternatives
+ mOptions.push_back({'h', "help", no_argument, v++, [](ListCommand*, const char*) {
+ return USAGE;
+ }, ""});
+ mOptions.push_back({'i', "interface", no_argument, v++, [](ListCommand* thiz, const char*) {
+ thiz->mSelectedColumns.push_back(TableColumnType::INTERFACE_NAME);
+ return OK;
+ }, "print the instance name column"});
+ mOptions.push_back({'l', "released", no_argument, v++, [](ListCommand* thiz, const char*) {
+ thiz->mSelectedColumns.push_back(TableColumnType::RELEASED);
+ return OK;
+ }, "print the 'is released?' column\n(Y=released, empty=unreleased or unknown)"});
+ mOptions.push_back({'t', "transport", no_argument, v++, [](ListCommand* thiz, const char*) {
+ thiz->mSelectedColumns.push_back(TableColumnType::TRANSPORT);
+ return OK;
+ }, "print the transport mode column"});
+ mOptions.push_back({'r', "arch", no_argument, v++, [](ListCommand* thiz, const char*) {
+ thiz->mSelectedColumns.push_back(TableColumnType::ARCH);
+ return OK;
+ }, "print the bitness column"});
+ mOptions.push_back({'s', "hash", no_argument, v++, [](ListCommand* thiz, const char*) {
+ thiz->mSelectedColumns.push_back(TableColumnType::HASH);
+ return OK;
+ }, "print hash of the interface"});
+ mOptions.push_back({'p', "pid", no_argument, v++, [](ListCommand* thiz, const char*) {
+ thiz->mSelectedColumns.push_back(TableColumnType::SERVER_PID);
+ return OK;
+ }, "print the server PID, or server cmdline if -m is set"});
+ mOptions.push_back({'a', "address", no_argument, v++, [](ListCommand* thiz, const char*) {
+ thiz->mSelectedColumns.push_back(TableColumnType::SERVER_ADDR);
+ return OK;
+ }, "print the server object address column"});
+ mOptions.push_back({'c', "clients", no_argument, v++, [](ListCommand* thiz, const char*) {
+ thiz->mSelectedColumns.push_back(TableColumnType::CLIENT_PIDS);
+ return OK;
+ }, "print the client PIDs, or client cmdlines if -m is set"});
+ mOptions.push_back({'e', "threads", no_argument, v++, [](ListCommand* thiz, const char*) {
+ thiz->mSelectedColumns.push_back(TableColumnType::THREADS);
+ return OK;
+ }, "print currently used/available threads\n(note, available threads created lazily)"});
+ mOptions.push_back({'m', "cmdline", no_argument, v++, [](ListCommand* thiz, const char*) {
+ thiz->mEnableCmdlines = true;
+ return OK;
+ }, "print cmdline instead of PIDs"});
+ mOptions.push_back({'d', "debug", optional_argument, v++, [](ListCommand* thiz, const char* arg) {
+ thiz->mEmitDebugInfo = true;
+ if (arg) thiz->mFileOutputPath = arg;
+ return OK;
+ }, "Emit debug info from\nIBase::debug with empty options. Cannot be used with --neat.\n"
+ "Writes to specified file if 'arg' is provided, otherwise stdout."});
- // long options without short alternatives
- {"sort", required_argument, 0, 's' },
- {"init-vintf",optional_argument, 0, 'v' },
- {"neat", no_argument, 0, 'n' },
- { 0, 0, 0, 0 }
- };
+ // long options without short alternatives
+ mOptions.push_back({'\0', "init-vintf", no_argument, v++, [](ListCommand* thiz, const char* arg) {
+ thiz->mVintf = true;
+ if (arg) thiz->mFileOutputPath = arg;
+ return OK;
+ }, "form a skeleton HAL manifest to specified file,\nor stdout if no file specified."});
+ mOptions.push_back({'\0', "sort", required_argument, v++, [](ListCommand* thiz, const char* arg) {
+ if (strcmp(arg, "interface") == 0 || strcmp(arg, "i") == 0) {
+ thiz->mSortColumn = TableEntry::sortByInterfaceName;
+ } else if (strcmp(arg, "pid") == 0 || strcmp(arg, "p") == 0) {
+ thiz->mSortColumn = TableEntry::sortByServerPid;
+ } else {
+ thiz->err() << "Unrecognized sorting column: " << arg << std::endl;
+ return USAGE;
+ }
+ return OK;
+ }, "sort by a column. 'arg' can be (i|interface) or (p|pid)."});
+ mOptions.push_back({'\0', "neat", no_argument, v++, [](ListCommand* thiz, const char*) {
+ thiz->mNeat = true;
+ return OK;
+ }, "output is machine parsable (no explanatory text).\nCannot be used with --debug."});
+}
+
+// Create 'longopts' argument to getopt_long. Caller is responsible for maintaining
+// the lifetime of "options" during the usage of the returned array.
+static std::unique_ptr<struct option[]> getLongOptions(
+ const ListCommand::RegisteredOptions& options,
+ int* longOptFlag) {
+ std::unique_ptr<struct option[]> ret{new struct option[options.size() + 1]};
+ int i = 0;
+ for (const auto& e : options) {
+ ret[i].name = e.longOption.c_str();
+ ret[i].has_arg = e.hasArg;
+ ret[i].flag = longOptFlag;
+ ret[i].val = e.val;
+
+ i++;
+ }
+ // getopt_long last option has all zeros
+ ret[i].name = NULL;
+ ret[i].has_arg = 0;
+ ret[i].flag = NULL;
+ ret[i].val = 0;
+
+ return ret;
+}
+
+// Create 'optstring' argument to getopt_long.
+static std::string getShortOptions(const ListCommand::RegisteredOptions& options) {
+ std::stringstream ss;
+ for (const auto& e : options) {
+ if (e.shortOption != '\0') {
+ ss << e.shortOption;
+ }
+ }
+ return ss.str();
+}
+
+Status ListCommand::parseArgs(const Arg &arg) {
+
+ if (mOptions.empty()) {
+ registerAllOptions();
+ }
+ int longOptFlag;
+ std::unique_ptr<struct option[]> longOptions = getLongOptions(mOptions, &longOptFlag);
+ std::string shortOptions = getShortOptions(mOptions);
+
+ // suppress output to std::err for unknown options
+ opterr = 0;
int optionIndex;
int c;
// Lshal::parseArgs has set optind to the next option to parse
for (;;) {
- // using getopt_long in case we want to add other options in the future
c = getopt_long(arg.argc, arg.argv,
- "hitrpacmde", longOptions, &optionIndex);
+ shortOptions.c_str(), longOptions.get(), &optionIndex);
if (c == -1) {
break;
}
- switch (c) {
- case 's': {
- if (strcmp(optarg, "interface") == 0 || strcmp(optarg, "i") == 0) {
- mSortColumn = TableEntry::sortByInterfaceName;
- } else if (strcmp(optarg, "pid") == 0 || strcmp(optarg, "p") == 0) {
- mSortColumn = TableEntry::sortByServerPid;
- } else {
- mErr << "Unrecognized sorting column: " << optarg << std::endl;
- mLshal.usage(command);
- return USAGE;
+ const RegisteredOption* found = nullptr;
+ if (c == 0) {
+ // see long option
+ for (const auto& e : mOptions) {
+ if (longOptFlag == e.val) found = &e;
}
- break;
- }
- case 'v': {
- if (optarg) {
- mFileOutput = new std::ofstream{optarg};
- mOut = mFileOutput;
- if (!mFileOutput.buf().is_open()) {
- mErr << "Could not open file '" << optarg << "'." << std::endl;
- return IO_ERROR;
- }
+ } else {
+ // see short option
+ for (const auto& e : mOptions) {
+ if (c == e.shortOption) found = &e;
}
- mVintf = true;
}
- case 'i': {
- mSelectedColumns |= ENABLE_INTERFACE_NAME;
- break;
- }
- case 't': {
- mSelectedColumns |= ENABLE_TRANSPORT;
- break;
- }
- case 'r': {
- mSelectedColumns |= ENABLE_ARCH;
- break;
- }
- case 'p': {
- mSelectedColumns |= ENABLE_SERVER_PID;
- break;
- }
- case 'a': {
- mSelectedColumns |= ENABLE_SERVER_ADDR;
- break;
- }
- case 'c': {
- mSelectedColumns |= ENABLE_CLIENT_PIDS;
- break;
- }
- case 'e': {
- mSelectedColumns |= ENABLE_THREADS;
- break;
- }
- case 'm': {
- mEnableCmdlines = true;
- break;
- }
- case 'd': {
- mEmitDebugInfo = true;
- if (optarg) {
- mFileOutput = new std::ofstream{optarg};
- mOut = mFileOutput;
- if (!mFileOutput.buf().is_open()) {
- mErr << "Could not open file '" << optarg << "'." << std::endl;
- return IO_ERROR;
- }
- chown(optarg, AID_SHELL, AID_SHELL);
- }
- break;
- }
- case 'n': {
- mNeat = true;
- break;
- }
- case 'h': // falls through
- default: // see unrecognized options
- mLshal.usage(command);
+ if (found == nullptr) {
+ // see unrecognized options
+ err() << "unrecognized option `" << arg.argv[optind - 1] << "'" << std::endl;
return USAGE;
}
+
+ Status status = found->op(this, optarg);
+ if (status != OK) {
+ return status;
+ }
}
if (optind < arg.argc) {
// see non option
- mErr << "Unrecognized option `" << arg.argv[optind] << "`" << std::endl;
+ err() << "unrecognized option `" << arg.argv[optind] << "'" << std::endl;
+ return USAGE;
}
- if (mSelectedColumns == 0) {
- mSelectedColumns = ENABLE_INTERFACE_NAME | ENABLE_SERVER_PID | ENABLE_CLIENT_PIDS | ENABLE_THREADS;
+ if (mNeat && mEmitDebugInfo) {
+ err() << "Error: --neat should not be used with --debug." << std::endl;
+ return USAGE;
}
+
+ if (mSelectedColumns.empty()) {
+ mSelectedColumns = {TableColumnType::RELEASED,
+ TableColumnType::INTERFACE_NAME, TableColumnType::THREADS,
+ TableColumnType::SERVER_PID, TableColumnType::CLIENT_PIDS};
+ }
+
+ if (mEnableCmdlines) {
+ for (size_t i = 0; i < mSelectedColumns.size(); ++i) {
+ if (mSelectedColumns[i] == TableColumnType::SERVER_PID) {
+ mSelectedColumns[i] = TableColumnType::SERVER_CMD;
+ }
+ if (mSelectedColumns[i] == TableColumnType::CLIENT_PIDS) {
+ mSelectedColumns[i] = TableColumnType::CLIENT_CMDS;
+ }
+ }
+ }
+
+ forEachTable([this] (Table& table) {
+ table.setSelectedColumns(this->mSelectedColumns);
+ });
+
return OK;
}
-Status ListCommand::main(const std::string &command, const Arg &arg) {
- Status status = parseArgs(command, arg);
+Status ListCommand::main(const Arg &arg) {
+ Status status = parseArgs(arg);
if (status != OK) {
return status;
}
status = fetch();
postprocess();
- dump();
+ status |= dump();
return status;
}
+static std::vector<std::string> splitString(const std::string &s, char c) {
+ std::vector<std::string> components;
+
+ size_t startPos = 0;
+ size_t matchPos;
+ while ((matchPos = s.find(c, startPos)) != std::string::npos) {
+ components.push_back(s.substr(startPos, matchPos - startPos));
+ startPos = matchPos + 1;
+ }
+
+ if (startPos <= s.length()) {
+ components.push_back(s.substr(startPos));
+ }
+ return components;
+}
+
+const std::string& ListCommand::RegisteredOption::getHelpMessageForArgument() const {
+ static const std::string empty{};
+ static const std::string optional{"[=<arg>]"};
+ static const std::string required{"=<arg>"};
+
+ if (hasArg == optional_argument) {
+ return optional;
+ }
+ if (hasArg == required_argument) {
+ return required;
+ }
+ return empty;
+}
+
+void ListCommand::usage() const {
+
+ err() << "list:" << std::endl
+ << " lshal" << std::endl
+ << " lshal list" << std::endl
+ << " List all hals with default ordering and columns (`lshal list -riepc`)" << std::endl
+ << " lshal list [-h|--help]" << std::endl
+ << " -h, --help: Print help message for list (`lshal help list`)" << std::endl
+ << " lshal [list] [OPTIONS...]" << std::endl;
+ for (const auto& e : mOptions) {
+ if (e.help.empty()) {
+ continue;
+ }
+ err() << " ";
+ if (e.shortOption != '\0')
+ err() << "-" << e.shortOption << e.getHelpMessageForArgument();
+ if (e.shortOption != '\0' && !e.longOption.empty())
+ err() << ", ";
+ if (!e.longOption.empty())
+ err() << "--" << e.longOption << e.getHelpMessageForArgument();
+ err() << ": ";
+ std::vector<std::string> lines = splitString(e.help, '\n');
+ for (const auto& line : lines) {
+ if (&line != &lines.front())
+ err() << " ";
+ err() << line << std::endl;
+ }
+ }
+}
+
} // namespace lshal
} // namespace android
diff --git a/cmds/lshal/ListCommand.h b/cmds/lshal/ListCommand.h
index a75db04..7e252fc 100644
--- a/cmds/lshal/ListCommand.h
+++ b/cmds/lshal/ListCommand.h
@@ -17,6 +17,7 @@
#ifndef FRAMEWORK_NATIVE_CMDS_LSHAL_LIST_COMMAND_H_
#define FRAMEWORK_NATIVE_CMDS_LSHAL_LIST_COMMAND_H_
+#include <getopt.h>
#include <stdint.h>
#include <fstream>
@@ -26,8 +27,10 @@
#include <android-base/macros.h>
#include <android/hidl/manager/1.0/IServiceManager.h>
+#include "Command.h"
#include "NullableOStream.h"
#include "TableEntry.h"
+#include "TextTable.h"
#include "utils.h"
namespace android {
@@ -35,39 +38,71 @@
class Lshal;
-class ListCommand {
+struct PidInfo {
+ std::map<uint64_t, Pids> refPids; // pids that are referenced
+ uint32_t threadUsage; // number of threads in use
+ uint32_t threadCount; // number of threads total
+};
+
+class ListCommand : public Command {
public:
- ListCommand(Lshal &lshal);
- Status main(const std::string &command, const Arg &arg);
-private:
- Status parseArgs(const std::string &command, const Arg &arg);
+ ListCommand(Lshal &lshal) : Command(lshal) {}
+ virtual ~ListCommand() = default;
+ Status main(const Arg &arg) override;
+ void usage() const override;
+ std::string getSimpleDescription() const override;
+ std::string getName() const override { return GetName(); }
+
+ static std::string GetName();
+
+ struct RegisteredOption {
+ // short alternative, e.g. 'v'. If '\0', no short options is available.
+ char shortOption;
+ // long alternative, e.g. 'init-vintf'
+ std::string longOption;
+ // no_argument, required_argument or optional_argument
+ int hasArg;
+ // value written to 'flag' by getopt_long
+ int val;
+ // operation when the argument is present
+ std::function<Status(ListCommand* thiz, const char* arg)> op;
+ // help message
+ std::string help;
+
+ const std::string& getHelpMessageForArgument() const;
+ };
+ // A list of acceptable command line options
+ // key: value returned by getopt_long
+ using RegisteredOptions = std::vector<RegisteredOption>;
+
+protected:
+ Status parseArgs(const Arg &arg);
Status fetch();
- void postprocess();
- void dump();
+ virtual void postprocess();
+ Status dump();
void putEntry(TableEntrySource source, TableEntry &&entry);
Status fetchPassthrough(const sp<::android::hidl::manager::V1_0::IServiceManager> &manager);
Status fetchBinderized(const sp<::android::hidl::manager::V1_0::IServiceManager> &manager);
Status fetchAllLibraries(const sp<::android::hidl::manager::V1_0::IServiceManager> &manager);
- struct PidInfo {
- std::map<uint64_t, Pids> refPids; // pids that are referenced
- uint32_t threadUsage; // number of threads in use
- uint32_t threadCount; // number of threads total
- };
- bool getPidInfo(pid_t serverPid, PidInfo *info) const;
+ Status fetchBinderizedEntry(const sp<::android::hidl::manager::V1_0::IServiceManager> &manager,
+ TableEntry *entry);
- void dumpTable();
- void dumpVintf() const;
- void printLine(
- const std::string &interfaceName,
- const std::string &transport,
- const std::string &arch,
- const std::string &threadUsage,
- const std::string &server,
- const std::string &serverCmdline,
- const std::string &address,
- const std::string &clients,
- const std::string &clientCmdlines) const;
+ // Get relevant information for a PID by parsing files under /d/binder.
+ // It is a virtual member function so that it can be mocked.
+ virtual bool getPidInfo(pid_t serverPid, PidInfo *info) const;
+ // Retrieve from mCachedPidInfos and call getPidInfo if necessary.
+ const PidInfo* getPidInfoCached(pid_t serverPid);
+
+ void dumpTable(const NullableOStream<std::ostream>& out) const;
+ void dumpVintf(const NullableOStream<std::ostream>& out) const;
+ void addLine(TextTable *table, const std::string &interfaceName, const std::string &transport,
+ const std::string &arch, const std::string &threadUsage, const std::string &server,
+ const std::string &serverCmdline, const std::string &address,
+ const std::string &clients, const std::string &clientCmdlines) const;
+ void addLine(TextTable *table, const TableEntry &entry);
+ // Read and return /proc/{pid}/cmdline.
+ virtual std::string parseCmdline(pid_t pid) const;
// Return /proc/{pid}/cmdline if it exists, else empty string.
const std::string &getCmdline(pid_t pid);
// Call getCmdline on all pid in pids. If it returns empty string, the process might
@@ -76,21 +111,18 @@
void forEachTable(const std::function<void(Table &)> &f);
void forEachTable(const std::function<void(const Table &)> &f) const;
- Lshal &mLshal;
+ NullableOStream<std::ostream> err() const;
+ NullableOStream<std::ostream> out() const;
+
+ void registerAllOptions();
Table mServicesTable{};
Table mPassthroughRefTable{};
Table mImplementationsTable{};
- NullableOStream<std::ostream> mErr;
- NullableOStream<std::ostream> mOut;
- NullableOStream<std::ofstream> mFileOutput = nullptr;
+ std::string mFileOutputPath;
TableEntryCompare mSortColumn = nullptr;
- TableEntrySelect mSelectedColumns = 0;
- // If true, cmdlines will be printed instead of pid.
- bool mEnableCmdlines = false;
- // If true, calls IBase::debug(...) on each service.
bool mEmitDebugInfo = false;
// If true, output in VINTF format.
@@ -104,6 +136,16 @@
// If an entry exist and not empty, it contains the cached content of /proc/{pid}/cmdline.
std::map<pid_t, std::string> mCmdlines;
+ // Cache for getPidInfo.
+ std::map<pid_t, PidInfo> mCachedPidInfos;
+
+ RegisteredOptions mOptions;
+ // All selected columns
+ std::vector<TableColumnType> mSelectedColumns;
+ // If true, emit cmdlines instead of PIDs
+ bool mEnableCmdlines = false;
+
+private:
DISALLOW_COPY_AND_ASSIGN(ListCommand);
};
diff --git a/cmds/lshal/Lshal.cpp b/cmds/lshal/Lshal.cpp
index e2d5f6d..c6f28ac 100644
--- a/cmds/lshal/Lshal.cpp
+++ b/cmds/lshal/Lshal.cpp
@@ -34,9 +34,8 @@
using ::android::hidl::manager::V1_0::IServiceManager;
Lshal::Lshal()
- : mOut(std::cout), mErr(std::cerr),
- mServiceManager(::android::hardware::defaultServiceManager()),
- mPassthroughManager(::android::hardware::getPassthroughServiceManager()) {
+ : Lshal(std::cout, std::cerr, ::android::hardware::defaultServiceManager(),
+ ::android::hardware::getPassthroughServiceManager()) {
}
Lshal::Lshal(std::ostream &out, std::ostream &err,
@@ -46,76 +45,39 @@
mServiceManager(serviceManager),
mPassthroughManager(passthroughManager) {
+ mRegisteredCommands.push_back({std::make_unique<ListCommand>(*this)});
+ mRegisteredCommands.push_back({std::make_unique<DebugCommand>(*this)});
+ mRegisteredCommands.push_back({std::make_unique<HelpCommand>(*this)});
}
-void Lshal::usage(const std::string &command) const {
- static const std::string helpSummary =
- "lshal: List and debug HALs.\n"
- "\n"
- "commands:\n"
- " help Print help message\n"
- " list list HALs\n"
- " debug debug a specified HAL\n"
- "\n"
- "If no command is specified, `list` is the default.\n";
+void Lshal::forEachCommand(const std::function<void(const Command* c)>& f) const {
+ for (const auto& e : mRegisteredCommands) f(e.get());
+}
- static const std::string list =
- "list:\n"
- " lshal\n"
- " lshal list\n"
- " List all hals with default ordering and columns (`lshal list -ipc`)\n"
- " lshal list [-h|--help]\n"
- " -h, --help: Print help message for list (`lshal help list`)\n"
- " lshal [list] [--interface|-i] [--transport|-t] [-r|--arch] [-e|--threads]\n"
- " [--pid|-p] [--address|-a] [--clients|-c] [--cmdline|-m]\n"
- " [--sort={interface|i|pid|p}] [--init-vintf[=<output file>]]\n"
- " [--debug|-d[=<output file>]]\n"
- " -i, --interface: print the interface name column\n"
- " -n, --instance: print the instance name column\n"
- " -t, --transport: print the transport mode column\n"
- " -r, --arch: print if the HAL is in 64-bit or 32-bit\n"
- " -e, --threads: print currently used/available threads\n"
- " (note, available threads created lazily)\n"
- " -p, --pid: print the server PID, or server cmdline if -m is set\n"
- " -a, --address: print the server object address column\n"
- " -c, --clients: print the client PIDs, or client cmdlines if -m is set\n"
- " -m, --cmdline: print cmdline instead of PIDs\n"
- " -d[=<output file>], --debug[=<output file>]: emit debug info from \n"
- " IBase::debug with empty options\n"
- " --sort=i, --sort=interface: sort by interface name\n"
- " --sort=p, --sort=pid: sort by server pid\n"
- " --init-vintf=<output file>: form a skeleton HAL manifest to specified\n"
- " file, or stdout if no file specified.\n";
+void Lshal::usage() {
+ err() << "lshal: List and debug HALs." << std::endl << std::endl
+ << "commands:" << std::endl;
- static const std::string debug =
- "debug:\n"
- " lshal debug <interface> [options [options [...]]] \n"
- " Print debug information of a specified interface.\n"
- " <inteface>: Format is `android.hardware.foo@1.0::IFoo/default`.\n"
- " If instance name is missing `default` is used.\n"
- " options: space separated options to IBase::debug.\n";
+ size_t nameMaxLength = 0;
+ forEachCommand([&](const Command* e) {
+ nameMaxLength = std::max(nameMaxLength, e->getName().length());
+ });
+ bool first = true;
+ forEachCommand([&](const Command* e) {
+ if (!first) err() << std::endl;
+ first = false;
+ err() << " " << std::left << std::setw(nameMaxLength + 8) << e->getName()
+ << e->getSimpleDescription();
+ });
+ err() << std::endl << "If no command is specified, `" << ListCommand::GetName()
+ << "` is the default." << std::endl << std::endl;
- static const std::string help =
- "help:\n"
- " lshal -h\n"
- " lshal --help\n"
- " lshal help\n"
- " Print this help message\n"
- " lshal help list\n"
- " Print help message for list\n"
- " lshal help debug\n"
- " Print help message for debug\n";
-
- if (command == "list") {
- mErr << list;
- return;
- }
- if (command == "debug") {
- mErr << debug;
- return;
- }
-
- mErr << helpSummary << "\n" << list << "\n" << debug << "\n" << help;
+ first = true;
+ forEachCommand([&](const Command* e) {
+ if (!first) err() << std::endl;
+ first = false;
+ e->usage();
+ });
}
// A unique_ptr type using a custom deleter function.
@@ -186,26 +148,24 @@
}
Status Lshal::parseArgs(const Arg &arg) {
- static std::set<std::string> sAllCommands{"list", "debug", "help"};
optind = 1;
if (optind >= arg.argc) {
// no options at all.
return OK;
}
mCommand = arg.argv[optind];
- if (sAllCommands.find(mCommand) != sAllCommands.end()) {
+ if (selectCommand(mCommand) != nullptr) {
++optind;
return OK; // mCommand is set correctly
}
if (mCommand.size() > 0 && mCommand[0] == '-') {
// first argument is an option, set command to "" (which is recognized as "list")
- mCommand = "";
+ mCommand.clear();
return OK;
}
- mErr << arg.argv[0] << ": unrecognized option `" << arg.argv[optind] << "`" << std::endl;
- usage();
+ err() << arg.argv[0] << ": unrecognized option `" << arg.argv[optind] << "'" << std::endl;
return USAGE;
}
@@ -216,27 +176,43 @@
}
}
+Command* Lshal::selectCommand(const std::string& command) const {
+ if (command.empty()) {
+ return selectCommand(ListCommand::GetName());
+ }
+ for (const auto& e : mRegisteredCommands) {
+ if (e->getName() == command) {
+ return e.get();
+ }
+ }
+ return nullptr;
+}
+
Status Lshal::main(const Arg &arg) {
// Allow SIGINT to terminate all threads.
signal(SIGINT, signalHandler);
Status status = parseArgs(arg);
if (status != OK) {
+ usage();
return status;
}
- if (mCommand == "help") {
- usage(optind < arg.argc ? arg.argv[optind] : "");
+ auto c = selectCommand(mCommand);
+ if (c == nullptr) {
+ // unknown command, print global usage
+ usage();
return USAGE;
}
- // Default command is list
- if (mCommand == "list" || mCommand == "") {
- return ListCommand{*this}.main(mCommand, arg);
+ status = c->main(arg);
+ if (status == USAGE) {
+ // bad options. Run `lshal help ${mCommand}` instead.
+ // For example, `lshal --unknown-option` becomes `lshal help` (prints global help)
+ // and `lshal list --unknown-option` becomes `lshal help list`
+ auto&& help = selectCommand(HelpCommand::GetName());
+ return static_cast<HelpCommand*>(help)->usageOfCommand(mCommand);
}
- if (mCommand == "debug") {
- return DebugCommand{*this}.main(mCommand, arg);
- }
- usage();
- return USAGE;
+
+ return status;
}
NullableOStream<std::ostream> Lshal::err() const {
diff --git a/cmds/lshal/Lshal.h b/cmds/lshal/Lshal.h
index 00db5d0..690f30e 100644
--- a/cmds/lshal/Lshal.h
+++ b/cmds/lshal/Lshal.h
@@ -24,6 +24,8 @@
#include <android/hidl/manager/1.0/IServiceManager.h>
#include <utils/StrongPointer.h>
+#include "Command.h"
+#include "HelpCommand.h"
#include "NullableOStream.h"
#include "utils.h"
@@ -33,13 +35,15 @@
class Lshal {
public:
Lshal();
+ virtual ~Lshal() {}
Lshal(std::ostream &out, std::ostream &err,
sp<hidl::manager::V1_0::IServiceManager> serviceManager,
sp<hidl::manager::V1_0::IServiceManager> passthroughManager);
Status main(const Arg &arg);
- void usage(const std::string &command = "") const;
- NullableOStream<std::ostream> err() const;
- NullableOStream<std::ostream> out() const;
+ // global usage
+ void usage();
+ virtual NullableOStream<std::ostream> err() const;
+ virtual NullableOStream<std::ostream> out() const;
const sp<hidl::manager::V1_0::IServiceManager> &serviceManager() const;
const sp<hidl::manager::V1_0::IServiceManager> &passthroughManager() const;
@@ -49,16 +53,23 @@
const std::vector<std::string> &options,
std::ostream &out,
NullableOStream<std::ostream> err) const;
+
+ Command* selectCommand(const std::string& command) const;
+
+ void forEachCommand(const std::function<void(const Command* c)>& f) const;
+
private:
Status parseArgs(const Arg &arg);
+
std::string mCommand;
- Arg mCmdArgs;
NullableOStream<std::ostream> mOut;
NullableOStream<std::ostream> mErr;
sp<hidl::manager::V1_0::IServiceManager> mServiceManager;
sp<hidl::manager::V1_0::IServiceManager> mPassthroughManager;
+ std::vector<std::unique_ptr<Command>> mRegisteredCommands;
+
DISALLOW_COPY_AND_ASSIGN(Lshal);
};
diff --git a/cmds/lshal/PipeRelay.cpp b/cmds/lshal/PipeRelay.cpp
index 54d19f6..fc40749 100644
--- a/cmds/lshal/PipeRelay.cpp
+++ b/cmds/lshal/PipeRelay.cpp
@@ -57,8 +57,7 @@
////////////////////////////////////////////////////////////////////////////////
PipeRelay::PipeRelay(std::ostream &os)
- : mOutStream(os),
- mInitCheck(NO_INIT) {
+ : mInitCheck(NO_INIT) {
int res = socketpair(AF_UNIX, SOCK_STREAM, 0 /* protocol */, mFds);
if (res < 0) {
diff --git a/cmds/lshal/PipeRelay.h b/cmds/lshal/PipeRelay.h
index 76b2b23..8dc3093 100644
--- a/cmds/lshal/PipeRelay.h
+++ b/cmds/lshal/PipeRelay.h
@@ -42,7 +42,6 @@
private:
struct RelayThread;
- std::ostream &mOutStream;
status_t mInitCheck;
int mFds[2];
sp<RelayThread> mThread;
diff --git a/cmds/lshal/TableEntry.cpp b/cmds/lshal/TableEntry.cpp
new file mode 100644
index 0000000..e8792a4
--- /dev/null
+++ b/cmds/lshal/TableEntry.cpp
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 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.
+ */
+#define LOG_TAG "lshal"
+#include <android-base/logging.h>
+
+#include <hidl-hash/Hash.h>
+
+#include "TableEntry.h"
+
+#include "TextTable.h"
+#include "utils.h"
+
+namespace android {
+namespace lshal {
+
+static const std::string &getArchString(Architecture arch) {
+ static const std::string sStr64 = "64";
+ static const std::string sStr32 = "32";
+ static const std::string sStrBoth = "32+64";
+ static const std::string sStrUnknown = "";
+ switch (arch) {
+ case ARCH64:
+ return sStr64;
+ case ARCH32:
+ return sStr32;
+ case ARCH_BOTH:
+ return sStrBoth;
+ case ARCH_UNKNOWN: // fall through
+ default:
+ return sStrUnknown;
+ }
+}
+
+static std::string getTitle(TableColumnType type) {
+ switch (type) {
+ case TableColumnType::INTERFACE_NAME: return "Interface";
+ case TableColumnType::TRANSPORT: return "Transport";
+ case TableColumnType::SERVER_PID: return "Server";
+ case TableColumnType::SERVER_CMD: return "Server CMD";
+ case TableColumnType::SERVER_ADDR: return "PTR";
+ case TableColumnType::CLIENT_PIDS: return "Clients";
+ case TableColumnType::CLIENT_CMDS: return "Clients CMD";
+ case TableColumnType::ARCH: return "Arch";
+ case TableColumnType::THREADS: return "Thread Use";
+ case TableColumnType::RELEASED: return "R";
+ case TableColumnType::HASH: return "Hash";
+ default:
+ LOG(FATAL) << __func__ << "Should not reach here. " << static_cast<int>(type);
+ return "";
+ }
+}
+
+std::string TableEntry::getField(TableColumnType type) const {
+ switch (type) {
+ case TableColumnType::INTERFACE_NAME:
+ return interfaceName;
+ case TableColumnType::TRANSPORT:
+ return transport;
+ case TableColumnType::SERVER_PID:
+ return serverPid == NO_PID ? "N/A" : std::to_string(serverPid);
+ case TableColumnType::SERVER_CMD:
+ return serverCmdline;
+ case TableColumnType::SERVER_ADDR:
+ return serverObjectAddress == NO_PTR ? "N/A" : toHexString(serverObjectAddress);
+ case TableColumnType::CLIENT_PIDS:
+ return join(clientPids, " ");
+ case TableColumnType::CLIENT_CMDS:
+ return join(clientCmdlines, ";");
+ case TableColumnType::ARCH:
+ return getArchString(arch);
+ case TableColumnType::THREADS:
+ return getThreadUsage();
+ case TableColumnType::RELEASED:
+ return isReleased();
+ case TableColumnType::HASH:
+ return hash;
+ default:
+ LOG(FATAL) << __func__ << "Should not reach here. " << static_cast<int>(type);
+ return "";
+ }
+}
+
+std::string TableEntry::isReleased() const {
+ static const std::string unreleased = Hash::hexString(Hash::kEmptyHash);
+
+ if (hash.empty() || hash == unreleased) {
+ return " "; // unknown or unreleased
+ }
+ return "Y"; // released
+}
+
+TextTable Table::createTextTable(bool neat,
+ const std::function<std::string(const std::string&)>& emitDebugInfo) const {
+
+ TextTable textTable;
+ std::vector<std::string> row;
+ if (!neat) {
+ textTable.add(mDescription);
+
+ row.clear();
+ for (TableColumnType type : mSelectedColumns) {
+ row.push_back(getTitle(type));
+ }
+ textTable.add(std::move(row));
+ }
+
+ for (const auto& entry : mEntries) {
+ row.clear();
+ for (TableColumnType type : mSelectedColumns) {
+ row.push_back(entry.getField(type));
+ }
+ textTable.add(std::move(row));
+
+ if (emitDebugInfo) {
+ std::string debugInfo = emitDebugInfo(entry.interfaceName);
+ if (!debugInfo.empty()) textTable.add(debugInfo);
+ }
+ }
+ return textTable;
+}
+
+TextTable MergedTable::createTextTable() {
+ TextTable textTable;
+ for (const Table* table : mTables) {
+ textTable.addAll(table->createTextTable());
+ }
+ return textTable;
+}
+
+bool TableEntry::operator==(const TableEntry& other) const {
+ if (this == &other) {
+ return true;
+ }
+ return interfaceName == other.interfaceName && transport == other.transport &&
+ serverPid == other.serverPid && threadUsage == other.threadUsage &&
+ threadCount == other.threadCount && serverCmdline == other.serverCmdline &&
+ serverObjectAddress == other.serverObjectAddress && clientPids == other.clientPids &&
+ clientCmdlines == other.clientCmdlines && arch == other.arch;
+}
+
+std::string TableEntry::to_string() const {
+ std::stringstream ss;
+ ss << "name=" << interfaceName << ";transport=" << transport << ";thread=" << getThreadUsage()
+ << ";server=" << serverPid
+ << "(" << serverObjectAddress << ";" << serverCmdline << ");clients=["
+ << join(clientPids, ";") << "](" << join(clientCmdlines, ";") << ");arch="
+ << getArchString(arch);
+ return ss.str();
+
+}
+
+} // namespace lshal
+} // namespace android
diff --git a/cmds/lshal/TableEntry.h b/cmds/lshal/TableEntry.h
index e04c3ca..69206cc 100644
--- a/cmds/lshal/TableEntry.h
+++ b/cmds/lshal/TableEntry.h
@@ -23,6 +23,8 @@
#include <vector>
#include <iostream>
+#include "TextTable.h"
+
namespace android {
namespace lshal {
@@ -43,17 +45,38 @@
};
using Architecture = unsigned int;
+enum class TableColumnType : unsigned int {
+ INTERFACE_NAME,
+ TRANSPORT,
+ SERVER_PID,
+ SERVER_CMD,
+ SERVER_ADDR,
+ CLIENT_PIDS,
+ CLIENT_CMDS,
+ ARCH,
+ THREADS,
+ RELEASED,
+ HASH,
+};
+
+enum {
+ NO_PID = -1,
+ NO_PTR = 0
+};
+
struct TableEntry {
- std::string interfaceName;
- std::string transport;
- int32_t serverPid;
- uint32_t threadUsage;
- uint32_t threadCount;
- std::string serverCmdline;
- uint64_t serverObjectAddress;
- Pids clientPids;
- std::vector<std::string> clientCmdlines;
- Architecture arch;
+ std::string interfaceName{};
+ std::string transport{};
+ int32_t serverPid{NO_PID};
+ uint32_t threadUsage{0};
+ uint32_t threadCount{0};
+ std::string serverCmdline{};
+ uint64_t serverObjectAddress{NO_PTR};
+ Pids clientPids{};
+ std::vector<std::string> clientCmdlines{};
+ Architecture arch{ARCH_UNKNOWN};
+ // empty: unknown, all zeros: unreleased, otherwise: released
+ std::string hash{};
static bool sortByInterfaceName(const TableEntry &a, const TableEntry &b) {
return a.interfaceName < b.interfaceName;
@@ -69,36 +92,52 @@
return std::to_string(threadUsage) + "/" + std::to_string(threadCount);
}
+
+ std::string isReleased() const;
+
+ std::string getField(TableColumnType type) const;
+
+ bool operator==(const TableEntry& other) const;
+ std::string to_string() const;
};
-struct Table {
- using Entries = std::vector<TableEntry>;
- std::string description;
- Entries entries;
+using SelectedColumns = std::vector<TableColumnType>;
- Entries::iterator begin() { return entries.begin(); }
- Entries::const_iterator begin() const { return entries.begin(); }
- Entries::iterator end() { return entries.end(); }
- Entries::const_iterator end() const { return entries.end(); }
+class Table {
+public:
+ using Entries = std::vector<TableEntry>;
+
+ Entries::iterator begin() { return mEntries.begin(); }
+ Entries::const_iterator begin() const { return mEntries.begin(); }
+ Entries::iterator end() { return mEntries.end(); }
+ Entries::const_iterator end() const { return mEntries.end(); }
+ size_t size() const { return mEntries.size(); }
+
+ void add(TableEntry&& entry) { mEntries.push_back(std::move(entry)); }
+
+ void setSelectedColumns(const SelectedColumns& s) { mSelectedColumns = s; }
+ const SelectedColumns& getSelectedColumns() const { return mSelectedColumns; }
+
+ void setDescription(std::string&& d) { mDescription = std::move(d); }
+
+ // Write table content.
+ TextTable createTextTable(bool neat = true,
+ const std::function<std::string(const std::string&)>& emitDebugInfo = nullptr) const;
+
+private:
+ std::string mDescription;
+ Entries mEntries;
+ SelectedColumns mSelectedColumns;
};
using TableEntryCompare = std::function<bool(const TableEntry &, const TableEntry &)>;
-enum : unsigned int {
- ENABLE_INTERFACE_NAME = 1 << 0,
- ENABLE_TRANSPORT = 1 << 1,
- ENABLE_SERVER_PID = 1 << 2,
- ENABLE_SERVER_ADDR = 1 << 3,
- ENABLE_CLIENT_PIDS = 1 << 4,
- ENABLE_ARCH = 1 << 5,
- ENABLE_THREADS = 1 << 6,
-};
-
-using TableEntrySelect = unsigned int;
-
-enum {
- NO_PID = -1,
- NO_PTR = 0
+class MergedTable {
+public:
+ MergedTable(std::vector<const Table*>&& tables) : mTables(std::move(tables)) {}
+ TextTable createTextTable();
+private:
+ std::vector<const Table*> mTables;
};
} // namespace lshal
diff --git a/cmds/lshal/TextTable.cpp b/cmds/lshal/TextTable.cpp
new file mode 100644
index 0000000..eca9061
--- /dev/null
+++ b/cmds/lshal/TextTable.cpp
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 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 <algorithm>
+#include <iomanip>
+
+#include "TextTable.h"
+
+namespace android {
+namespace lshal {
+
+void TextTable::computeWidth(const std::vector<std::string>& v) {
+ if (mWidths.size() < v.size()) {
+ mWidths.resize(v.size());
+ }
+ for (size_t i = 0; i < v.size(); ++i) {
+ mWidths[i] = std::max(mWidths[i], v[i].length());
+ }
+}
+
+void TextTable::dump(std::ostream& out) const {
+ out << std::left;
+ for (const auto& row : mTable) {
+ if (!row.isRow()) {
+ out << row.line() << std::endl;
+ continue;
+ }
+
+ for (size_t i = 0; i < row.fields().size(); ++i) {
+ if (i != 0) {
+ out << " ";
+ }
+ // last column does not std::setw to avoid printing unnecessary spaces.
+ if (i < row.fields().size() - 1) {
+ out << std::setw(mWidths[i]);
+ }
+ out << row.fields()[i];
+ }
+ out << std::endl;
+ }
+}
+
+void TextTable::addAll(TextTable&& other) {
+ for (auto&& row : other.mTable) {
+ if (row.isRow()) {
+ computeWidth(row.fields());
+ }
+
+ mTable.emplace_back(std::move(row));
+ }
+}
+
+} // namespace lshal
+} // namespace android
diff --git a/cmds/lshal/TextTable.h b/cmds/lshal/TextTable.h
new file mode 100644
index 0000000..91d522a
--- /dev/null
+++ b/cmds/lshal/TextTable.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef FRAMEWORK_NATIVE_CMDS_LSHAL_TEXT_TABLE_H_
+#define FRAMEWORK_NATIVE_CMDS_LSHAL_TEXT_TABLE_H_
+
+#include <iostream>
+#include <string>
+#include <vector>
+
+namespace android {
+namespace lshal {
+
+// An element in TextTable. This is either an actual row (an array of cells
+// in this row), or a string of explanatory text.
+// To see if this is an actual row, test fields().empty().
+class TextTableRow {
+public:
+ // An empty line.
+ TextTableRow() {}
+
+ // A row of cells.
+ TextTableRow(std::vector<std::string>&& v) : mFields(std::move(v)) {}
+
+ // A single comment string.
+ TextTableRow(std::string&& s) : mLine(std::move(s)) {}
+ TextTableRow(const std::string& s) : mLine(s) {}
+
+ // Whether this row is an actual row of cells.
+ bool isRow() const { return !fields().empty(); }
+
+ // Get all cells.
+ const std::vector<std::string>& fields() const { return mFields; }
+
+ // Get the single comment string.
+ const std::string& line() const { return mLine; }
+
+private:
+ std::vector<std::string> mFields;
+ std::string mLine;
+};
+
+// A TextTable is a 2D array of strings.
+class TextTable {
+public:
+
+ // Add a TextTableRow.
+ void add() { mTable.emplace_back(); }
+ void add(std::vector<std::string>&& v) {
+ computeWidth(v);
+ mTable.emplace_back(std::move(v));
+ }
+ void add(const std::string& s) { mTable.emplace_back(s); }
+ void add(std::string&& s) { mTable.emplace_back(std::move(s)); }
+
+ void addAll(TextTable&& other);
+
+ // Prints the table to out, with column widths adjusted appropriately according
+ // to the content.
+ void dump(std::ostream& out) const;
+
+private:
+ void computeWidth(const std::vector<std::string>& v);
+ std::vector<size_t> mWidths;
+ std::vector<TextTableRow> mTable;
+};
+
+} // namespace lshal
+} // namespace android
+
+#endif // FRAMEWORK_NATIVE_CMDS_LSHAL_TEXT_TABLE_H_
diff --git a/cmds/lshal/test.cpp b/cmds/lshal/test.cpp
index 972d508..9220fc0 100644
--- a/cmds/lshal/test.cpp
+++ b/cmds/lshal/test.cpp
@@ -26,21 +26,29 @@
#include <gmock/gmock.h>
#include <android/hardware/tests/baz/1.0/IQuux.h>
#include <hidl/HidlTransportSupport.h>
+#include <vintf/parse_xml.h>
+#include "ListCommand.h"
#include "Lshal.h"
#define NELEMS(array) static_cast<int>(sizeof(array) / sizeof(array[0]))
using namespace testing;
+using ::android::hidl::base::V1_0::DebugInfo;
using ::android::hidl::base::V1_0::IBase;
using ::android::hidl::manager::V1_0::IServiceManager;
using ::android::hidl::manager::V1_0::IServiceNotification;
+using ::android::hardware::hidl_array;
using ::android::hardware::hidl_death_recipient;
using ::android::hardware::hidl_handle;
using ::android::hardware::hidl_string;
using ::android::hardware::hidl_vec;
+using InstanceDebugInfo = IServiceManager::InstanceDebugInfo;
+
+using hidl_hash = hidl_array<uint8_t, 32>;
+
namespace android {
namespace hardware {
namespace tests {
@@ -76,7 +84,6 @@
namespace lshal {
-
class MockServiceManager : public IServiceManager {
public:
template<typename T>
@@ -107,7 +114,7 @@
};
-class LshalTest : public ::testing::Test {
+class DebugTest : public ::testing::Test {
public:
void SetUp() override {
using ::android::hardware::tests::baz::V1_0::IQuux;
@@ -122,43 +129,545 @@
return new Quux();
return nullptr;
}));
+
+ lshal = std::make_unique<Lshal>(out, err, serviceManager, serviceManager);
}
void TearDown() override {}
std::stringstream err;
std::stringstream out;
sp<MockServiceManager> serviceManager;
+
+ std::unique_ptr<Lshal> lshal;
};
-TEST_F(LshalTest, Debug) {
- const char *args[] = {
+static Arg createArg(const std::vector<const char*>& args) {
+ return Arg{static_cast<int>(args.size()), const_cast<char**>(args.data())};
+}
+
+template<typename T>
+static Status callMain(const std::unique_ptr<T>& lshal, const std::vector<const char*>& args) {
+ return lshal->main(createArg(args));
+}
+
+TEST_F(DebugTest, Debug) {
+ EXPECT_EQ(0u, callMain(lshal, {
"lshal", "debug", "android.hardware.tests.baz@1.0::IQuux/default", "foo", "bar"
- };
- EXPECT_EQ(0u, Lshal(out, err, serviceManager, serviceManager)
- .main({NELEMS(args), const_cast<char **>(args)}));
+ }));
EXPECT_THAT(out.str(), StrEq("android.hardware.tests.baz@1.0::IQuux\nfoo\nbar"));
EXPECT_THAT(err.str(), IsEmpty());
}
-TEST_F(LshalTest, Debug2) {
- const char *args[] = {
+TEST_F(DebugTest, Debug2) {
+ EXPECT_EQ(0u, callMain(lshal, {
"lshal", "debug", "android.hardware.tests.baz@1.0::IQuux", "baz", "quux"
- };
- EXPECT_EQ(0u, Lshal(out, err, serviceManager, serviceManager)
- .main({NELEMS(args), const_cast<char **>(args)}));
+ }));
EXPECT_THAT(out.str(), StrEq("android.hardware.tests.baz@1.0::IQuux\nbaz\nquux"));
EXPECT_THAT(err.str(), IsEmpty());
}
-TEST_F(LshalTest, Debug3) {
- const char *args[] = {
+TEST_F(DebugTest, Debug3) {
+ EXPECT_NE(0u, callMain(lshal, {
"lshal", "debug", "android.hardware.tests.doesnotexist@1.0::IDoesNotExist",
- };
- EXPECT_NE(0u, Lshal(out, err, serviceManager, serviceManager)
- .main({NELEMS(args), const_cast<char **>(args)}));
+ }));
EXPECT_THAT(err.str(), HasSubstr("does not exist"));
}
+class MockLshal : public Lshal {
+public:
+ MockLshal() {}
+ ~MockLshal() = default;
+ MOCK_CONST_METHOD0(out, NullableOStream<std::ostream>());
+ MOCK_CONST_METHOD0(err, NullableOStream<std::ostream>());
+};
+
+// expose protected fields and methods for ListCommand
+class MockListCommand : public ListCommand {
+public:
+ MockListCommand(Lshal* lshal) : ListCommand(*lshal) {}
+
+ Status parseArgs(const Arg& arg) { return ListCommand::parseArgs(arg); }
+ Status main(const Arg& arg) { return ListCommand::main(arg); }
+ void forEachTable(const std::function<void(Table &)> &f) {
+ return ListCommand::forEachTable(f);
+ }
+ void forEachTable(const std::function<void(const Table &)> &f) const {
+ return ListCommand::forEachTable(f);
+ }
+ Status fetch() { return ListCommand::fetch(); }
+ void dumpVintf(const NullableOStream<std::ostream>& out) {
+ return ListCommand::dumpVintf(out);
+ }
+ void internalPostprocess() { ListCommand::postprocess(); }
+ const PidInfo* getPidInfoCached(pid_t serverPid) {
+ return ListCommand::getPidInfoCached(serverPid);
+ }
+
+ MOCK_METHOD0(postprocess, void());
+ MOCK_CONST_METHOD2(getPidInfo, bool(pid_t, PidInfo*));
+ MOCK_CONST_METHOD1(parseCmdline, std::string(pid_t));
+};
+
+class ListParseArgsTest : public ::testing::Test {
+public:
+ void SetUp() override {
+ mockLshal = std::make_unique<NiceMock<MockLshal>>();
+ mockList = std::make_unique<MockListCommand>(mockLshal.get());
+ // ListCommand::parseArgs should parse arguments from the second element
+ optind = 1;
+ }
+ std::unique_ptr<MockLshal> mockLshal;
+ std::unique_ptr<MockListCommand> mockList;
+ std::stringstream output;
+};
+
+TEST_F(ListParseArgsTest, Args) {
+ EXPECT_EQ(0u, mockList->parseArgs(createArg({"lshal", "-p", "-i", "-a", "-c"})));
+ mockList->forEachTable([](const Table& table) {
+ EXPECT_EQ(SelectedColumns({TableColumnType::SERVER_PID, TableColumnType::INTERFACE_NAME,
+ TableColumnType::SERVER_ADDR, TableColumnType::CLIENT_PIDS}),
+ table.getSelectedColumns());
+ });
+}
+
+TEST_F(ListParseArgsTest, Cmds) {
+ EXPECT_EQ(0u, mockList->parseArgs(createArg({"lshal", "-m"})));
+ mockList->forEachTable([](const Table& table) {
+ EXPECT_THAT(table.getSelectedColumns(), Not(Contains(TableColumnType::SERVER_PID)))
+ << "should not print server PID with -m";
+ EXPECT_THAT(table.getSelectedColumns(), Not(Contains(TableColumnType::CLIENT_PIDS)))
+ << "should not print client PIDs with -m";
+ EXPECT_THAT(table.getSelectedColumns(), Contains(TableColumnType::SERVER_CMD))
+ << "should print server cmd with -m";
+ EXPECT_THAT(table.getSelectedColumns(), Contains(TableColumnType::CLIENT_CMDS))
+ << "should print client cmds with -m";
+ });
+}
+
+TEST_F(ListParseArgsTest, DebugAndNeat) {
+ ON_CALL(*mockLshal, err()).WillByDefault(Return(NullableOStream<std::ostream>(output)));
+ EXPECT_NE(0u, mockList->parseArgs(createArg({"lshal", "--neat", "-d"})));
+ EXPECT_THAT(output.str(), StrNe(""));
+}
+
+/// Fetch Test
+
+// A set of deterministic functions to generate fake debug infos.
+static uint64_t getPtr(pid_t serverId) { return 10000 + serverId; }
+static std::vector<pid_t> getClients(pid_t serverId) {
+ return {serverId + 1, serverId + 3};
+}
+static PidInfo getPidInfoFromId(pid_t serverId) {
+ PidInfo info;
+ info.refPids[getPtr(serverId)] = getClients(serverId);
+ info.threadUsage = 10 + serverId;
+ info.threadCount = 20 + serverId;
+ return info;
+}
+static std::string getInterfaceName(pid_t serverId) {
+ return "a.h.foo" + std::to_string(serverId) + "@" + std::to_string(serverId) + ".0::IFoo";
+}
+static std::string getInstanceName(pid_t serverId) {
+ return std::to_string(serverId);
+}
+static pid_t getIdFromInstanceName(const hidl_string& instance) {
+ return atoi(instance.c_str());
+}
+static std::string getFqInstanceName(pid_t serverId) {
+ return getInterfaceName(serverId) + "/" + getInstanceName(serverId);
+}
+static std::string getCmdlineFromId(pid_t serverId) {
+ if (serverId == NO_PID) return "";
+ return "command_line_" + std::to_string(serverId);
+}
+static bool getIsReleasedFromId(pid_t p) { return p % 2 == 0; }
+static hidl_hash getHashFromId(pid_t serverId) {
+ hidl_hash hash;
+ bool isReleased = getIsReleasedFromId(serverId);
+ for (size_t i = 0; i < hash.size(); ++i) {
+ hash[i] = isReleased ? static_cast<uint8_t>(serverId) : 0u;
+ }
+ return hash;
+}
+
+// Fake service returned by mocked IServiceManager::get.
+class TestService : public IBase {
+public:
+ TestService(pid_t id) : mId(id) {}
+ hardware::Return<void> getDebugInfo(getDebugInfo_cb cb) override {
+ cb({ mId /* pid */, getPtr(mId), DebugInfo::Architecture::IS_64BIT });
+ return hardware::Void();
+ }
+ hardware::Return<void> interfaceChain(interfaceChain_cb cb) override {
+ cb({getInterfaceName(mId), IBase::descriptor});
+ return hardware::Void();
+ }
+ hardware::Return<void> getHashChain(getHashChain_cb cb) override {
+ cb({getHashFromId(mId), getHashFromId(0xff)});
+ return hardware::Void();
+ }
+private:
+ pid_t mId;
+};
+
+class ListTest : public ::testing::Test {
+public:
+ void SetUp() override {
+ initMockServiceManager();
+ lshal = std::make_unique<Lshal>(out, err, serviceManager, passthruManager);
+ initMockList();
+ }
+
+ void initMockList() {
+ mockList = std::make_unique<NiceMock<MockListCommand>>(lshal.get());
+ ON_CALL(*mockList, getPidInfo(_,_)).WillByDefault(Invoke(
+ [](pid_t serverPid, PidInfo* info) {
+ *info = getPidInfoFromId(serverPid);
+ return true;
+ }));
+ ON_CALL(*mockList, parseCmdline(_)).WillByDefault(Invoke(&getCmdlineFromId));
+ ON_CALL(*mockList, postprocess()).WillByDefault(Invoke([&]() {
+ mockList->internalPostprocess();
+ size_t i = 0;
+ mockList->forEachTable([&](Table& table) {
+ table.setDescription("[fake description " + std::to_string(i++) + "]");
+ });
+ }));
+ }
+
+ void initMockServiceManager() {
+ serviceManager = new testing::NiceMock<MockServiceManager>();
+ passthruManager = new testing::NiceMock<MockServiceManager>();
+ using A = DebugInfo::Architecture;
+ ON_CALL(*serviceManager, list(_)).WillByDefault(Invoke(
+ [] (IServiceManager::list_cb cb) {
+ cb({ getFqInstanceName(1), getFqInstanceName(2) });
+ return hardware::Void();
+ }));
+
+ ON_CALL(*serviceManager, get(_, _)).WillByDefault(Invoke(
+ [&](const hidl_string&, const hidl_string& instance) {
+ int id = getIdFromInstanceName(instance);
+ return sp<IBase>(new TestService(id));
+ }));
+
+ ON_CALL(*serviceManager, debugDump(_)).WillByDefault(Invoke(
+ [] (IServiceManager::debugDump_cb cb) {
+ cb({InstanceDebugInfo{getInterfaceName(3), getInstanceName(3), 3,
+ getClients(3), A::IS_32BIT},
+ InstanceDebugInfo{getInterfaceName(4), getInstanceName(4), 4,
+ getClients(4), A::IS_32BIT}});
+ return hardware::Void();
+ }));
+
+ ON_CALL(*passthruManager, debugDump(_)).WillByDefault(Invoke(
+ [] (IServiceManager::debugDump_cb cb) {
+ cb({InstanceDebugInfo{getInterfaceName(5), getInstanceName(5), 5,
+ getClients(5), A::IS_32BIT},
+ InstanceDebugInfo{getInterfaceName(6), getInstanceName(6), 6,
+ getClients(6), A::IS_32BIT}});
+ return hardware::Void();
+ }));
+ }
+
+ std::stringstream err;
+ std::stringstream out;
+ std::unique_ptr<Lshal> lshal;
+ std::unique_ptr<MockListCommand> mockList;
+ sp<MockServiceManager> serviceManager;
+ sp<MockServiceManager> passthruManager;
+};
+
+TEST_F(ListTest, GetPidInfoCached) {
+ EXPECT_CALL(*mockList, getPidInfo(5, _)).Times(1);
+
+ EXPECT_NE(nullptr, mockList->getPidInfoCached(5));
+ EXPECT_NE(nullptr, mockList->getPidInfoCached(5));
+}
+
+TEST_F(ListTest, Fetch) {
+ EXPECT_EQ(0u, mockList->fetch());
+ std::array<std::string, 6> transports{{"hwbinder", "hwbinder", "passthrough",
+ "passthrough", "passthrough", "passthrough"}};
+ std::array<Architecture, 6> archs{{ARCH64, ARCH64, ARCH32, ARCH32, ARCH32, ARCH32}};
+ int id = 1;
+ mockList->forEachTable([&](const Table& table) {
+ ASSERT_EQ(2u, table.size());
+ for (const auto& entry : table) {
+ const auto& transport = transports[id - 1];
+ TableEntry expected{
+ .interfaceName = getFqInstanceName(id),
+ .transport = transport,
+ .serverPid = transport == "hwbinder" ? id : NO_PID,
+ .threadUsage = transport == "hwbinder" ? getPidInfoFromId(id).threadUsage : 0,
+ .threadCount = transport == "hwbinder" ? getPidInfoFromId(id).threadCount : 0,
+ .serverCmdline = {},
+ .serverObjectAddress = transport == "hwbinder" ? getPtr(id) : NO_PTR,
+ .clientPids = getClients(id),
+ .clientCmdlines = {},
+ .arch = archs[id - 1],
+ };
+ EXPECT_EQ(expected, entry) << expected.to_string() << " vs. " << entry.to_string();
+
+ ++id;
+ }
+ });
+
+}
+
+TEST_F(ListTest, DumpVintf) {
+ const std::string expected =
+ "<!-- \n"
+ " This is a skeleton device manifest. Notes: \n"
+ " 1. android.hidl.*, android.frameworks.*, android.system.* are not included.\n"
+ " 2. If a HAL is supported in both hwbinder and passthrough transport, \n"
+ " only hwbinder is shown.\n"
+ " 3. It is likely that HALs in passthrough transport does not have\n"
+ " <interface> declared; users will have to write them by hand.\n"
+ " 4. A HAL with lower minor version can be overridden by a HAL with\n"
+ " higher minor version if they have the same name and major version.\n"
+ " 5. sepolicy version is set to 0.0. It is recommended that the entry\n"
+ " is removed from the manifest file and written by assemble_vintf\n"
+ " at build time.\n"
+ "-->\n"
+ "<manifest version=\"1.0\" type=\"device\">\n"
+ " <hal format=\"hidl\">\n"
+ " <name>a.h.foo1</name>\n"
+ " <transport>hwbinder</transport>\n"
+ " <version>1.0</version>\n"
+ " <interface>\n"
+ " <name>IFoo</name>\n"
+ " <instance>1</instance>\n"
+ " </interface>\n"
+ " </hal>\n"
+ " <hal format=\"hidl\">\n"
+ " <name>a.h.foo2</name>\n"
+ " <transport>hwbinder</transport>\n"
+ " <version>2.0</version>\n"
+ " <interface>\n"
+ " <name>IFoo</name>\n"
+ " <instance>2</instance>\n"
+ " </interface>\n"
+ " </hal>\n"
+ " <hal format=\"hidl\">\n"
+ " <name>a.h.foo3</name>\n"
+ " <transport arch=\"32\">passthrough</transport>\n"
+ " <version>3.0</version>\n"
+ " <interface>\n"
+ " <name>IFoo</name>\n"
+ " <instance>3</instance>\n"
+ " </interface>\n"
+ " </hal>\n"
+ " <hal format=\"hidl\">\n"
+ " <name>a.h.foo4</name>\n"
+ " <transport arch=\"32\">passthrough</transport>\n"
+ " <version>4.0</version>\n"
+ " <interface>\n"
+ " <name>IFoo</name>\n"
+ " <instance>4</instance>\n"
+ " </interface>\n"
+ " </hal>\n"
+ " <hal format=\"hidl\">\n"
+ " <name>a.h.foo5</name>\n"
+ " <transport arch=\"32\">passthrough</transport>\n"
+ " <version>5.0</version>\n"
+ " </hal>\n"
+ " <hal format=\"hidl\">\n"
+ " <name>a.h.foo6</name>\n"
+ " <transport arch=\"32\">passthrough</transport>\n"
+ " <version>6.0</version>\n"
+ " </hal>\n"
+ " <sepolicy>\n"
+ " <version>0.0</version>\n"
+ " </sepolicy>\n"
+ "</manifest>\n";
+
+ optind = 1; // mimic Lshal::parseArg()
+ EXPECT_EQ(0u, mockList->main(createArg({"lshal", "--init-vintf"})));
+ EXPECT_EQ(expected, out.str());
+ EXPECT_EQ("", err.str());
+
+ vintf::HalManifest m;
+ EXPECT_EQ(true, vintf::gHalManifestConverter(&m, out.str()))
+ << "--init-vintf does not emit valid HAL manifest: "
+ << vintf::gHalManifestConverter.lastError();
+}
+
+// test default columns
+TEST_F(ListTest, DumpDefault) {
+ const std::string expected =
+ "[fake description 0]\n"
+ "R Interface Thread Use Server Clients\n"
+ " a.h.foo1@1.0::IFoo/1 11/21 1 2 4\n"
+ "Y a.h.foo2@2.0::IFoo/2 12/22 2 3 5\n"
+ "\n"
+ "[fake description 1]\n"
+ "R Interface Thread Use Server Clients\n"
+ " a.h.foo3@3.0::IFoo/3 N/A N/A 4 6\n"
+ " a.h.foo4@4.0::IFoo/4 N/A N/A 5 7\n"
+ "\n"
+ "[fake description 2]\n"
+ "R Interface Thread Use Server Clients\n"
+ " a.h.foo5@5.0::IFoo/5 N/A N/A 6 8\n"
+ " a.h.foo6@6.0::IFoo/6 N/A N/A 7 9\n"
+ "\n";
+
+ optind = 1; // mimic Lshal::parseArg()
+ EXPECT_EQ(0u, mockList->main(createArg({"lshal"})));
+ EXPECT_EQ(expected, out.str());
+ EXPECT_EQ("", err.str());
+}
+
+TEST_F(ListTest, DumpHash) {
+ const std::string expected =
+ "[fake description 0]\n"
+ "Interface R Hash\n"
+ "a.h.foo1@1.0::IFoo/1 0000000000000000000000000000000000000000000000000000000000000000\n"
+ "a.h.foo2@2.0::IFoo/2 Y 0202020202020202020202020202020202020202020202020202020202020202\n"
+ "\n"
+ "[fake description 1]\n"
+ "Interface R Hash\n"
+ "a.h.foo3@3.0::IFoo/3 \n"
+ "a.h.foo4@4.0::IFoo/4 \n"
+ "\n"
+ "[fake description 2]\n"
+ "Interface R Hash\n"
+ "a.h.foo5@5.0::IFoo/5 \n"
+ "a.h.foo6@6.0::IFoo/6 \n"
+ "\n";
+
+ optind = 1; // mimic Lshal::parseArg()
+ EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-ils"})));
+ EXPECT_EQ(expected, out.str());
+ EXPECT_EQ("", err.str());
+}
+
+TEST_F(ListTest, Dump) {
+ const std::string expected =
+ "[fake description 0]\n"
+ "Interface Transport Arch Thread Use Server PTR Clients\n"
+ "a.h.foo1@1.0::IFoo/1 hwbinder 64 11/21 1 0000000000002711 2 4\n"
+ "a.h.foo2@2.0::IFoo/2 hwbinder 64 12/22 2 0000000000002712 3 5\n"
+ "\n"
+ "[fake description 1]\n"
+ "Interface Transport Arch Thread Use Server PTR Clients\n"
+ "a.h.foo3@3.0::IFoo/3 passthrough 32 N/A N/A N/A 4 6\n"
+ "a.h.foo4@4.0::IFoo/4 passthrough 32 N/A N/A N/A 5 7\n"
+ "\n"
+ "[fake description 2]\n"
+ "Interface Transport Arch Thread Use Server PTR Clients\n"
+ "a.h.foo5@5.0::IFoo/5 passthrough 32 N/A N/A N/A 6 8\n"
+ "a.h.foo6@6.0::IFoo/6 passthrough 32 N/A N/A N/A 7 9\n"
+ "\n";
+
+ optind = 1; // mimic Lshal::parseArg()
+ EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-itrepac"})));
+ EXPECT_EQ(expected, out.str());
+ EXPECT_EQ("", err.str());
+}
+
+TEST_F(ListTest, DumpCmdline) {
+ const std::string expected =
+ "[fake description 0]\n"
+ "Interface Transport Arch Thread Use Server CMD PTR Clients CMD\n"
+ "a.h.foo1@1.0::IFoo/1 hwbinder 64 11/21 command_line_1 0000000000002711 command_line_2;command_line_4\n"
+ "a.h.foo2@2.0::IFoo/2 hwbinder 64 12/22 command_line_2 0000000000002712 command_line_3;command_line_5\n"
+ "\n"
+ "[fake description 1]\n"
+ "Interface Transport Arch Thread Use Server CMD PTR Clients CMD\n"
+ "a.h.foo3@3.0::IFoo/3 passthrough 32 N/A N/A command_line_4;command_line_6\n"
+ "a.h.foo4@4.0::IFoo/4 passthrough 32 N/A N/A command_line_5;command_line_7\n"
+ "\n"
+ "[fake description 2]\n"
+ "Interface Transport Arch Thread Use Server CMD PTR Clients CMD\n"
+ "a.h.foo5@5.0::IFoo/5 passthrough 32 N/A N/A command_line_6;command_line_8\n"
+ "a.h.foo6@6.0::IFoo/6 passthrough 32 N/A N/A command_line_7;command_line_9\n"
+ "\n";
+
+ optind = 1; // mimic Lshal::parseArg()
+ EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-itrepacm"})));
+ EXPECT_EQ(expected, out.str());
+ EXPECT_EQ("", err.str());
+}
+
+TEST_F(ListTest, DumpNeat) {
+ const std::string expected =
+ "a.h.foo1@1.0::IFoo/1 11/21 1 2 4\n"
+ "a.h.foo2@2.0::IFoo/2 12/22 2 3 5\n"
+ "a.h.foo3@3.0::IFoo/3 N/A N/A 4 6\n"
+ "a.h.foo4@4.0::IFoo/4 N/A N/A 5 7\n"
+ "a.h.foo5@5.0::IFoo/5 N/A N/A 6 8\n"
+ "a.h.foo6@6.0::IFoo/6 N/A N/A 7 9\n";
+
+ optind = 1; // mimic Lshal::parseArg()
+ EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-iepc", "--neat"})));
+ EXPECT_EQ(expected, out.str());
+ EXPECT_EQ("", err.str());
+}
+
+class HelpTest : public ::testing::Test {
+public:
+ void SetUp() override {
+ lshal = std::make_unique<Lshal>(out, err, new MockServiceManager() /* serviceManager */,
+ new MockServiceManager() /* passthruManager */);
+ }
+
+ std::stringstream err;
+ std::stringstream out;
+ std::unique_ptr<Lshal> lshal;
+};
+
+TEST_F(HelpTest, GlobalUsage) {
+ (void)callMain(lshal, {"lshal", "--help"}); // ignore return
+ std::string errStr = err.str();
+ EXPECT_THAT(errStr, ContainsRegex("(^|\n)commands:($|\n)"))
+ << "`lshal --help` does not contain global usage";
+ EXPECT_THAT(errStr, ContainsRegex("(^|\n)list:($|\n)"))
+ << "`lshal --help` does not contain usage for 'list' command";
+ EXPECT_THAT(errStr, ContainsRegex("(^|\n)debug:($|\n)"))
+ << "`lshal --help` does not contain usage for 'debug' command";
+ EXPECT_THAT(errStr, ContainsRegex("(^|\n)help:($|\n)"))
+ << "`lshal --help` does not contain usage for 'help' command";
+
+ err.str("");
+ (void)callMain(lshal, {"lshal", "help"}); // ignore return
+ EXPECT_EQ(errStr, err.str()) << "`lshal help` should have the same output as `lshal --help`";
+
+ err.str("");
+ EXPECT_NE(0u, callMain(lshal, {"lshal", "--unknown-option"}));
+ EXPECT_THAT(err.str(), ContainsRegex("unrecognized option"));
+ EXPECT_THAT(err.str(), EndsWith(errStr))
+ << "`lshal --unknown-option` should have the same output as `lshal --help`";
+ EXPECT_EQ("", out.str());
+}
+
+TEST_F(HelpTest, UnknownOptionList1) {
+ (void)callMain(lshal, {"lshal", "help", "list"});
+ EXPECT_THAT(err.str(), ContainsRegex("(^|\n)list:($|\n)"))
+ << "`lshal help list` does not contain usage for 'list' command";
+}
+
+TEST_F(HelpTest, UnknownOptionList2) {
+ EXPECT_NE(0u, callMain(lshal, {"lshal", "list", "--unknown-option"}));
+ EXPECT_THAT(err.str(), ContainsRegex("unrecognized option"));
+ EXPECT_THAT(err.str(), ContainsRegex("(^|\n)list:($|\n)"))
+ << "`lshal list --unknown-option` does not contain usage for 'list' command";
+ EXPECT_EQ("", out.str());
+}
+
+TEST_F(HelpTest, UnknownOptionHelp1) {
+ (void)callMain(lshal, {"lshal", "help", "help"});
+ EXPECT_THAT(err.str(), ContainsRegex("(^|\n)help:($|\n)"))
+ << "`lshal help help` does not contain usage for 'help' command";
+}
+
+TEST_F(HelpTest, UnknownOptionHelp2) {
+ (void)callMain(lshal, {"lshal", "help", "--unknown-option"});
+ EXPECT_THAT(err.str(), ContainsRegex("(^|\n)help:($|\n)"))
+ << "`lshal help --unknown-option` does not contain usage for 'help' command";
+ EXPECT_EQ("", out.str());
+}
+
} // namespace lshal
} // namespace android
diff --git a/cmds/lshal/utils.h b/cmds/lshal/utils.h
index 45b922c..c09e8b1 100644
--- a/cmds/lshal/utils.h
+++ b/cmds/lshal/utils.h
@@ -29,15 +29,23 @@
enum : unsigned int {
OK = 0,
+ // Return to Lshal::main to print help info.
USAGE = 1 << 0,
+ // no service managers
NO_BINDERIZED_MANAGER = 1 << 1,
NO_PASSTHROUGH_MANAGER = 1 << 2,
+ // general error in getting information from the three sources
DUMP_BINDERIZED_ERROR = 1 << 3,
DUMP_PASSTHROUGH_ERROR = 1 << 4,
DUMP_ALL_LIBS_ERROR = 1 << 5,
+ // I/O error in reading files
IO_ERROR = 1 << 6,
+ // Interface does not exist (IServiceManager::get fails)
NO_INTERFACE = 1 << 7,
+ // Transaction error from hwbinder transactions
TRANSACTION_ERROR = 1 << 8,
+ // No transaction error, but return value is unexpected.
+ BAD_IMPL = 1 << 9,
};
using Status = unsigned int;
diff --git a/cmds/rawbu/Android.mk b/cmds/rawbu/Android.mk
index b580390..9322151 100644
--- a/cmds/rawbu/Android.mk
+++ b/cmds/rawbu/Android.mk
@@ -5,6 +5,8 @@
LOCAL_SRC_FILES:= backup.cpp
+LOCAL_CFLAGS := -Wall -Werror
+
LOCAL_SHARED_LIBRARIES := libcutils libc
LOCAL_MODULE:= rawbu
diff --git a/cmds/rawbu/backup.cpp b/cmds/rawbu/backup.cpp
index ff6719f..0072281 100644
--- a/cmds/rawbu/backup.cpp
+++ b/cmds/rawbu/backup.cpp
@@ -129,7 +129,6 @@
}
if(S_ISDIR(statBuffer.st_mode)) {
- int i;
char *newpath;
newpath = strdup(nameBuffer);
diff --git a/cmds/service/Android.bp b/cmds/service/Android.bp
index b703ed4..9513ec1 100644
--- a/cmds/service/Android.bp
+++ b/cmds/service/Android.bp
@@ -8,7 +8,11 @@
"libbinder",
],
- cflags: ["-DXP_UNIX"],
+ cflags: [
+ "-DXP_UNIX",
+ "-Wall",
+ "-Werror",
+ ],
}
cc_binary {
@@ -22,5 +26,10 @@
"libbinder",
],
- cflags: ["-DXP_UNIX", "-DVENDORSERVICES"],
+ cflags: [
+ "-DXP_UNIX",
+ "-DVENDORSERVICES",
+ "-Wall",
+ "-Werror",
+ ],
}
diff --git a/cmds/servicemanager/Android.bp b/cmds/servicemanager/Android.bp
index d3d396f..428561b 100644
--- a/cmds/servicemanager/Android.bp
+++ b/cmds/servicemanager/Android.bp
@@ -46,6 +46,6 @@
cflags: [
"-DVENDORSERVICEMANAGER=1",
],
- shared_libs: ["libcutils", "libselinux_vendor"],
+ shared_libs: ["libcutils", "libselinux"],
init_rc: ["vndservicemanager.rc"],
}
diff --git a/cmds/servicemanager/binder.c b/cmds/servicemanager/binder.c
index 93a18fc..fade8cf 100644
--- a/cmds/servicemanager/binder.c
+++ b/cmds/servicemanager/binder.c
@@ -514,7 +514,7 @@
return;
obj->flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
- obj->type = BINDER_TYPE_BINDER;
+ obj->hdr.type = BINDER_TYPE_BINDER;
obj->binder = (uintptr_t)ptr;
obj->cookie = 0;
}
@@ -532,7 +532,7 @@
return;
obj->flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
- obj->type = BINDER_TYPE_HANDLE;
+ obj->hdr.type = BINDER_TYPE_HANDLE;
obj->handle = handle;
obj->cookie = 0;
}
@@ -649,7 +649,7 @@
if (!obj)
return 0;
- if (obj->type == BINDER_TYPE_HANDLE)
+ if (obj->hdr.type == BINDER_TYPE_HANDLE)
return obj->handle;
return 0;
diff --git a/cmds/servicemanager/service_manager.c b/cmds/servicemanager/service_manager.c
index 45bb1d0..6b340a8 100644
--- a/cmds/servicemanager/service_manager.c
+++ b/cmds/servicemanager/service_manager.c
@@ -8,10 +8,9 @@
#include <stdlib.h>
#include <string.h>
+#include <cutils/android_filesystem_config.h>
#include <cutils/multiuser.h>
-#include <private/android_filesystem_config.h>
-
#include <selinux/android.h>
#include <selinux/avc.h>
@@ -139,6 +138,7 @@
uint32_t handle;
struct binder_death death;
int allow_isolated;
+ uint32_t dumpsys_priority;
size_t len;
uint16_t name[0];
};
@@ -199,11 +199,8 @@
return si->handle;
}
-int do_add_service(struct binder_state *bs,
- const uint16_t *s, size_t len,
- uint32_t handle, uid_t uid, int allow_isolated,
- pid_t spid)
-{
+int do_add_service(struct binder_state *bs, const uint16_t *s, size_t len, uint32_t handle,
+ uid_t uid, int allow_isolated, uint32_t dumpsys_priority, pid_t spid) {
struct svcinfo *si;
//ALOGI("add_service('%s',%x,%s) uid=%d\n", str8(s, len), handle,
@@ -240,6 +237,7 @@
si->death.func = (void*) svcinfo_death;
si->death.ptr = si;
si->allow_isolated = allow_isolated;
+ si->dumpsys_priority = dumpsys_priority;
si->next = svclist;
svclist = si;
}
@@ -260,6 +258,7 @@
uint32_t handle;
uint32_t strict_policy;
int allow_isolated;
+ uint32_t dumpsys_priority;
//ALOGI("target=%p code=%d pid=%d uid=%d\n",
// (void*) txn->target.ptr, txn->code, txn->sender_pid, txn->sender_euid);
@@ -287,7 +286,11 @@
}
if (sehandle && selinux_status_updated() > 0) {
+#ifdef VENDORSERVICEMANAGER
+ struct selabel_handle *tmp_sehandle = selinux_android_vendor_service_context_handle();
+#else
struct selabel_handle *tmp_sehandle = selinux_android_service_context_handle();
+#endif
if (tmp_sehandle) {
selabel_close(sehandle);
sehandle = tmp_sehandle;
@@ -314,13 +317,15 @@
}
handle = bio_get_ref(msg);
allow_isolated = bio_get_uint32(msg) ? 1 : 0;
- if (do_add_service(bs, s, len, handle, txn->sender_euid,
- allow_isolated, txn->sender_pid))
+ dumpsys_priority = bio_get_uint32(msg);
+ if (do_add_service(bs, s, len, handle, txn->sender_euid, allow_isolated, dumpsys_priority,
+ txn->sender_pid))
return -1;
break;
case SVC_MGR_LIST_SERVICES: {
uint32_t n = bio_get_uint32(msg);
+ uint32_t req_dumpsys_priority = bio_get_uint32(msg);
if (!svc_can_list(txn->sender_pid, txn->sender_euid)) {
ALOGE("list_service() uid=%d - PERMISSION DENIED\n",
@@ -328,8 +333,15 @@
return -1;
}
si = svclist;
- while ((n-- > 0) && si)
+ // walk through the list of services n times skipping services that
+ // do not support the requested priority
+ while (si) {
+ if (si->dumpsys_priority & req_dumpsys_priority) {
+ if (n == 0) break;
+ n--;
+ }
si = si->next;
+ }
if (si) {
bio_put_string16(reply, si->name);
return 0;
diff --git a/cmds/servicemanager/servicemanager.rc b/cmds/servicemanager/servicemanager.rc
index aec211a..d336a43 100644
--- a/cmds/servicemanager/servicemanager.rc
+++ b/cmds/servicemanager/servicemanager.rc
@@ -12,3 +12,4 @@
onrestart restart drm
onrestart restart cameraserver
writepid /dev/cpuset/system-background/tasks
+ shutdown critical
diff --git a/cmds/servicemanager/vndservicemanager.rc b/cmds/servicemanager/vndservicemanager.rc
index d5ddaaf..3fa4d7d 100644
--- a/cmds/servicemanager/vndservicemanager.rc
+++ b/cmds/servicemanager/vndservicemanager.rc
@@ -3,4 +3,4 @@
user system
group system readproc
writepid /dev/cpuset/system-background/tasks
-
+ shutdown critical
diff --git a/cmds/surfacereplayer/proto/Android.bp b/cmds/surfacereplayer/proto/Android.bp
index dda80bb..71a5e23 100644
--- a/cmds/surfacereplayer/proto/Android.bp
+++ b/cmds/surfacereplayer/proto/Android.bp
@@ -3,6 +3,10 @@
srcs: [
"src/trace.proto",
],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
proto: {
type: "lite",
export_proto_headers: true,
diff --git a/cmds/surfacereplayer/replayer/Replayer.cpp b/cmds/surfacereplayer/replayer/Replayer.cpp
index 35b63ec..4140f40 100644
--- a/cmds/surfacereplayer/replayer/Replayer.cpp
+++ b/cmds/surfacereplayer/replayer/Replayer.cpp
@@ -24,9 +24,9 @@
#include <gui/BufferQueue.h>
#include <gui/ISurfaceComposer.h>
+#include <gui/LayerState.h>
#include <gui/Surface.h>
#include <private/gui/ComposerService.h>
-#include <private/gui/LayerState.h>
#include <ui/DisplayInfo.h>
#include <utils/Log.h>
@@ -338,27 +338,29 @@
status_t Replayer::doTransaction(const Transaction& t, const std::shared_ptr<Event>& event) {
ALOGV("Started Transaction");
- SurfaceComposerClient::openGlobalTransaction();
+ SurfaceComposerClient::Transaction liveTransaction;
status_t status = NO_ERROR;
- status = doSurfaceTransaction(t.surface_change());
- doDisplayTransaction(t.display_change());
+ status = doSurfaceTransaction(liveTransaction, t.surface_change());
+ doDisplayTransaction(liveTransaction, t.display_change());
if (t.animation()) {
- SurfaceComposerClient::setAnimationTransaction();
+ liveTransaction.setAnimationTransaction();
}
event->readyToExecute();
- SurfaceComposerClient::closeGlobalTransaction(t.synchronous());
+ liveTransaction.apply(t.synchronous());
ALOGV("Ended Transaction");
return status;
}
-status_t Replayer::doSurfaceTransaction(const SurfaceChanges& surfaceChanges) {
+status_t Replayer::doSurfaceTransaction(
+ SurfaceComposerClient::Transaction& transaction,
+ const SurfaceChanges& surfaceChanges) {
status_t status = NO_ERROR;
for (const SurfaceChange& change : surfaceChanges) {
@@ -369,62 +371,66 @@
switch (change.SurfaceChange_case()) {
case SurfaceChange::SurfaceChangeCase::kPosition:
- status = setPosition(change.id(), change.position());
+ setPosition(transaction, change.id(), change.position());
break;
case SurfaceChange::SurfaceChangeCase::kSize:
- status = setSize(change.id(), change.size());
+ setSize(transaction, change.id(), change.size());
break;
case SurfaceChange::SurfaceChangeCase::kAlpha:
- status = setAlpha(change.id(), change.alpha());
+ setAlpha(transaction, change.id(), change.alpha());
break;
case SurfaceChange::SurfaceChangeCase::kLayer:
- status = setLayer(change.id(), change.layer());
+ setLayer(transaction, change.id(), change.layer());
break;
case SurfaceChange::SurfaceChangeCase::kCrop:
- status = setCrop(change.id(), change.crop());
+ setCrop(transaction, change.id(), change.crop());
break;
case SurfaceChange::SurfaceChangeCase::kMatrix:
- status = setMatrix(change.id(), change.matrix());
+ setMatrix(transaction, change.id(), change.matrix());
break;
case SurfaceChange::SurfaceChangeCase::kFinalCrop:
- status = setFinalCrop(change.id(), change.final_crop());
+ setFinalCrop(transaction, change.id(), change.final_crop());
break;
case SurfaceChange::SurfaceChangeCase::kOverrideScalingMode:
- status = setOverrideScalingMode(change.id(), change.override_scaling_mode());
+ setOverrideScalingMode(transaction, change.id(),
+ change.override_scaling_mode());
break;
case SurfaceChange::SurfaceChangeCase::kTransparentRegionHint:
- status = setTransparentRegionHint(change.id(), change.transparent_region_hint());
+ setTransparentRegionHint(transaction, change.id(),
+ change.transparent_region_hint());
break;
case SurfaceChange::SurfaceChangeCase::kLayerStack:
- status = setLayerStack(change.id(), change.layer_stack());
+ setLayerStack(transaction, change.id(), change.layer_stack());
break;
case SurfaceChange::SurfaceChangeCase::kHiddenFlag:
- status = setHiddenFlag(change.id(), change.hidden_flag());
+ setHiddenFlag(transaction, change.id(), change.hidden_flag());
break;
case SurfaceChange::SurfaceChangeCase::kOpaqueFlag:
- status = setOpaqueFlag(change.id(), change.opaque_flag());
+ setOpaqueFlag(transaction, change.id(), change.opaque_flag());
break;
case SurfaceChange::SurfaceChangeCase::kSecureFlag:
- status = setSecureFlag(change.id(), change.secure_flag());
+ setSecureFlag(transaction, change.id(), change.secure_flag());
break;
case SurfaceChange::SurfaceChangeCase::kDeferredTransaction:
waitUntilDeferredTransactionLayerExists(change.deferred_transaction(), lock);
- status = setDeferredTransaction(change.id(), change.deferred_transaction());
+ setDeferredTransaction(transaction, change.id(),
+ change.deferred_transaction());
break;
default:
- status = NO_ERROR;
+ status = 1;
break;
}
if (status != NO_ERROR) {
- ALOGE("SET TRANSACTION FAILED");
+ ALOGE("Unknown Transaction Code");
return status;
}
}
return status;
}
-void Replayer::doDisplayTransaction(const DisplayChanges& displayChanges) {
+void Replayer::doDisplayTransaction(SurfaceComposerClient::Transaction& t,
+ const DisplayChanges& displayChanges) {
for (const DisplayChange& change : displayChanges) {
ALOGV("Doing display transaction");
std::unique_lock<std::mutex> lock(mDisplayLock);
@@ -434,16 +440,16 @@
switch (change.DisplayChange_case()) {
case DisplayChange::DisplayChangeCase::kSurface:
- setDisplaySurface(change.id(), change.surface());
+ setDisplaySurface(t, change.id(), change.surface());
break;
case DisplayChange::DisplayChangeCase::kLayerStack:
- setDisplayLayerStack(change.id(), change.layer_stack());
+ setDisplayLayerStack(t, change.id(), change.layer_stack());
break;
case DisplayChange::DisplayChangeCase::kSize:
- setDisplaySize(change.id(), change.size());
+ setDisplaySize(t, change.id(), change.size());
break;
case DisplayChange::DisplayChangeCase::kProjection:
- setDisplayProjection(change.id(), change.projection());
+ setDisplayProjection(t, change.id(), change.projection());
break;
default:
break;
@@ -451,130 +457,148 @@
}
}
-status_t Replayer::setPosition(layer_id id, const PositionChange& pc) {
+void Replayer::setPosition(SurfaceComposerClient::Transaction& t,
+ layer_id id, const PositionChange& pc) {
ALOGV("Layer %d: Setting Position -- x=%f, y=%f", id, pc.x(), pc.y());
- return mLayers[id]->setPosition(pc.x(), pc.y());
+ t.setPosition(mLayers[id], pc.x(), pc.y());
}
-status_t Replayer::setSize(layer_id id, const SizeChange& sc) {
+void Replayer::setSize(SurfaceComposerClient::Transaction& t,
+ layer_id id, const SizeChange& sc) {
ALOGV("Layer %d: Setting Size -- w=%u, h=%u", id, sc.w(), sc.h());
- return mLayers[id]->setSize(sc.w(), sc.h());
+ t.setSize(mLayers[id], sc.w(), sc.h());
}
-status_t Replayer::setLayer(layer_id id, const LayerChange& lc) {
+void Replayer::setLayer(SurfaceComposerClient::Transaction& t,
+ layer_id id, const LayerChange& lc) {
ALOGV("Layer %d: Setting Layer -- layer=%d", id, lc.layer());
- return mLayers[id]->setLayer(lc.layer());
+ t.setLayer(mLayers[id], lc.layer());
}
-status_t Replayer::setAlpha(layer_id id, const AlphaChange& ac) {
+void Replayer::setAlpha(SurfaceComposerClient::Transaction& t,
+ layer_id id, const AlphaChange& ac) {
ALOGV("Layer %d: Setting Alpha -- alpha=%f", id, ac.alpha());
- return mLayers[id]->setAlpha(ac.alpha());
+ t.setAlpha(mLayers[id], ac.alpha());
}
-status_t Replayer::setCrop(layer_id id, const CropChange& cc) {
+void Replayer::setCrop(SurfaceComposerClient::Transaction& t,
+ layer_id id, const CropChange& cc) {
ALOGV("Layer %d: Setting Crop -- left=%d, top=%d, right=%d, bottom=%d", id,
cc.rectangle().left(), cc.rectangle().top(), cc.rectangle().right(),
cc.rectangle().bottom());
Rect r = Rect(cc.rectangle().left(), cc.rectangle().top(), cc.rectangle().right(),
cc.rectangle().bottom());
- return mLayers[id]->setCrop(r);
+ t.setCrop(mLayers[id], r);
}
-status_t Replayer::setFinalCrop(layer_id id, const FinalCropChange& fcc) {
+void Replayer::setFinalCrop(SurfaceComposerClient::Transaction& t,
+ layer_id id, const FinalCropChange& fcc) {
ALOGV("Layer %d: Setting Final Crop -- left=%d, top=%d, right=%d, bottom=%d", id,
fcc.rectangle().left(), fcc.rectangle().top(), fcc.rectangle().right(),
fcc.rectangle().bottom());
Rect r = Rect(fcc.rectangle().left(), fcc.rectangle().top(), fcc.rectangle().right(),
fcc.rectangle().bottom());
- return mLayers[id]->setFinalCrop(r);
+ t.setFinalCrop(mLayers[id], r);
}
-status_t Replayer::setMatrix(layer_id id, const MatrixChange& mc) {
+void Replayer::setMatrix(SurfaceComposerClient::Transaction& t,
+ layer_id id, const MatrixChange& mc) {
ALOGV("Layer %d: Setting Matrix -- dsdx=%f, dtdx=%f, dsdy=%f, dtdy=%f", id, mc.dsdx(),
mc.dtdx(), mc.dsdy(), mc.dtdy());
- return mLayers[id]->setMatrix(mc.dsdx(), mc.dtdx(), mc.dsdy(), mc.dtdy());
+ t.setMatrix(mLayers[id], mc.dsdx(), mc.dtdx(), mc.dsdy(), mc.dtdy());
}
-status_t Replayer::setOverrideScalingMode(layer_id id, const OverrideScalingModeChange& osmc) {
+void Replayer::setOverrideScalingMode(SurfaceComposerClient::Transaction& t,
+ layer_id id, const OverrideScalingModeChange& osmc) {
ALOGV("Layer %d: Setting Override Scaling Mode -- mode=%d", id, osmc.override_scaling_mode());
- return mLayers[id]->setOverrideScalingMode(osmc.override_scaling_mode());
+ t.setOverrideScalingMode(mLayers[id], osmc.override_scaling_mode());
}
-status_t Replayer::setTransparentRegionHint(layer_id id, const TransparentRegionHintChange& trhc) {
+void Replayer::setTransparentRegionHint(SurfaceComposerClient::Transaction& t,
+ layer_id id, const TransparentRegionHintChange& trhc) {
ALOGV("Setting Transparent Region Hint");
Region re = Region();
- for (auto r : trhc.region()) {
+ for (const auto& r : trhc.region()) {
Rect rect = Rect(r.left(), r.top(), r.right(), r.bottom());
re.merge(rect);
}
- return mLayers[id]->setTransparentRegionHint(re);
+ t.setTransparentRegionHint(mLayers[id], re);
}
-status_t Replayer::setLayerStack(layer_id id, const LayerStackChange& lsc) {
+void Replayer::setLayerStack(SurfaceComposerClient::Transaction& t,
+ layer_id id, const LayerStackChange& lsc) {
ALOGV("Layer %d: Setting LayerStack -- layer_stack=%d", id, lsc.layer_stack());
- return mLayers[id]->setLayerStack(lsc.layer_stack());
+ t.setLayerStack(mLayers[id], lsc.layer_stack());
}
-status_t Replayer::setHiddenFlag(layer_id id, const HiddenFlagChange& hfc) {
+void Replayer::setHiddenFlag(SurfaceComposerClient::Transaction& t,
+ layer_id id, const HiddenFlagChange& hfc) {
ALOGV("Layer %d: Setting Hidden Flag -- hidden_flag=%d", id, hfc.hidden_flag());
layer_id flag = hfc.hidden_flag() ? layer_state_t::eLayerHidden : 0;
- return mLayers[id]->setFlags(flag, layer_state_t::eLayerHidden);
+ t.setFlags(mLayers[id], flag, layer_state_t::eLayerHidden);
}
-status_t Replayer::setOpaqueFlag(layer_id id, const OpaqueFlagChange& ofc) {
+void Replayer::setOpaqueFlag(SurfaceComposerClient::Transaction& t,
+ layer_id id, const OpaqueFlagChange& ofc) {
ALOGV("Layer %d: Setting Opaque Flag -- opaque_flag=%d", id, ofc.opaque_flag());
layer_id flag = ofc.opaque_flag() ? layer_state_t::eLayerOpaque : 0;
- return mLayers[id]->setFlags(flag, layer_state_t::eLayerOpaque);
+ t.setFlags(mLayers[id], flag, layer_state_t::eLayerOpaque);
}
-status_t Replayer::setSecureFlag(layer_id id, const SecureFlagChange& sfc) {
+void Replayer::setSecureFlag(SurfaceComposerClient::Transaction& t,
+ layer_id id, const SecureFlagChange& sfc) {
ALOGV("Layer %d: Setting Secure Flag -- secure_flag=%d", id, sfc.secure_flag());
layer_id flag = sfc.secure_flag() ? layer_state_t::eLayerSecure : 0;
- return mLayers[id]->setFlags(flag, layer_state_t::eLayerSecure);
+ t.setFlags(mLayers[id], flag, layer_state_t::eLayerSecure);
}
-status_t Replayer::setDeferredTransaction(layer_id id, const DeferredTransactionChange& dtc) {
+void Replayer::setDeferredTransaction(SurfaceComposerClient::Transaction& t,
+ layer_id id, const DeferredTransactionChange& dtc) {
ALOGV("Layer %d: Setting Deferred Transaction -- layer_id=%d, "
"frame_number=%llu",
id, dtc.layer_id(), dtc.frame_number());
if (mLayers.count(dtc.layer_id()) == 0 || mLayers[dtc.layer_id()] == nullptr) {
ALOGE("Layer %d not found in Deferred Transaction", dtc.layer_id());
- return BAD_VALUE;
+ return;
}
auto handle = mLayers[dtc.layer_id()]->getHandle();
- return mLayers[id]->deferTransactionUntil(handle, dtc.frame_number());
+ t.deferTransactionUntil(mLayers[id], handle, dtc.frame_number());
}
-void Replayer::setDisplaySurface(display_id id, const DispSurfaceChange& /*dsc*/) {
+void Replayer::setDisplaySurface(SurfaceComposerClient::Transaction& t,
+ display_id id, const DispSurfaceChange& /*dsc*/) {
sp<IGraphicBufferProducer> outProducer;
sp<IGraphicBufferConsumer> outConsumer;
BufferQueue::createBufferQueue(&outProducer, &outConsumer);
- SurfaceComposerClient::setDisplaySurface(mDisplays[id], outProducer);
+ t.setDisplaySurface(mDisplays[id], outProducer);
}
-void Replayer::setDisplayLayerStack(display_id id, const LayerStackChange& lsc) {
- SurfaceComposerClient::setDisplayLayerStack(mDisplays[id], lsc.layer_stack());
+void Replayer::setDisplayLayerStack(SurfaceComposerClient::Transaction& t,
+ display_id id, const LayerStackChange& lsc) {
+ t.setDisplayLayerStack(mDisplays[id], lsc.layer_stack());
}
-void Replayer::setDisplaySize(display_id id, const SizeChange& sc) {
- SurfaceComposerClient::setDisplaySize(mDisplays[id], sc.w(), sc.h());
+void Replayer::setDisplaySize(SurfaceComposerClient::Transaction& t,
+ display_id id, const SizeChange& sc) {
+ t.setDisplaySize(mDisplays[id], sc.w(), sc.h());
}
-void Replayer::setDisplayProjection(display_id id, const ProjectionChange& pc) {
+void Replayer::setDisplayProjection(SurfaceComposerClient::Transaction& t,
+ display_id id, const ProjectionChange& pc) {
Rect viewport = Rect(pc.viewport().left(), pc.viewport().top(), pc.viewport().right(),
pc.viewport().bottom());
Rect frame = Rect(pc.frame().left(), pc.frame().top(), pc.frame().right(), pc.frame().bottom());
- SurfaceComposerClient::setDisplayProjection(mDisplays[id], pc.orientation(), viewport, frame);
+ t.setDisplayProjection(mDisplays[id], pc.orientation(), viewport, frame);
}
status_t Replayer::createSurfaceControl(
diff --git a/cmds/surfacereplayer/replayer/Replayer.h b/cmds/surfacereplayer/replayer/Replayer.h
index f36c9fd..295403e 100644
--- a/cmds/surfacereplayer/replayer/Replayer.h
+++ b/cmds/surfacereplayer/replayer/Replayer.h
@@ -77,28 +77,48 @@
void deleteDisplay(const DisplayDeletion& delete_, const std::shared_ptr<Event>& event);
void updatePowerMode(const PowerModeUpdate& update, const std::shared_ptr<Event>& event);
- status_t doSurfaceTransaction(const SurfaceChanges& surfaceChange);
- void doDisplayTransaction(const DisplayChanges& displayChange);
+ status_t doSurfaceTransaction(SurfaceComposerClient::Transaction& transaction,
+ const SurfaceChanges& surfaceChange);
+ void doDisplayTransaction(SurfaceComposerClient::Transaction& transaction,
+ const DisplayChanges& displayChange);
- status_t setPosition(layer_id id, const PositionChange& pc);
- status_t setSize(layer_id id, const SizeChange& sc);
- status_t setAlpha(layer_id id, const AlphaChange& ac);
- status_t setLayer(layer_id id, const LayerChange& lc);
- status_t setCrop(layer_id id, const CropChange& cc);
- status_t setFinalCrop(layer_id id, const FinalCropChange& fcc);
- status_t setMatrix(layer_id id, const MatrixChange& mc);
- status_t setOverrideScalingMode(layer_id id, const OverrideScalingModeChange& osmc);
- status_t setTransparentRegionHint(layer_id id, const TransparentRegionHintChange& trgc);
- status_t setLayerStack(layer_id id, const LayerStackChange& lsc);
- status_t setHiddenFlag(layer_id id, const HiddenFlagChange& hfc);
- status_t setOpaqueFlag(layer_id id, const OpaqueFlagChange& ofc);
- status_t setSecureFlag(layer_id id, const SecureFlagChange& sfc);
- status_t setDeferredTransaction(layer_id id, const DeferredTransactionChange& dtc);
+ void setPosition(SurfaceComposerClient::Transaction& t,
+ layer_id id, const PositionChange& pc);
+ void setSize(SurfaceComposerClient::Transaction& t,
+ layer_id id, const SizeChange& sc);
+ void setAlpha(SurfaceComposerClient::Transaction& t,
+ layer_id id, const AlphaChange& ac);
+ void setLayer(SurfaceComposerClient::Transaction& t,
+ layer_id id, const LayerChange& lc);
+ void setCrop(SurfaceComposerClient::Transaction& t,
+ layer_id id, const CropChange& cc);
+ void setFinalCrop(SurfaceComposerClient::Transaction& t,
+ layer_id id, const FinalCropChange& fcc);
+ void setMatrix(SurfaceComposerClient::Transaction& t,
+ layer_id id, const MatrixChange& mc);
+ void setOverrideScalingMode(SurfaceComposerClient::Transaction& t,
+ layer_id id, const OverrideScalingModeChange& osmc);
+ void setTransparentRegionHint(SurfaceComposerClient::Transaction& t,
+ layer_id id, const TransparentRegionHintChange& trgc);
+ void setLayerStack(SurfaceComposerClient::Transaction& t,
+ layer_id id, const LayerStackChange& lsc);
+ void setHiddenFlag(SurfaceComposerClient::Transaction& t,
+ layer_id id, const HiddenFlagChange& hfc);
+ void setOpaqueFlag(SurfaceComposerClient::Transaction& t,
+ layer_id id, const OpaqueFlagChange& ofc);
+ void setSecureFlag(SurfaceComposerClient::Transaction& t,
+ layer_id id, const SecureFlagChange& sfc);
+ void setDeferredTransaction(SurfaceComposerClient::Transaction& t,
+ layer_id id, const DeferredTransactionChange& dtc);
- void setDisplaySurface(display_id id, const DispSurfaceChange& dsc);
- void setDisplayLayerStack(display_id id, const LayerStackChange& lsc);
- void setDisplaySize(display_id id, const SizeChange& sc);
- void setDisplayProjection(display_id id, const ProjectionChange& pc);
+ void setDisplaySurface(SurfaceComposerClient::Transaction& t,
+ display_id id, const DispSurfaceChange& dsc);
+ void setDisplayLayerStack(SurfaceComposerClient::Transaction& t,
+ display_id id, const LayerStackChange& lsc);
+ void setDisplaySize(SurfaceComposerClient::Transaction& t,
+ display_id id, const SizeChange& sc);
+ void setDisplayProjection(SurfaceComposerClient::Transaction& t,
+ display_id id, const ProjectionChange& pc);
void doDeleteSurfaceControls();
void waitUntilTimestamp(int64_t timestamp);
diff --git a/data/etc/android.hardware.radio.xml b/data/etc/android.hardware.broadcastradio.xml
similarity index 93%
rename from data/etc/android.hardware.radio.xml
rename to data/etc/android.hardware.broadcastradio.xml
index f718c47..c669518 100644
--- a/data/etc/android.hardware.radio.xml
+++ b/data/etc/android.hardware.broadcastradio.xml
@@ -16,5 +16,5 @@
<!-- This is the standard set of features for a broadcast radio. -->
<permissions>
- <feature name="android.hardware.radio" />
+ <feature name="android.hardware.broadcastradio" />
</permissions>
diff --git a/data/etc/android.hardware.radio.xml b/data/etc/android.hardware.wifi.rtt.xml
similarity index 82%
copy from data/etc/android.hardware.radio.xml
copy to data/etc/android.hardware.wifi.rtt.xml
index f718c47..60529ea 100644
--- a/data/etc/android.hardware.radio.xml
+++ b/data/etc/android.hardware.wifi.rtt.xml
@@ -14,7 +14,7 @@
limitations under the License.
-->
-<!-- This is the standard set of features for a broadcast radio. -->
+<!-- This is the standard feature indicating that the device supports WiFi RTT (IEEE 802.11mc). -->
<permissions>
- <feature name="android.hardware.radio" />
+ <feature name="android.hardware.wifi.rtt" />
</permissions>
diff --git a/data/etc/car_core_hardware.xml b/data/etc/car_core_hardware.xml
index 835504f..561f5ba 100644
--- a/data/etc/car_core_hardware.xml
+++ b/data/etc/car_core_hardware.xml
@@ -41,7 +41,6 @@
<feature name="android.software.voice_recognizers" notLowRam="true" />
<feature name="android.software.backup" />
<feature name="android.software.home_screen" />
- <feature name="android.software.input_methods" />
<feature name="android.software.print" />
<!-- Feature to specify if the device supports adding device admins. -->
diff --git a/data/etc/handheld_core_hardware.xml b/data/etc/handheld_core_hardware.xml
index 0d5d206..b6abc1b 100644
--- a/data/etc/handheld_core_hardware.xml
+++ b/data/etc/handheld_core_hardware.xml
@@ -45,7 +45,7 @@
<feature name="android.software.backup" />
<feature name="android.software.home_screen" />
<feature name="android.software.input_methods" />
- <feature name="android.software.picture_in_picture" />
+ <feature name="android.software.picture_in_picture" notLowRam="true" />
<feature name="android.software.activities_on_secondary_displays" />
<feature name="android.software.print" />
<feature name="android.software.companion_device_setup" />
@@ -55,7 +55,7 @@
<feature name="android.software.device_admin" />
<!-- Feature to specify if the device support managed users. -->
- <feature name="android.software.managed_users" />
+ <feature name="android.software.managed_users" notLowRam="true"/>
<!-- Feature to specify if the device supports a VR mode.
feature name="android.software.vr.mode" -->
diff --git a/data/etc/wearable_core_hardware.xml b/data/etc/wearable_core_hardware.xml
index a7955e9..d7c3730 100644
--- a/data/etc/wearable_core_hardware.xml
+++ b/data/etc/wearable_core_hardware.xml
@@ -39,6 +39,9 @@
<!-- device administration -->
<feature name="android.software.device_admin" />
+ <!-- input management and third-party input method editors -->
+ <feature name="android.software.input_methods" />
+
<!-- devices with GPS must include device/google/clockwork/gps.xml -->
<!-- devices with an autofocus camera and/or flash must include either
android.hardware.camera.autofocus.xml or
diff --git a/headers/Android.bp b/headers/Android.bp
new file mode 100644
index 0000000..82bc8a1
--- /dev/null
+++ b/headers/Android.bp
@@ -0,0 +1,20 @@
+cc_library_headers {
+ name: "media_plugin_headers",
+ vendor_available: true,
+ export_include_dirs: [
+ "media_plugin",
+ "media_plugin/media/openmax",
+ ],
+ header_libs: [
+ "libstagefright_headers",
+ "libcutils_headers",
+ "libutils_headers",
+ "libstagefright_foundation_headers",
+ ],
+ export_header_lib_headers: [
+ "libstagefright_headers",
+ "libcutils_headers",
+ "libutils_headers",
+ "libstagefright_foundation_headers",
+ ],
+}
diff --git a/include/media/cas/CasAPI.h b/headers/media_plugin/media/cas/CasAPI.h
similarity index 100%
rename from include/media/cas/CasAPI.h
rename to headers/media_plugin/media/cas/CasAPI.h
diff --git a/include/media/cas/DescramblerAPI.h b/headers/media_plugin/media/cas/DescramblerAPI.h
similarity index 100%
rename from include/media/cas/DescramblerAPI.h
rename to headers/media_plugin/media/cas/DescramblerAPI.h
diff --git a/include/media/drm/DrmAPI.h b/headers/media_plugin/media/drm/DrmAPI.h
similarity index 100%
rename from include/media/drm/DrmAPI.h
rename to headers/media_plugin/media/drm/DrmAPI.h
diff --git a/include/media/editor/II420ColorConverter.h b/headers/media_plugin/media/editor/II420ColorConverter.h
similarity index 100%
rename from include/media/editor/II420ColorConverter.h
rename to headers/media_plugin/media/editor/II420ColorConverter.h
diff --git a/include/media/hardware/CryptoAPI.h b/headers/media_plugin/media/hardware/CryptoAPI.h
similarity index 100%
rename from include/media/hardware/CryptoAPI.h
rename to headers/media_plugin/media/hardware/CryptoAPI.h
diff --git a/include/media/hardware/HDCPAPI.h b/headers/media_plugin/media/hardware/HDCPAPI.h
similarity index 100%
rename from include/media/hardware/HDCPAPI.h
rename to headers/media_plugin/media/hardware/HDCPAPI.h
diff --git a/include/media/hardware/HardwareAPI.h b/headers/media_plugin/media/hardware/HardwareAPI.h
similarity index 100%
rename from include/media/hardware/HardwareAPI.h
rename to headers/media_plugin/media/hardware/HardwareAPI.h
diff --git a/include/media/hardware/MetadataBufferType.h b/headers/media_plugin/media/hardware/MetadataBufferType.h
similarity index 100%
rename from include/media/hardware/MetadataBufferType.h
rename to headers/media_plugin/media/hardware/MetadataBufferType.h
diff --git a/include/media/hardware/OMXPluginBase.h b/headers/media_plugin/media/hardware/OMXPluginBase.h
similarity index 100%
rename from include/media/hardware/OMXPluginBase.h
rename to headers/media_plugin/media/hardware/OMXPluginBase.h
diff --git a/include/media/hardware/VideoAPI.h b/headers/media_plugin/media/hardware/VideoAPI.h
similarity index 100%
rename from include/media/hardware/VideoAPI.h
rename to headers/media_plugin/media/hardware/VideoAPI.h
diff --git a/include/media/openmax/OMX_AsString.h b/headers/media_plugin/media/openmax/OMX_AsString.h
similarity index 98%
rename from include/media/openmax/OMX_AsString.h
rename to headers/media_plugin/media/openmax/OMX_AsString.h
index 56d7cc8..dc25ded 100644
--- a/include/media/openmax/OMX_AsString.h
+++ b/headers/media_plugin/media/openmax/OMX_AsString.h
@@ -930,6 +930,14 @@
#ifndef AS_STRING_FOR_OMX_VIDEOEXT_H
#define AS_STRING_FOR_OMX_VIDEOEXT_H
+inline static const char *asString(OMX_VIDEO_AVCPROFILEEXTTYPE i, const char *def = "??") {
+ switch (i) {
+ case OMX_VIDEO_AVCProfileConstrainedBaseline: return "ConstrainedBaseline";
+ case OMX_VIDEO_AVCProfileConstrainedHigh: return "ConstrainedHigh";
+ default: return asString((OMX_VIDEO_AVCPROFILETYPE)i, def);
+ }
+}
+
inline static const char *asString(OMX_VIDEO_VP8PROFILETYPE i, const char *def = "??") {
switch (i) {
case OMX_VIDEO_VP8ProfileMain: return "Main";
diff --git a/include/media/openmax/OMX_Audio.h b/headers/media_plugin/media/openmax/OMX_Audio.h
similarity index 100%
rename from include/media/openmax/OMX_Audio.h
rename to headers/media_plugin/media/openmax/OMX_Audio.h
diff --git a/include/media/openmax/OMX_AudioExt.h b/headers/media_plugin/media/openmax/OMX_AudioExt.h
similarity index 100%
rename from include/media/openmax/OMX_AudioExt.h
rename to headers/media_plugin/media/openmax/OMX_AudioExt.h
diff --git a/include/media/openmax/OMX_Component.h b/headers/media_plugin/media/openmax/OMX_Component.h
similarity index 100%
rename from include/media/openmax/OMX_Component.h
rename to headers/media_plugin/media/openmax/OMX_Component.h
diff --git a/include/media/openmax/OMX_ContentPipe.h b/headers/media_plugin/media/openmax/OMX_ContentPipe.h
similarity index 100%
rename from include/media/openmax/OMX_ContentPipe.h
rename to headers/media_plugin/media/openmax/OMX_ContentPipe.h
diff --git a/include/media/openmax/OMX_Core.h b/headers/media_plugin/media/openmax/OMX_Core.h
similarity index 100%
rename from include/media/openmax/OMX_Core.h
rename to headers/media_plugin/media/openmax/OMX_Core.h
diff --git a/include/media/openmax/OMX_IVCommon.h b/headers/media_plugin/media/openmax/OMX_IVCommon.h
similarity index 100%
rename from include/media/openmax/OMX_IVCommon.h
rename to headers/media_plugin/media/openmax/OMX_IVCommon.h
diff --git a/include/media/openmax/OMX_Image.h b/headers/media_plugin/media/openmax/OMX_Image.h
similarity index 100%
rename from include/media/openmax/OMX_Image.h
rename to headers/media_plugin/media/openmax/OMX_Image.h
diff --git a/include/media/openmax/OMX_Index.h b/headers/media_plugin/media/openmax/OMX_Index.h
similarity index 100%
rename from include/media/openmax/OMX_Index.h
rename to headers/media_plugin/media/openmax/OMX_Index.h
diff --git a/include/media/openmax/OMX_IndexExt.h b/headers/media_plugin/media/openmax/OMX_IndexExt.h
similarity index 100%
rename from include/media/openmax/OMX_IndexExt.h
rename to headers/media_plugin/media/openmax/OMX_IndexExt.h
diff --git a/include/media/openmax/OMX_Other.h b/headers/media_plugin/media/openmax/OMX_Other.h
similarity index 100%
rename from include/media/openmax/OMX_Other.h
rename to headers/media_plugin/media/openmax/OMX_Other.h
diff --git a/include/media/openmax/OMX_Types.h b/headers/media_plugin/media/openmax/OMX_Types.h
similarity index 100%
rename from include/media/openmax/OMX_Types.h
rename to headers/media_plugin/media/openmax/OMX_Types.h
diff --git a/include/media/openmax/OMX_Video.h b/headers/media_plugin/media/openmax/OMX_Video.h
similarity index 100%
rename from include/media/openmax/OMX_Video.h
rename to headers/media_plugin/media/openmax/OMX_Video.h
diff --git a/include/media/openmax/OMX_VideoExt.h b/headers/media_plugin/media/openmax/OMX_VideoExt.h
similarity index 94%
rename from include/media/openmax/OMX_VideoExt.h
rename to headers/media_plugin/media/openmax/OMX_VideoExt.h
index 128dd2d..c102564 100644
--- a/include/media/openmax/OMX_VideoExt.h
+++ b/headers/media_plugin/media/openmax/OMX_VideoExt.h
@@ -58,6 +58,12 @@
OMX_NALUFORMATSTYPE eNaluFormat;
} OMX_NALSTREAMFORMATTYPE;
+/** AVC additional profiles */
+typedef enum OMX_VIDEO_AVCPROFILEEXTTYPE {
+ OMX_VIDEO_AVCProfileConstrainedBaseline = 0x10000, /**< Constrained baseline profile */
+ OMX_VIDEO_AVCProfileConstrainedHigh = 0x80000, /**< Constrained high profile */
+} OMX_VIDEO_AVCPROFILEEXTTYPE;
+
/** VP8 profiles */
typedef enum OMX_VIDEO_VP8PROFILETYPE {
OMX_VIDEO_VP8ProfileMain = 0x01,
@@ -164,20 +170,20 @@
/** VP9 levels */
typedef enum OMX_VIDEO_VP9LEVELTYPE {
- OMX_VIDEO_VP9Level1 = 0x0,
- OMX_VIDEO_VP9Level11 = 0x1,
- OMX_VIDEO_VP9Level2 = 0x2,
- OMX_VIDEO_VP9Level21 = 0x4,
- OMX_VIDEO_VP9Level3 = 0x8,
- OMX_VIDEO_VP9Level31 = 0x10,
- OMX_VIDEO_VP9Level4 = 0x20,
- OMX_VIDEO_VP9Level41 = 0x40,
- OMX_VIDEO_VP9Level5 = 0x80,
- OMX_VIDEO_VP9Level51 = 0x100,
- OMX_VIDEO_VP9Level52 = 0x200,
- OMX_VIDEO_VP9Level6 = 0x400,
- OMX_VIDEO_VP9Level61 = 0x800,
- OMX_VIDEO_VP9Level62 = 0x1000,
+ OMX_VIDEO_VP9Level1 = 0x1,
+ OMX_VIDEO_VP9Level11 = 0x2,
+ OMX_VIDEO_VP9Level2 = 0x4,
+ OMX_VIDEO_VP9Level21 = 0x8,
+ OMX_VIDEO_VP9Level3 = 0x10,
+ OMX_VIDEO_VP9Level31 = 0x20,
+ OMX_VIDEO_VP9Level4 = 0x40,
+ OMX_VIDEO_VP9Level41 = 0x80,
+ OMX_VIDEO_VP9Level5 = 0x100,
+ OMX_VIDEO_VP9Level51 = 0x200,
+ OMX_VIDEO_VP9Level52 = 0x400,
+ OMX_VIDEO_VP9Level6 = 0x800,
+ OMX_VIDEO_VP9Level61 = 0x1000,
+ OMX_VIDEO_VP9Level62 = 0x2000,
OMX_VIDEO_VP9LevelUnknown = 0x6EFFFFFF,
OMX_VIDEO_VP9LevelMax = 0x7FFFFFFF
} OMX_VIDEO_VP9LEVELTYPE;
@@ -290,6 +296,8 @@
OMX_VIDEO_DolbyVisionProfileDvheStn = 0x20,
OMX_VIDEO_DolbyVisionProfileDvheDth = 0x40,
OMX_VIDEO_DolbyVisionProfileDvheDtb = 0x80,
+ OMX_VIDEO_DolbyVisionProfileDvheSt = 0x100,
+ OMX_VIDEO_DolbyVisionProfileDvavSe = 0x200,
OMX_VIDEO_DolbyVisionProfileMax = 0x7FFFFFFF
} OMX_VIDEO_DOLBYVISIONPROFILETYPE;
diff --git a/include/android/asset_manager.h b/include/android/asset_manager.h
index 7ef3ecb..2ac7d4d 100644
--- a/include/android/asset_manager.h
+++ b/include/android/asset_manager.h
@@ -33,6 +33,10 @@
extern "C" {
#endif
+#if !defined(__ANDROID__) && !defined(__RENAME_IF_FILE_OFFSET64)
+#define __RENAME_IF_FILE_OFFSET64(x)
+#endif
+
struct AAssetManager;
/**
* {@link AAssetManager} provides access to an application's raw assets by
@@ -132,9 +136,9 @@
*
* Returns the new position on success, or (off_t) -1 on error.
*/
-off_t AAsset_seek(AAsset* asset, off_t offset, int whence);
+off_t AAsset_seek(AAsset* asset, off_t offset, int whence)
+ __RENAME_IF_FILE_OFFSET64(AAsset_seek64);
-#if __ANDROID_API__ >= 13
/**
* Seek to the specified offset within the asset data. 'whence' uses the
* same constants as lseek()/fseek().
@@ -145,7 +149,6 @@
* Returns the new position on success, or (off64_t) -1 on error.
*/
off64_t AAsset_seek64(AAsset* asset, off64_t offset, int whence);
-#endif
/**
* Close the asset, freeing all associated resources.
@@ -162,29 +165,27 @@
/**
* Report the total size of the asset data.
*/
-off_t AAsset_getLength(AAsset* asset);
+off_t AAsset_getLength(AAsset* asset)
+ __RENAME_IF_FILE_OFFSET64(AAsset_getLength64);
-#if __ANDROID_API__ >= 13
/**
* Report the total size of the asset data. Reports the size using a 64-bit
* number insted of 32-bit as AAsset_getLength.
*/
off64_t AAsset_getLength64(AAsset* asset);
-#endif
/**
* Report the total amount of asset data that can be read from the current position.
*/
-off_t AAsset_getRemainingLength(AAsset* asset);
+off_t AAsset_getRemainingLength(AAsset* asset)
+ __RENAME_IF_FILE_OFFSET64(AAsset_getRemainingLength64);
-#if __ANDROID_API__ >= 13
/**
* Report the total amount of asset data that can be read from the current position.
*
* Uses a 64-bit number instead of a 32-bit number as AAsset_getRemainingLength does.
*/
off64_t AAsset_getRemainingLength64(AAsset* asset);
-#endif
/**
* Open a new file descriptor that can be used to read the asset data. If the
@@ -194,9 +195,9 @@
* Returns < 0 if direct fd access is not possible (for example, if the asset is
* compressed).
*/
-int AAsset_openFileDescriptor(AAsset* asset, off_t* outStart, off_t* outLength);
+int AAsset_openFileDescriptor(AAsset* asset, off_t* outStart, off_t* outLength)
+ __RENAME_IF_FILE_OFFSET64(AAsset_openFileDescriptor64);
-#if __ANDROID_API__ >= 13
/**
* Open a new file descriptor that can be used to read the asset data.
*
@@ -207,7 +208,6 @@
* compressed).
*/
int AAsset_openFileDescriptor64(AAsset* asset, off64_t* outStart, off64_t* outLength);
-#endif
/**
* Returns whether this asset's internal buffer is allocated in ordinary RAM (i.e. not
diff --git a/include/android/keycodes.h b/include/android/keycodes.h
index e202060..2164d61 100644
--- a/include/android/keycodes.h
+++ b/include/android/keycodes.h
@@ -765,7 +765,9 @@
/** fingerprint navigation key, left. */
AKEYCODE_SYSTEM_NAVIGATION_LEFT = 282,
/** fingerprint navigation key, right. */
- AKEYCODE_SYSTEM_NAVIGATION_RIGHT = 283
+ AKEYCODE_SYSTEM_NAVIGATION_RIGHT = 283,
+ /** all apps */
+ AKEYCODE_ALL_APPS = 284
// NOTE: If you add a new keycode here you must also add it to several other files.
// Refer to frameworks/base/core/java/android/view/KeyEvent.java for the full list.
diff --git a/include/android/sensor.h b/include/android/sensor.h
index 97b4a2a..2db0ee7 100644
--- a/include/android/sensor.h
+++ b/include/android/sensor.h
@@ -197,7 +197,7 @@
* A sensor event.
*/
-/* NOTE: Must match hardware/sensors.h */
+/* NOTE: changes to these structs have to be backward compatible */
typedef struct ASensorVector {
union {
float v[3];
@@ -259,7 +259,7 @@
};
} AAdditionalInfoEvent;
-/* NOTE: Must match hardware/sensors.h */
+/* NOTE: changes to this struct has to be backward compatible */
typedef struct ASensorEvent {
int32_t version; /* sizeof(struct ASensorEvent) */
int32_t sensor;
@@ -381,18 +381,24 @@
* ASensorManager* sensorManager = ASensorManager_getInstance();
*
*/
+#if __ANDROID_API__ >= __ANDROID_API_O__
__attribute__ ((deprecated)) ASensorManager* ASensorManager_getInstance();
+#else
+ASensorManager* ASensorManager_getInstance();
+#endif
-/*
+#if __ANDROID_API__ >= __ANDROID_API_O__
+/**
* Get a reference to the sensor manager. ASensorManager is a singleton
* per package as different packages may have access to different sensors.
*
* Example:
*
- * ASensorManager* sensorManager = ASensorManager_getInstanceForPackage("foo.bar.baz");
+ * ASensorManager* sensorManager = ASensorManager_getInstanceForPackage("foo.bar.baz");
*
*/
ASensorManager* ASensorManager_getInstanceForPackage(const char* packageName);
+#endif
/**
* Returns the list of available sensors.
@@ -497,14 +503,12 @@
* {@link ASensor_isDirectChannelTypeSupported}, respectively.
*
* Example:
- * \code{.cpp}
- * ASensorManager *manager = ...;
- * ASensor *sensor = ...;
- * int channelId = ...;
*
- * ASensorManager_configureDirectReport(
- * manager, sensor, channel_id, ASENSOR_DIRECT_RATE_FAST);
- * \endcode
+ * ASensorManager *manager = ...;
+ * ASensor *sensor = ...;
+ * int channelId = ...;
+ *
+ * ASensorManager_configureDirectReport(manager, sensor, channel_id, ASENSOR_DIRECT_RATE_FAST);
*
* \param manager the {@link ASensorManager} instance obtained from
* {@link ASensorManager_getInstanceForPackage}.
@@ -524,50 +528,86 @@
/*****************************************************************************/
/**
- * Enable the selected sensor with a specified sampling period and max batch report latency.
- * Returns a negative error code on failure.
- * Note: To disable the selected sensor, use ASensorEventQueue_disableSensor() same as before.
+ * Enable the selected sensor with sampling and report parameters
+ *
+ * Enable the selected sensor at a specified sampling period and max batch report latency.
+ * To disable sensor, use {@link ASensorEventQueue_disableSensor}.
+ *
+ * \param queue {@link ASensorEventQueue} for sensor event to be report to.
+ * \param sensor {@link ASensor} to be enabled.
+ * \param samplingPeriodUs sampling period of sensor in microseconds.
+ * \param maxBatchReportLatencyus maximum time interval between two batch of sensor events are
+ * delievered in microseconds. For sensor streaming, set to 0.
+ * \return 0 on success or a negative error code on failure.
*/
int ASensorEventQueue_registerSensor(ASensorEventQueue* queue, ASensor const* sensor,
int32_t samplingPeriodUs, int64_t maxBatchReportLatencyUs);
/**
- * Enable the selected sensor. Returns a negative error code on failure.
+ * Enable the selected sensor at default sampling rate.
+ *
+ * Start event reports of a sensor to specified sensor event queue at a default rate.
+ *
+ * \param queue {@link ASensorEventQueue} for sensor event to be report to.
+ * \param sensor {@link ASensor} to be enabled.
+ *
+ * \return 0 on success or a negative error code on failure.
*/
int ASensorEventQueue_enableSensor(ASensorEventQueue* queue, ASensor const* sensor);
/**
- * Disable the selected sensor. Returns a negative error code on failure.
+ * Disable the selected sensor.
+ *
+ * Stop event reports from the sensor to specified sensor event queue.
+ *
+ * \param queue {@link ASensorEventQueue} to be changed
+ * \param sensor {@link ASensor} to be disabled
+ * \return 0 on success or a negative error code on failure.
*/
int ASensorEventQueue_disableSensor(ASensorEventQueue* queue, ASensor const* sensor);
/**
* Sets the delivery rate of events in microseconds for the given sensor.
+ *
+ * This function has to be called after {@link ASensorEventQueue_enableSensor}.
* Note that this is a hint only, generally event will arrive at a higher
* rate. It is an error to set a rate inferior to the value returned by
* ASensor_getMinDelay().
- * Returns a negative error code on failure.
+ *
+ * \param queue {@link ASensorEventQueue} to which sensor event is delivered.
+ * \param sensor {@link ASensor} of which sampling rate to be updated.
+ * \param usec sensor sampling period (1/sampling rate) in microseconds
+ * \return 0 on sucess or a negative error code on failure.
*/
int ASensorEventQueue_setEventRate(ASensorEventQueue* queue, ASensor const* sensor, int32_t usec);
/**
- * Returns true if there are one or more events available in the
- * sensor queue. Returns 1 if the queue has events; 0 if
- * it does not have events; and a negative value if there is an error.
+ * Determine if a sensor event queue has pending event to be processed.
+ *
+ * \param queue {@link ASensorEventQueue} to be queried
+ * \return 1 if the queue has events; 0 if it does not have events;
+ * or a negative value if there is an error.
*/
int ASensorEventQueue_hasEvents(ASensorEventQueue* queue);
/**
- * Returns the next available events from the queue. Returns a negative
- * value if no events are available or an error has occurred, otherwise
- * the number of events returned.
+ * Retrieve pending events in sensor event queue
+ *
+ * Retrieve next available events from the queue to a specified event array.
+ *
+ * \param queue {@link ASensorEventQueue} to get events from
+ * \param events pointer to an array of {@link ASensorEvents}.
+ * \param count max number of event that can be filled into array event.
+ * \return number of events returned on success; negative error code when
+ * no events are pending or an error has occurred.
*
* Examples:
- * ASensorEvent event;
- * ssize_t numEvent = ASensorEventQueue_getEvents(queue, &event, 1);
*
- * ASensorEvent eventBuffer[8];
- * ssize_t numEvent = ASensorEventQueue_getEvents(queue, eventBuffer, 8);
+ * ASensorEvent event;
+ * ssize_t numEvent = ASensorEventQueue_getEvents(queue, &event, 1);
+ *
+ * ASensorEvent eventBuffer[8];
+ * ssize_t numEvent = ASensorEventQueue_getEvents(queue, eventBuffer, 8);
*
*/
ssize_t ASensorEventQueue_getEvents(ASensorEventQueue* queue, ASensorEvent* events, size_t count);
diff --git a/include/android/sharedmem_jni.h b/include/android/sharedmem_jni.h
new file mode 100644
index 0000000..85ac78f
--- /dev/null
+++ b/include/android/sharedmem_jni.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 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.
+ */
+
+/**
+ * @addtogroup Memory
+ * @{
+ */
+
+/**
+ * @file sharedmem_jni.h
+ */
+
+#ifndef ANDROID_SHARED_MEMORY_JNI_H
+#define ANDROID_SHARED_MEMORY_JNI_H
+
+#include <jni.h>
+#include <android/sharedmem.h>
+#include <stddef.h>
+
+/******************************************************************
+ *
+ * IMPORTANT NOTICE:
+ *
+ * This file is part of Android's set of stable system headers
+ * exposed by the Android NDK (Native Development Kit).
+ *
+ * Third-party source AND binary code relies on the definitions
+ * here to be FROZEN ON ALL UPCOMING PLATFORM RELEASES.
+ *
+ * - DO NOT MODIFY ENUMS (EXCEPT IF YOU ADD NEW 32-BIT VALUES)
+ * - DO NOT MODIFY CONSTANTS OR FUNCTIONAL MACROS
+ * - DO NOT CHANGE THE SIGNATURE OF FUNCTIONS IN ANY WAY
+ * - DO NOT CHANGE THE LAYOUT OR SIZE OF STRUCTURES
+ */
+
+/**
+ * Structures and functions for a shared memory buffer that can be shared across process.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if __ANDROID_API__ >= __ANDROID_API_O_MR1__
+
+/**
+ * Returns a dup'd FD from the given Java android.os.SharedMemory object. The returned file
+ * descriptor has all the same properties & capabilities as the FD returned from
+ * ASharedMemory_create(), however the protection flags will be the same as those of the
+ * android.os.SharedMemory object.
+ *
+ * Use close() to release the shared memory region.
+ *
+ * \param env The JNIEnv* pointer
+ * \param sharedMemory The Java android.os.SharedMemory object
+ * \return file descriptor that denotes the shared memory; -1 if the shared memory object is
+ * already closed, if the JNIEnv or jobject is NULL, or if there are too many open file
+ * descriptors (errno=EMFILE)
+ */
+int ASharedMemory_dupFromJava(JNIEnv* env, jobject sharedMemory);
+
+#endif
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif // ANDROID_SHARED_MEMORY_JNI_H
+
+/** @} */
diff --git a/include/audiomanager/IPlayer.h b/include/audiomanager/IPlayer.h
deleted file mode 100644
index de5c1c7..0000000
--- a/include/audiomanager/IPlayer.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (C) 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.
- */
-
-#ifndef ANDROID_IPLAYER_H
-#define ANDROID_IPLAYER_H
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <media/VolumeShaper.h>
-#include <utils/RefBase.h>
-#include <utils/Errors.h>
-#include <binder/IInterface.h>
-
-namespace android {
-
-// ----------------------------------------------------------------------------
-
-class IPlayer : public IInterface
-{
-public:
- DECLARE_META_INTERFACE(Player);
-
- virtual void start() = 0;
-
- virtual void pause() = 0;
-
- virtual void stop() = 0;
-
- virtual void setVolume(float vol) = 0;
-
- virtual void setPan(float pan) = 0;
-
- virtual void setStartDelayMs(int delayMs) = 0;
-
- virtual void applyVolumeShaper(
- const sp<VolumeShaper::Configuration>& configuration,
- const sp<VolumeShaper::Operation>& operation) = 0;
-};
-
-// ----------------------------------------------------------------------------
-
-class BnPlayer : public BnInterface<IPlayer>
-{
-public:
- virtual status_t onTransact( uint32_t code,
- const Parcel& data,
- Parcel* reply,
- uint32_t flags = 0);
-};
-
-// ----------------------------------------------------------------------------
-
-}; // namespace android
-
-#endif // ANDROID_IPLAYER_H
diff --git a/include/batteryservice b/include/batteryservice
new file mode 120000
index 0000000..2178c32
--- /dev/null
+++ b/include/batteryservice
@@ -0,0 +1 @@
+../services/batteryservice/include/batteryservice/
\ No newline at end of file
diff --git a/include/gui b/include/gui
new file mode 120000
index 0000000..3b796f3
--- /dev/null
+++ b/include/gui
@@ -0,0 +1 @@
+../libs/gui/include/gui
\ No newline at end of file
diff --git a/include/gui/SurfaceComposerClient.h b/include/gui/SurfaceComposerClient.h
deleted file mode 100644
index ec310cf..0000000
--- a/include/gui/SurfaceComposerClient.h
+++ /dev/null
@@ -1,279 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_GUI_SURFACE_COMPOSER_CLIENT_H
-#define ANDROID_GUI_SURFACE_COMPOSER_CLIENT_H
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <binder/IBinder.h>
-
-#include <utils/RefBase.h>
-#include <utils/Singleton.h>
-#include <utils/SortedVector.h>
-#include <utils/threads.h>
-
-#include <ui/FrameStats.h>
-#include <ui/PixelFormat.h>
-
-#include <gui/CpuConsumer.h>
-#include <gui/SurfaceControl.h>
-
-namespace android {
-
-// ---------------------------------------------------------------------------
-
-struct DisplayInfo;
-class Composer;
-class HdrCapabilities;
-class ISurfaceComposerClient;
-class IGraphicBufferProducer;
-class Region;
-
-// ---------------------------------------------------------------------------
-
-class SurfaceComposerClient : public RefBase
-{
- friend class Composer;
-public:
- SurfaceComposerClient();
- SurfaceComposerClient(const sp<IGraphicBufferProducer>& parent);
- virtual ~SurfaceComposerClient();
-
- // Always make sure we could initialize
- status_t initCheck() const;
-
- // Return the connection of this client
- sp<IBinder> connection() const;
-
- // Forcibly remove connection before all references have gone away.
- void dispose();
-
- // callback when the composer is dies
- status_t linkToComposerDeath(const sp<IBinder::DeathRecipient>& recipient,
- void* cookie = NULL, uint32_t flags = 0);
-
- // Get a list of supported configurations for a given display
- static status_t getDisplayConfigs(const sp<IBinder>& display,
- Vector<DisplayInfo>* configs);
-
- // Get the DisplayInfo for the currently-active configuration
- static status_t getDisplayInfo(const sp<IBinder>& display,
- DisplayInfo* info);
-
- // Get the index of the current active configuration (relative to the list
- // returned by getDisplayInfo)
- static int getActiveConfig(const sp<IBinder>& display);
-
- // Set a new active configuration using an index relative to the list
- // returned by getDisplayInfo
- static status_t setActiveConfig(const sp<IBinder>& display, int id);
-
- // Gets the list of supported color modes for the given display
- static status_t getDisplayColorModes(const sp<IBinder>& display,
- Vector<android_color_mode_t>* outColorModes);
-
- // Gets the active color mode for the given display
- static android_color_mode_t getActiveColorMode(const sp<IBinder>& display);
-
- // Sets the active color mode for the given display
- static status_t setActiveColorMode(const sp<IBinder>& display, android_color_mode_t colorMode);
-
- /* Triggers screen on/off or low power mode and waits for it to complete */
- static void setDisplayPowerMode(const sp<IBinder>& display, int mode);
-
- // ------------------------------------------------------------------------
- // surface creation / destruction
-
- //! Create a surface
- sp<SurfaceControl> createSurface(
- const String8& name,// name of the surface
- uint32_t w, // width in pixel
- uint32_t h, // height in pixel
- PixelFormat format, // pixel-format desired
- uint32_t flags = 0, // usage flags
- SurfaceControl* parent = nullptr, // parent
- uint32_t windowType = 0, // from WindowManager.java (STATUS_BAR, INPUT_METHOD, etc.)
- uint32_t ownerUid = 0 // UID of the task
- );
-
- //! Create a virtual display
- static sp<IBinder> createDisplay(const String8& displayName, bool secure);
-
- //! Destroy a virtual display
- static void destroyDisplay(const sp<IBinder>& display);
-
- //! Get the token for the existing default displays.
- //! Possible values for id are eDisplayIdMain and eDisplayIdHdmi.
- static sp<IBinder> getBuiltInDisplay(int32_t id);
-
- // ------------------------------------------------------------------------
- // Composer parameters
- // All composer parameters must be changed within a transaction
- // several surfaces can be updated in one transaction, all changes are
- // committed at once when the transaction is closed.
- // closeGlobalTransaction() requires an IPC with the server.
-
- //! Open a composer transaction on all active SurfaceComposerClients.
- static void openGlobalTransaction();
-
- //! Close a composer transaction on all active SurfaceComposerClients.
- static void closeGlobalTransaction(bool synchronous = false);
-
- static status_t enableVSyncInjections(bool enable);
-
- static status_t injectVSync(nsecs_t when);
-
- //! Flag the currently open transaction as an animation transaction.
- static void setAnimationTransaction();
-
- status_t hide(const sp<IBinder>& id);
- status_t show(const sp<IBinder>& id);
- status_t setFlags(const sp<IBinder>& id, uint32_t flags, uint32_t mask);
- status_t setTransparentRegionHint(const sp<IBinder>& id, const Region& transparent);
- status_t setLayer(const sp<IBinder>& id, int32_t layer);
- status_t setRelativeLayer(const sp<IBinder>& id,
- const sp<IBinder>& relativeTo, int32_t layer);
- status_t setAlpha(const sp<IBinder>& id, float alpha=1.0f);
- status_t setMatrix(const sp<IBinder>& id, float dsdx, float dtdx, float dtdy, float dsdy);
- status_t setPosition(const sp<IBinder>& id, float x, float y);
- status_t setSize(const sp<IBinder>& id, uint32_t w, uint32_t h);
- status_t setCrop(const sp<IBinder>& id, const Rect& crop);
- status_t setFinalCrop(const sp<IBinder>& id, const Rect& crop);
- status_t setLayerStack(const sp<IBinder>& id, uint32_t layerStack);
- status_t deferTransactionUntil(const sp<IBinder>& id,
- const sp<IBinder>& handle, uint64_t frameNumber);
- status_t deferTransactionUntil(const sp<IBinder>& id,
- const sp<Surface>& handle, uint64_t frameNumber);
- status_t reparentChildren(const sp<IBinder>& id,
- const sp<IBinder>& newParentHandle);
- status_t detachChildren(const sp<IBinder>& id);
- status_t setOverrideScalingMode(const sp<IBinder>& id,
- int32_t overrideScalingMode);
- status_t setGeometryAppliesWithResize(const sp<IBinder>& id);
-
- status_t destroySurface(const sp<IBinder>& id);
-
- status_t clearLayerFrameStats(const sp<IBinder>& token) const;
- status_t getLayerFrameStats(const sp<IBinder>& token, FrameStats* outStats) const;
-
- static status_t clearAnimationFrameStats();
- static status_t getAnimationFrameStats(FrameStats* outStats);
-
- static status_t getHdrCapabilities(const sp<IBinder>& display,
- HdrCapabilities* outCapabilities);
-
- static status_t setDisplaySurface(const sp<IBinder>& token,
- sp<IGraphicBufferProducer> bufferProducer);
- static void setDisplayLayerStack(const sp<IBinder>& token,
- uint32_t layerStack);
- static void setDisplaySize(const sp<IBinder>& token, uint32_t width, uint32_t height);
-
- /* setDisplayProjection() defines the projection of layer stacks
- * to a given display.
- *
- * - orientation defines the display's orientation.
- * - layerStackRect defines which area of the window manager coordinate
- * space will be used.
- * - displayRect defines where on the display will layerStackRect be
- * mapped to. displayRect is specified post-orientation, that is
- * it uses the orientation seen by the end-user.
- */
- static void setDisplayProjection(const sp<IBinder>& token,
- uint32_t orientation,
- const Rect& layerStackRect,
- const Rect& displayRect);
-
-private:
- virtual void onFirstRef();
- Composer& getComposer();
-
- mutable Mutex mLock;
- status_t mStatus;
- sp<ISurfaceComposerClient> mClient;
- Composer& mComposer;
- wp<IGraphicBufferProducer> mParent;
-};
-
-// ---------------------------------------------------------------------------
-
-class ScreenshotClient
-{
-public:
- // if cropping isn't required, callers may pass in a default Rect, e.g.:
- // capture(display, producer, Rect(), reqWidth, ...);
- static status_t capture(
- const sp<IBinder>& display,
- const sp<IGraphicBufferProducer>& producer,
- Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
- int32_t minLayerZ, int32_t maxLayerZ,
- bool useIdentityTransform);
- static status_t captureToBuffer(
- const sp<IBinder>& display,
- Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
- int32_t minLayerZ, int32_t maxLayerZ,
- bool useIdentityTransform,
- uint32_t rotation,
- sp<GraphicBuffer>* outbuffer);
-private:
- mutable sp<CpuConsumer> mCpuConsumer;
- mutable sp<IGraphicBufferProducer> mProducer;
- CpuConsumer::LockedBuffer mBuffer;
- bool mHaveBuffer;
-
-public:
- ScreenshotClient();
- ~ScreenshotClient();
-
- // frees the previous screenshot and captures a new one
- // if cropping isn't required, callers may pass in a default Rect, e.g.:
- // update(display, Rect(), useIdentityTransform);
- status_t update(const sp<IBinder>& display,
- Rect sourceCrop, bool useIdentityTransform);
- status_t update(const sp<IBinder>& display,
- Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
- bool useIdentityTransform);
- status_t update(const sp<IBinder>& display,
- Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
- int32_t minLayerZ, int32_t maxLayerZ,
- bool useIdentityTransform);
- status_t update(const sp<IBinder>& display,
- Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
- int32_t minLayerZ, int32_t maxLayerZ,
- bool useIdentityTransform, uint32_t rotation);
-
- sp<CpuConsumer> getCpuConsumer() const;
-
- // release memory occupied by the screenshot
- void release();
-
- // pixels are valid until this object is freed or
- // release() or update() is called
- void const* getPixels() const;
-
- uint32_t getWidth() const;
- uint32_t getHeight() const;
- PixelFormat getFormat() const;
- uint32_t getStride() const;
- // size of allocated memory in bytes
- size_t getSize() const;
-};
-
-// ---------------------------------------------------------------------------
-}; // namespace android
-
-#endif // ANDROID_GUI_SURFACE_COMPOSER_CLIENT_H
diff --git a/include/gui/SurfaceControl.h b/include/gui/SurfaceControl.h
deleted file mode 100644
index 712a323..0000000
--- a/include/gui/SurfaceControl.h
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_GUI_SURFACE_CONTROL_H
-#define ANDROID_GUI_SURFACE_CONTROL_H
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <utils/KeyedVector.h>
-#include <utils/RefBase.h>
-#include <utils/threads.h>
-
-#include <ui/FrameStats.h>
-#include <ui/PixelFormat.h>
-#include <ui/Region.h>
-
-#include <gui/ISurfaceComposerClient.h>
-
-namespace android {
-
-// ---------------------------------------------------------------------------
-
-class IGraphicBufferProducer;
-class Surface;
-class SurfaceComposerClient;
-
-// ---------------------------------------------------------------------------
-
-class SurfaceControl : public RefBase
-{
-public:
- static bool isValid(const sp<SurfaceControl>& surface) {
- return (surface != 0) && surface->isValid();
- }
-
- bool isValid() {
- return mHandle!=0 && mClient!=0;
- }
-
- static bool isSameSurface(
- const sp<SurfaceControl>& lhs, const sp<SurfaceControl>& rhs);
-
- // release surface data from java
- void clear();
-
- // disconnect any api that's connected
- void disconnect();
-
- status_t setLayerStack(uint32_t layerStack);
- status_t setLayer(int32_t layer);
-
- // Sets a Z order relative to the Surface specified by "relativeTo" but
- // without becoming a full child of the relative. Z-ordering works exactly
- // as if it were a child however.
- //
- // As a nod to sanity, only non-child surfaces may have a relative Z-order.
- //
- // This overrides any previous and is overriden by any future calls
- // to setLayer.
- //
- // If the relative dissapears, the Surface will have no layer and be
- // invisible, until the next time set(Relative)Layer is called.
- //
- // TODO: This is probably a hack. Currently it exists only to work around
- // some framework usage of the hidden APPLICATION_MEDIA_OVERLAY window type
- // which allows inserting a window between a SurfaceView and it's main application
- // window. However, since we are using child windows for the SurfaceView, but not using
- // child windows elsewhere in O, the WindowManager can't set the layer appropriately.
- // This is only used by the "TvInputService" and following the port of ViewRootImpl
- // to child surfaces, we can then port this and remove this method.
- status_t setRelativeLayer(const sp<IBinder>& relativeTo, int32_t layer);
- status_t setPosition(float x, float y);
- status_t setSize(uint32_t w, uint32_t h);
- status_t hide();
- status_t show();
- status_t setFlags(uint32_t flags, uint32_t mask);
- status_t setTransparentRegionHint(const Region& transparent);
- status_t setAlpha(float alpha=1.0f);
- status_t setMatrix(float dsdx, float dtdx, float dtdy, float dsdy);
- status_t setCrop(const Rect& crop);
- status_t setFinalCrop(const Rect& crop);
-
- // If the size changes in this transaction, all geometry updates specified
- // in this transaction will not complete until a buffer of the new size
- // arrives. As some elements normally apply immediately, this enables
- // freezing the total geometry of a surface until a resize is completed.
- status_t setGeometryAppliesWithResize();
-
- // Defers applying any changes made in this transaction until the Layer
- // identified by handle reaches the given frameNumber. If the Layer identified
- // by handle is removed, then we will apply this transaction regardless of
- // what frame number has been reached.
- status_t deferTransactionUntil(const sp<IBinder>& handle, uint64_t frameNumber);
-
- // A variant of deferTransactionUntil which identifies the Layer we wait for by
- // Surface instead of Handle. Useful for clients which may not have the
- // SurfaceControl for some of their Surfaces. Otherwise behaves identically.
- status_t deferTransactionUntil(const sp<Surface>& barrier, uint64_t frameNumber);
-
- // Reparents all children of this layer to the new parent handle.
- status_t reparentChildren(const sp<IBinder>& newParentHandle);
-
- // Detaches all child surfaces (and their children recursively)
- // from their SurfaceControl.
- // The child SurfaceControl's will not throw exceptions or return errors,
- // but transactions will have no effect.
- // The child surfaces will continue to follow their parent surfaces,
- // and remain eligible for rendering, but their relative state will be
- // frozen. We use this in the WindowManager, in app shutdown/relaunch
- // scenarios, where the app would otherwise clean up its child Surfaces.
- // Sometimes the WindowManager needs to extend their lifetime slightly
- // in order to perform an exit animation or prevent flicker.
- status_t detachChildren();
-
- // Set an override scaling mode as documented in <system/window.h>
- // the override scaling mode will take precedence over any client
- // specified scaling mode. -1 will clear the override scaling mode.
- status_t setOverrideScalingMode(int32_t overrideScalingMode);
-
- static status_t writeSurfaceToParcel(
- const sp<SurfaceControl>& control, Parcel* parcel);
-
- sp<Surface> getSurface() const;
- sp<IBinder> getHandle() const;
-
- status_t clearLayerFrameStats() const;
- status_t getLayerFrameStats(FrameStats* outStats) const;
-
-private:
- // can't be copied
- SurfaceControl& operator = (SurfaceControl& rhs);
- SurfaceControl(const SurfaceControl& rhs);
-
- friend class SurfaceComposerClient;
- friend class Surface;
-
- SurfaceControl(
- const sp<SurfaceComposerClient>& client,
- const sp<IBinder>& handle,
- const sp<IGraphicBufferProducer>& gbp);
-
- ~SurfaceControl();
-
- status_t validate() const;
- void destroy();
-
- sp<SurfaceComposerClient> mClient;
- sp<IBinder> mHandle;
- sp<IGraphicBufferProducer> mGraphicBufferProducer;
- mutable Mutex mLock;
- mutable sp<Surface> mSurfaceData;
-};
-
-}; // namespace android
-
-#endif // ANDROID_GUI_SURFACE_CONTROL_H
diff --git a/include/input/InputEventLabels.h b/include/input/InputEventLabels.h
index 20154eb..c282cf0 100644
--- a/include/input/InputEventLabels.h
+++ b/include/input/InputEventLabels.h
@@ -323,6 +323,7 @@
DEFINE_KEYCODE(SYSTEM_NAVIGATION_DOWN),
DEFINE_KEYCODE(SYSTEM_NAVIGATION_LEFT),
DEFINE_KEYCODE(SYSTEM_NAVIGATION_RIGHT),
+ DEFINE_KEYCODE(ALL_APPS),
{ NULL, 0 }
};
diff --git a/include/input/InputTransport.h b/include/input/InputTransport.h
index f31bcea..c4b5dca 100644
--- a/include/input/InputTransport.h
+++ b/include/input/InputTransport.h
@@ -65,6 +65,7 @@
nsecs_t eventTime __attribute__((aligned(8)));
int32_t deviceId;
int32_t source;
+ int32_t displayId;
int32_t action;
int32_t flags;
int32_t keyCode;
@@ -83,6 +84,7 @@
nsecs_t eventTime __attribute__((aligned(8)));
int32_t deviceId;
int32_t source;
+ int32_t displayId;
int32_t action;
int32_t actionButton;
int32_t flags;
@@ -232,6 +234,7 @@
uint32_t seq,
int32_t deviceId,
int32_t source,
+ int32_t displayId,
int32_t action,
int32_t actionButton,
int32_t flags,
@@ -303,7 +306,7 @@
* Other errors probably indicate that the channel is broken.
*/
status_t consume(InputEventFactoryInterface* factory, bool consumeBatches,
- nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent);
+ nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent, int32_t* displayId);
/* Sends a finished signal to the publisher to inform it that the message
* with the specified sequence number has finished being process and whether
@@ -367,20 +370,24 @@
int32_t idToIndex[MAX_POINTER_ID + 1];
PointerCoords pointers[MAX_POINTERS];
- void initializeFrom(const InputMessage* msg) {
- eventTime = msg->body.motion.eventTime;
+ void initializeFrom(const InputMessage& msg) {
+ eventTime = msg.body.motion.eventTime;
idBits.clear();
- for (uint32_t i = 0; i < msg->body.motion.pointerCount; i++) {
- uint32_t id = msg->body.motion.pointers[i].properties.id;
+ for (uint32_t i = 0; i < msg.body.motion.pointerCount; i++) {
+ uint32_t id = msg.body.motion.pointers[i].properties.id;
idBits.markBit(id);
idToIndex[id] = i;
- pointers[i].copyFrom(msg->body.motion.pointers[i].coords);
+ pointers[i].copyFrom(msg.body.motion.pointers[i].coords);
}
}
const PointerCoords& getPointerById(uint32_t id) const {
return pointers[idToIndex[id]];
}
+
+ bool hasPointerId(uint32_t id) const {
+ return idBits.hasBit(id);
+ }
};
struct TouchState {
int32_t deviceId;
@@ -399,7 +406,7 @@
lastResample.idBits.clear();
}
- void addHistory(const InputMessage* msg) {
+ void addHistory(const InputMessage& msg) {
historyCurrent ^= 1;
if (historySize < 2) {
historySize += 1;
@@ -410,6 +417,24 @@
const History* getHistory(size_t index) const {
return &history[(historyCurrent + index) & 1];
}
+
+ bool recentCoordinatesAreIdentical(uint32_t id) const {
+ // Return true if the two most recently received "raw" coordinates are identical
+ if (historySize < 2) {
+ return false;
+ }
+ if (!getHistory(0)->hasPointerId(id) || !getHistory(1)->hasPointerId(id)) {
+ return false;
+ }
+ float currentX = getHistory(0)->getPointerById(id).getX();
+ float currentY = getHistory(0)->getPointerById(id).getY();
+ float previousX = getHistory(1)->getPointerById(id).getX();
+ float previousY = getHistory(1)->getPointerById(id).getY();
+ if (currentX == previousX && currentY == previousY) {
+ return true;
+ }
+ return false;
+ }
};
Vector<TouchState> mTouchStates;
@@ -424,12 +449,12 @@
Vector<SeqChain> mSeqChains;
status_t consumeBatch(InputEventFactoryInterface* factory,
- nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent);
+ nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent, int32_t* displayId);
status_t consumeSamples(InputEventFactoryInterface* factory,
- Batch& batch, size_t count, uint32_t* outSeq, InputEvent** outEvent);
+ Batch& batch, size_t count, uint32_t* outSeq, InputEvent** outEvent,
+ int32_t* displayId);
- void updateTouchState(InputMessage* msg);
- void rewriteMessage(const TouchState& state, InputMessage* msg);
+ void updateTouchState(InputMessage& msg);
void resampleTouchState(nsecs_t frameTime, MotionEvent* event,
const InputMessage *next);
@@ -438,6 +463,7 @@
status_t sendUnchainedFinishedSignal(uint32_t seq, bool handled);
+ static bool rewriteMessage(const TouchState& state, InputMessage& msg);
static void initializeKeyEvent(KeyEvent* event, const InputMessage* msg);
static void initializeMotionEvent(MotionEvent* event, const InputMessage* msg);
static void addSample(MotionEvent* event, const InputMessage* msg);
diff --git a/include/input/VelocityTracker.h b/include/input/VelocityTracker.h
index 795f575..ffa1614 100644
--- a/include/input/VelocityTracker.h
+++ b/include/input/VelocityTracker.h
@@ -264,6 +264,40 @@
Movement mMovements[HISTORY_SIZE];
};
+class ImpulseVelocityTrackerStrategy : public VelocityTrackerStrategy {
+public:
+ ImpulseVelocityTrackerStrategy();
+ virtual ~ImpulseVelocityTrackerStrategy();
+
+ virtual void clear();
+ virtual void clearPointers(BitSet32 idBits);
+ virtual void addMovement(nsecs_t eventTime, BitSet32 idBits,
+ const VelocityTracker::Position* positions);
+ virtual bool getEstimator(uint32_t id, VelocityTracker::Estimator* outEstimator) const;
+
+private:
+ // Sample horizon.
+ // We don't use too much history by default since we want to react to quick
+ // changes in direction.
+ static constexpr nsecs_t HORIZON = 100 * 1000000; // 100 ms
+
+ // Number of samples to keep.
+ static constexpr size_t HISTORY_SIZE = 20;
+
+ struct Movement {
+ nsecs_t eventTime;
+ BitSet32 idBits;
+ VelocityTracker::Position positions[MAX_POINTERS];
+
+ inline const VelocityTracker::Position& getPosition(uint32_t id) const {
+ return positions[idBits.getIndexOfBit(id)];
+ }
+ };
+
+ size_t mIndex;
+ Movement mMovements[HISTORY_SIZE];
+};
+
} // namespace android
#endif // _LIBINPUT_VELOCITY_TRACKER_H
diff --git a/include/layerproto b/include/layerproto
new file mode 120000
index 0000000..ef21a4e
--- /dev/null
+++ b/include/layerproto
@@ -0,0 +1 @@
+../services/surfaceflinger/layerproto/include/layerproto/
\ No newline at end of file
diff --git a/include/media b/include/media
new file mode 120000
index 0000000..3e7da1c
--- /dev/null
+++ b/include/media
@@ -0,0 +1 @@
+../headers/media_plugin/media
\ No newline at end of file
diff --git a/include/private/gui b/include/private/gui
new file mode 120000
index 0000000..99de2dc
--- /dev/null
+++ b/include/private/gui
@@ -0,0 +1 @@
+../../libs/gui/include/private/gui
\ No newline at end of file
diff --git a/include/private/ui/RegionHelper.h b/include/private/ui/RegionHelper.h
index a86c586..0ec3e94 100644
--- a/include/private/ui/RegionHelper.h
+++ b/include/private/ui/RegionHelper.h
@@ -21,6 +21,8 @@
#include <stdint.h>
#include <sys/types.h>
+#include <limits>
+
namespace android {
// ----------------------------------------------------------------------------
@@ -79,7 +81,6 @@
int inside = spanner.next(current.top, current.bottom);
spannerInner.prepare(inside);
do {
- TYPE left, right;
int inner_inside = spannerInner.next(current.left, current.right);
if ((op_mask >> inner_inside) & 1) {
if (current.left < current.right &&
diff --git a/include_sensor/android/looper.h b/include_sensor/android/looper.h
new file mode 120000
index 0000000..0cf51b8
--- /dev/null
+++ b/include_sensor/android/looper.h
@@ -0,0 +1 @@
+../../include/android/looper.h
\ No newline at end of file
diff --git a/include_sensor/android/sensor.h b/include_sensor/android/sensor.h
new file mode 120000
index 0000000..0626f4f
--- /dev/null
+++ b/include_sensor/android/sensor.h
@@ -0,0 +1 @@
+../../include/android/sensor.h
\ No newline at end of file
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index 204fdb5..83b8021 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -15,6 +15,17 @@
cc_library_headers {
name: "libbinder_headers",
export_include_dirs: ["include"],
+ vendor_available: true,
+ header_libs: [
+ "libbase_headers",
+ "libcutils_headers",
+ "libutils_headers",
+ ],
+ export_header_lib_headers: [
+ "libbase_headers",
+ "libcutils_headers",
+ "libutils_headers",
+ ],
}
cc_library {
@@ -22,6 +33,9 @@
// for vndbinder
vendor_available: true,
+ vndk: {
+ enabled: true,
+ },
srcs: [
"AppOpsManager.cpp",
@@ -55,8 +69,13 @@
"TextOutput.cpp",
"IpPrefix.cpp",
"Value.cpp",
+ "aidl/android/content/pm/IPackageManagerNative.aidl",
],
+ aidl: {
+ export_aidl_headers: true,
+ },
+
cflags: [
"-Wall",
"-Wextra",
@@ -74,13 +93,13 @@
"libcutils",
"libutils",
],
- export_shared_lib_headers: [
- "libbase",
- "libutils",
+
+ header_libs: [
+ "libbinder_headers",
],
- export_include_dirs: [
- "include",
+ export_header_lib_headers: [
+ "libbinder_headers",
],
clang: true,
diff --git a/libs/binder/Binder.cpp b/libs/binder/Binder.cpp
index 890ef30..a81f44e 100644
--- a/libs/binder/Binder.cpp
+++ b/libs/binder/Binder.cpp
@@ -249,6 +249,8 @@
if (resultReceiver != NULL) {
resultReceiver->send(INVALID_OPERATION);
}
+
+ return NO_ERROR;
}
case SYSPROPS_TRANSACTION: {
diff --git a/libs/binder/BpBinder.cpp b/libs/binder/BpBinder.cpp
index c0e0296..289433b 100644
--- a/libs/binder/BpBinder.cpp
+++ b/libs/binder/BpBinder.cpp
@@ -21,6 +21,7 @@
#include <binder/IPCThreadState.h>
#include <binder/IResultReceiver.h>
+#include <cutils/compiler.h>
#include <utils/Log.h>
#include <stdio.h>
@@ -32,6 +33,23 @@
// ---------------------------------------------------------------------------
+Mutex BpBinder::sTrackingLock;
+std::unordered_map<int32_t,uint32_t> BpBinder::sTrackingMap;
+int BpBinder::sNumTrackedUids = 0;
+std::atomic_bool BpBinder::sCountByUidEnabled(false);
+binder_proxy_limit_callback BpBinder::sLimitCallback;
+bool BpBinder::sBinderProxyThrottleCreate = false;
+
+// Arbitrarily high value that probably distinguishes a bad behaving app
+uint32_t BpBinder::sBinderProxyCountHighWatermark = 2500;
+// Another arbitrary value a binder count needs to drop below before another callback will be called
+uint32_t BpBinder::sBinderProxyCountLowWatermark = 2000;
+
+enum {
+ CALLBACK_TRIGGERED_MASK = 0x80000000, // A flag denoting that the callback has been called
+ COUNTING_VALUE_MASK = 0x7FFFFFFF, // A mask of the remaining bits for the count value
+};
+
BpBinder::ObjectManager::ObjectManager()
{
}
@@ -87,11 +105,47 @@
// ---------------------------------------------------------------------------
-BpBinder::BpBinder(int32_t handle)
+
+BpBinder* BpBinder::create(int32_t handle) {
+ int32_t trackedUid = -1;
+ if (sCountByUidEnabled) {
+ BpBinder* out;
+ trackedUid = IPCThreadState::self()->getCallingUid();
+ AutoMutex _l(sTrackingLock);
+ if ((sTrackingMap[trackedUid] & COUNTING_VALUE_MASK) >= sBinderProxyCountHighWatermark) {
+ ALOGE("Too many binder proxy objects sent to uid %d from uid %d (over %d proxies held)",
+ getuid(), trackedUid, sBinderProxyCountHighWatermark);
+
+ if (sBinderProxyThrottleCreate) {
+ ALOGE("Returning Null Binder Proxy Object to uid %d", trackedUid);
+ out = nullptr;
+ } else {
+ // increment and construct here in case callback has an async kill causing a race
+ sTrackingMap[trackedUid]++;
+ out = new BpBinder(handle, trackedUid);
+ }
+
+ if (sLimitCallback && !(sTrackingMap[trackedUid] & CALLBACK_TRIGGERED_MASK)) {
+ sTrackingMap[trackedUid] |= CALLBACK_TRIGGERED_MASK;
+ sLimitCallback(trackedUid);
+ }
+ } else {
+ sTrackingMap[trackedUid]++;
+ out = new BpBinder(handle, trackedUid);
+ }
+
+ return out;
+ } else {
+ return new BpBinder(handle, trackedUid);
+ }
+}
+
+BpBinder::BpBinder(int32_t handle, int32_t trackedUid)
: mHandle(handle)
, mAlive(1)
, mObitsSent(0)
, mObituaries(NULL)
+ , mTrackedUid(trackedUid)
{
ALOGV("Creating BpBinder %p handle %d\n", this, mHandle);
@@ -315,6 +369,24 @@
IPCThreadState* ipc = IPCThreadState::self();
+ if (mTrackedUid >= 0) {
+ AutoMutex _l(sTrackingLock);
+ if (CC_UNLIKELY(sTrackingMap[mTrackedUid] == 0)) {
+ ALOGE("Unexpected Binder Proxy tracking decrement in %p handle %d\n", this, mHandle);
+ } else {
+ if (CC_UNLIKELY(
+ (sTrackingMap[mTrackedUid] & CALLBACK_TRIGGERED_MASK) &&
+ ((sTrackingMap[mTrackedUid] & COUNTING_VALUE_MASK) <= sBinderProxyCountLowWatermark)
+ )) {
+ // Clear the Callback Triggered bit when crossing below the low watermark
+ sTrackingMap[mTrackedUid] &= ~CALLBACK_TRIGGERED_MASK;
+ }
+ if (--sTrackingMap[mTrackedUid] == 0) {
+ sTrackingMap.erase(mTrackedUid);
+ }
+ }
+ }
+
mLock.lock();
Vector<Obituary>* obits = mObituaries;
if(obits != NULL) {
@@ -360,6 +432,42 @@
return ipc ? ipc->attemptIncStrongHandle(mHandle) == NO_ERROR : false;
}
+uint32_t BpBinder::getBinderProxyCount(uint32_t uid)
+{
+ AutoMutex _l(sTrackingLock);
+ auto it = sTrackingMap.find(uid);
+ if (it != sTrackingMap.end()) {
+ return it->second & COUNTING_VALUE_MASK;
+ }
+ return 0;
+}
+
+void BpBinder::getCountByUid(Vector<uint32_t>& uids, Vector<uint32_t>& counts)
+{
+ AutoMutex _l(sTrackingLock);
+ uids.setCapacity(sTrackingMap.size());
+ counts.setCapacity(sTrackingMap.size());
+ for (const auto& it : sTrackingMap) {
+ uids.push_back(it.first);
+ counts.push_back(it.second & COUNTING_VALUE_MASK);
+ }
+}
+
+void BpBinder::enableCountByUid() { sCountByUidEnabled.store(true); }
+void BpBinder::disableCountByUid() { sCountByUidEnabled.store(false); }
+void BpBinder::setCountByUidEnabled(bool enable) { sCountByUidEnabled.store(enable); }
+
+void BpBinder::setLimitCallback(binder_proxy_limit_callback cb) {
+ AutoMutex _l(sTrackingLock);
+ sLimitCallback = cb;
+}
+
+void BpBinder::setBinderProxyCountWatermarks(int high, int low) {
+ AutoMutex _l(sTrackingLock);
+ sBinderProxyCountHighWatermark = high;
+ sBinderProxyCountLowWatermark = low;
+}
+
// ---------------------------------------------------------------------------
}; // namespace android
diff --git a/libs/binder/Debug.cpp b/libs/binder/Debug.cpp
index a8f2da5..4ac61a3 100644
--- a/libs/binder/Debug.cpp
+++ b/libs/binder/Debug.cpp
@@ -15,6 +15,7 @@
*/
#include <binder/Debug.h>
+#include <binder/ProcessState.h>
#include <utils/misc.h>
@@ -294,5 +295,14 @@
}
}
+ssize_t getBinderKernelReferences(size_t count, uintptr_t* buf) {
+ sp<ProcessState> proc = ProcessState::selfOrNull();
+ if (proc.get() == NULL) {
+ return 0;
+ }
+
+ return proc->getKernelReferences(count, buf);
+}
+
}; // namespace android
diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp
index e832961..ba9bf61 100644
--- a/libs/binder/IPCThreadState.cpp
+++ b/libs/binder/IPCThreadState.cpp
@@ -470,22 +470,33 @@
void IPCThreadState::processPendingDerefs()
{
if (mIn.dataPosition() >= mIn.dataSize()) {
- size_t numPending = mPendingWeakDerefs.size();
- if (numPending > 0) {
- for (size_t i = 0; i < numPending; i++) {
- RefBase::weakref_type* refs = mPendingWeakDerefs[i];
+ /*
+ * The decWeak()/decStrong() calls may cause a destructor to run,
+ * which in turn could have initiated an outgoing transaction,
+ * which in turn could cause us to add to the pending refs
+ * vectors; so instead of simply iterating, loop until they're empty.
+ *
+ * We do this in an outer loop, because calling decStrong()
+ * may result in something being added to mPendingWeakDerefs,
+ * which could be delayed until the next incoming command
+ * from the driver if we don't process it now.
+ */
+ while (mPendingWeakDerefs.size() > 0 || mPendingStrongDerefs.size() > 0) {
+ while (mPendingWeakDerefs.size() > 0) {
+ RefBase::weakref_type* refs = mPendingWeakDerefs[0];
+ mPendingWeakDerefs.removeAt(0);
refs->decWeak(mProcess.get());
}
- mPendingWeakDerefs.clear();
- }
- numPending = mPendingStrongDerefs.size();
- if (numPending > 0) {
- for (size_t i = 0; i < numPending; i++) {
- BBinder* obj = mPendingStrongDerefs[i];
+ if (mPendingStrongDerefs.size() > 0) {
+ // We don't use while() here because we don't want to re-order
+ // strong and weak decs at all; if this decStrong() causes both a
+ // decWeak() and a decStrong() to be queued, we want to process
+ // the decWeak() first.
+ BBinder* obj = mPendingStrongDerefs[0];
+ mPendingStrongDerefs.removeAt(0);
obj->decStrong(mProcess.get());
}
- mPendingStrongDerefs.clear();
}
}
}
@@ -560,7 +571,7 @@
uint32_t code, const Parcel& data,
Parcel* reply, uint32_t flags)
{
- status_t err = data.errorCheck();
+ status_t err;
flags |= TF_ACCEPT_FDS;
@@ -571,11 +582,9 @@
<< indent << data << dedent << endl;
}
- if (err == NO_ERROR) {
- LOG_ONEWAY(">>>> SEND from pid %d uid %d %s", getpid(), getuid(),
- (flags & TF_ONE_WAY) == 0 ? "READ REPLY" : "ONE WAY");
- err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, NULL);
- }
+ LOG_ONEWAY(">>>> SEND from pid %d uid %d %s", getpid(), getuid(),
+ (flags & TF_ONE_WAY) == 0 ? "READ REPLY" : "ONE WAY");
+ err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, NULL);
if (err != NO_ERROR) {
if (reply) reply->setError(err);
@@ -675,7 +684,7 @@
#if LOG_REFCOUNTS
ALOGV("IPCThreadState::expungeHandle(%ld)\n", handle);
#endif
- self()->mProcess->expungeHandle(handle, binder);
+ self()->mProcess->expungeHandle(handle, binder); // NOLINT
}
status_t IPCThreadState::requestDeathNotification(int32_t handle, BpBinder* proxy)
diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp
index c7a0f43..70f5108 100644
--- a/libs/binder/IServiceManager.cpp
+++ b/libs/binder/IServiceManager.cpp
@@ -161,19 +161,18 @@
}
virtual status_t addService(const String16& name, const sp<IBinder>& service,
- bool allowIsolated)
- {
+ bool allowIsolated, int dumpsysPriority) {
Parcel data, reply;
data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
data.writeString16(name);
data.writeStrongBinder(service);
data.writeInt32(allowIsolated ? 1 : 0);
+ data.writeInt32(dumpsysPriority);
status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply);
return err == NO_ERROR ? reply.readExceptionCode() : err;
}
- virtual Vector<String16> listServices()
- {
+ virtual Vector<String16> listServices(int dumpsysPriority) {
Vector<String16> res;
int n = 0;
@@ -181,6 +180,7 @@
Parcel data, reply;
data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
data.writeInt32(n++);
+ data.writeInt32(dumpsysPriority);
status_t err = remote()->transact(LIST_SERVICES_TRANSACTION, data, &reply);
if (err != NO_ERROR)
break;
diff --git a/libs/binder/IShellCallback.cpp b/libs/binder/IShellCallback.cpp
index c793df3..23b83a6 100644
--- a/libs/binder/IShellCallback.cpp
+++ b/libs/binder/IShellCallback.cpp
@@ -39,11 +39,13 @@
{
}
- virtual int openOutputFile(const String16& path, const String16& seLinuxContext) {
+ virtual int openFile(const String16& path, const String16& seLinuxContext,
+ const String16& mode) {
Parcel data, reply;
data.writeInterfaceToken(IShellCallback::getInterfaceDescriptor());
data.writeString16(path);
data.writeString16(seLinuxContext);
+ data.writeString16(mode);
remote()->transact(OP_OPEN_OUTPUT_FILE, data, &reply, 0);
reply.readExceptionCode();
int fd = reply.readParcelFileDescriptor();
@@ -64,7 +66,8 @@
CHECK_INTERFACE(IShellCallback, data, reply);
String16 path(data.readString16());
String16 seLinuxContext(data.readString16());
- int fd = openOutputFile(path, seLinuxContext);
+ String16 mode(data.readString16());
+ int fd = openFile(path, seLinuxContext, mode);
if (reply != NULL) {
reply->writeNoException();
if (fd >= 0) {
diff --git a/libs/binder/MemoryDealer.cpp b/libs/binder/MemoryDealer.cpp
index 2a15773..1cfe02a 100644
--- a/libs/binder/MemoryDealer.cpp
+++ b/libs/binder/MemoryDealer.cpp
@@ -289,7 +289,15 @@
SimpleBestFitAllocator::~SimpleBestFitAllocator()
{
while(!mList.isEmpty()) {
- delete mList.remove(mList.head());
+ chunk_t* removed = mList.remove(mList.head());
+#ifdef __clang_analyzer__
+ // Clang static analyzer gets confused in this loop
+ // and generates a false positive warning about accessing
+ // memory that is already freed.
+ // Add an "assert" to avoid the confusion.
+ LOG_ALWAYS_FATAL_IF(mList.head() == removed);
+#endif
+ delete removed;
}
}
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index aec8f10..f739f07 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -104,7 +104,7 @@
void acquire_object(const sp<ProcessState>& proc,
const flat_binder_object& obj, const void* who, size_t* outAshmemSize)
{
- switch (obj.type) {
+ switch (obj.hdr.type) {
case BINDER_TYPE_BINDER:
if (obj.binder) {
LOG_REFS("Parcel %p acquiring reference on local %p", who, obj.cookie);
@@ -140,7 +140,7 @@
}
}
- ALOGD("Invalid object type 0x%08x", obj.type);
+ ALOGD("Invalid object type 0x%08x", obj.hdr.type);
}
void acquire_object(const sp<ProcessState>& proc,
@@ -152,7 +152,7 @@
static void release_object(const sp<ProcessState>& proc,
const flat_binder_object& obj, const void* who, size_t* outAshmemSize)
{
- switch (obj.type) {
+ switch (obj.hdr.type) {
case BINDER_TYPE_BINDER:
if (obj.binder) {
LOG_REFS("Parcel %p releasing reference on local %p", who, obj.cookie);
@@ -191,7 +191,7 @@
}
}
- ALOGE("Invalid object type 0x%08x", obj.type);
+ ALOGE("Invalid object type 0x%08x", obj.hdr.type);
}
void release_object(const sp<ProcessState>& proc,
@@ -227,17 +227,17 @@
ALOGE("null proxy");
}
const int32_t handle = proxy ? proxy->handle() : 0;
- obj.type = BINDER_TYPE_HANDLE;
+ obj.hdr.type = BINDER_TYPE_HANDLE;
obj.binder = 0; /* Don't pass uninitialized stack data to a remote process */
obj.handle = handle;
obj.cookie = 0;
} else {
- obj.type = BINDER_TYPE_BINDER;
+ obj.hdr.type = BINDER_TYPE_BINDER;
obj.binder = reinterpret_cast<uintptr_t>(local->getWeakRefs());
obj.cookie = reinterpret_cast<uintptr_t>(local);
}
} else {
- obj.type = BINDER_TYPE_BINDER;
+ obj.hdr.type = BINDER_TYPE_BINDER;
obj.binder = 0;
obj.cookie = 0;
}
@@ -261,12 +261,12 @@
ALOGE("null proxy");
}
const int32_t handle = proxy ? proxy->handle() : 0;
- obj.type = BINDER_TYPE_WEAK_HANDLE;
+ obj.hdr.type = BINDER_TYPE_WEAK_HANDLE;
obj.binder = 0; /* Don't pass uninitialized stack data to a remote process */
obj.handle = handle;
obj.cookie = 0;
} else {
- obj.type = BINDER_TYPE_WEAK_BINDER;
+ obj.hdr.type = BINDER_TYPE_WEAK_BINDER;
obj.binder = reinterpret_cast<uintptr_t>(binder.get_refs());
obj.cookie = reinterpret_cast<uintptr_t>(binder.unsafe_get());
}
@@ -281,13 +281,13 @@
// but we can't do that with the different reference counting
// implementation we are using.
ALOGE("Unable to unflatten Binder weak reference!");
- obj.type = BINDER_TYPE_BINDER;
+ obj.hdr.type = BINDER_TYPE_BINDER;
obj.binder = 0;
obj.cookie = 0;
return finish_flatten_binder(NULL, obj, out);
} else {
- obj.type = BINDER_TYPE_BINDER;
+ obj.hdr.type = BINDER_TYPE_BINDER;
obj.binder = 0;
obj.cookie = 0;
return finish_flatten_binder(NULL, obj, out);
@@ -307,7 +307,7 @@
const flat_binder_object* flat = in.readObject(false);
if (flat) {
- switch (flat->type) {
+ switch (flat->hdr.type) {
case BINDER_TYPE_BINDER:
*out = reinterpret_cast<IBinder*>(flat->cookie);
return finish_unflatten_binder(NULL, *flat, in);
@@ -326,7 +326,7 @@
const flat_binder_object* flat = in.readObject(false);
if (flat) {
- switch (flat->type) {
+ switch (flat->hdr.type) {
case BINDER_TYPE_BINDER:
*out = reinterpret_cast<IBinder*>(flat->cookie);
return finish_unflatten_binder(NULL, *flat, in);
@@ -543,7 +543,7 @@
= reinterpret_cast<flat_binder_object*>(mData + off);
acquire_object(proc, *flat, this, &mOpenAshmemSize);
- if (flat->type == BINDER_TYPE_FD) {
+ if (flat->hdr.type == BINDER_TYPE_FD) {
// If this is a file descriptor, we need to dup it so the
// new Parcel now owns its own fd, and can declare that we
// officially know we have fds.
@@ -1152,7 +1152,7 @@
status_t Parcel::writeFileDescriptor(int fd, bool takeOwnership)
{
flat_binder_object obj;
- obj.type = BINDER_TYPE_FD;
+ obj.hdr.type = BINDER_TYPE_FD;
obj.flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
obj.binder = 0; /* Don't pass uninitialized stack data to a remote process */
obj.handle = fd;
@@ -1310,7 +1310,7 @@
*reinterpret_cast<flat_binder_object*>(mData+mDataPos) = val;
// remember if it's a file descriptor
- if (val.type == BINDER_TYPE_FD) {
+ if (val.hdr.type == BINDER_TYPE_FD) {
if (!mAllowFds) {
// fail before modifying our object index
return FDS_NOT_ALLOWED;
@@ -1851,7 +1851,7 @@
status_t Parcel::readBool(bool *pArg) const
{
- int32_t tmp;
+ int32_t tmp = 0;
status_t ret = readInt32(&tmp);
*pArg = (tmp != 0);
return ret;
@@ -1864,7 +1864,7 @@
status_t Parcel::readChar(char16_t *pArg) const
{
- int32_t tmp;
+ int32_t tmp = 0;
status_t ret = readInt32(&tmp);
*pArg = char16_t(tmp);
return ret;
@@ -1877,7 +1877,7 @@
status_t Parcel::readByte(int8_t *pArg) const
{
- int32_t tmp;
+ int32_t tmp = 0;
status_t ret = readInt32(&tmp);
*pArg = int8_t(tmp);
return ret;
@@ -2132,7 +2132,7 @@
{
const flat_binder_object* flat = readObject(true);
- if (flat && flat->type == BINDER_TYPE_FD) {
+ if (flat && flat->hdr.type == BINDER_TYPE_FD) {
return flat->handle;
}
@@ -2325,7 +2325,7 @@
i--;
const flat_binder_object* flat
= reinterpret_cast<flat_binder_object*>(mData+mObjects[i]);
- if (flat->type == BINDER_TYPE_FD) {
+ if (flat->hdr.type == BINDER_TYPE_FD) {
//ALOGI("Closing fd: %ld", flat->handle);
close(flat->handle);
}
@@ -2397,7 +2397,7 @@
const flat_binder_object* flat
= reinterpret_cast<const flat_binder_object*>(DATA+OBJS[i]);
to << endl << "Object #" << i << " @ " << (void*)OBJS[i] << ": "
- << TypeCode(flat->type & 0x7f7f7f00)
+ << TypeCode(flat->hdr.type & 0x7f7f7f00)
<< " = " << flat->binder;
}
} else {
@@ -2618,7 +2618,7 @@
for (size_t i=objectsSize; i<mObjectsSize; i++) {
const flat_binder_object* flat
= reinterpret_cast<flat_binder_object*>(mData+mObjects[i]);
- if (flat->type == BINDER_TYPE_FD) {
+ if (flat->hdr.type == BINDER_TYPE_FD) {
// will need to rescan because we may have lopped off the only FDs
mFdsKnown = false;
}
@@ -2645,7 +2645,7 @@
pthread_mutex_unlock(&gParcelGlobalAllocSizeLock);
mData = data;
mDataCapacity = desired;
- } else if (desired > mDataCapacity) {
+ } else {
mError = NO_MEMORY;
return NO_MEMORY;
}
@@ -2728,7 +2728,7 @@
for (size_t i=0; i<mObjectsSize; i++) {
const flat_binder_object* flat
= reinterpret_cast<const flat_binder_object*>(mData + mObjects[i]);
- if (flat->type == BINDER_TYPE_FD) {
+ if (flat->hdr.type == BINDER_TYPE_FD) {
hasFds = true;
break;
}
diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp
index add5e74..44039f8 100644
--- a/libs/binder/ProcessState.cpp
+++ b/libs/binder/ProcessState.cpp
@@ -90,6 +90,12 @@
return gProcess;
}
+sp<ProcessState> ProcessState::selfOrNull()
+{
+ Mutex::Autolock _l(gProcessMutex);
+ return gProcess;
+}
+
void ProcessState::setContextObject(const sp<IBinder>& object)
{
setContextObject(object, String16("default"));
@@ -176,6 +182,46 @@
return mManagesContexts;
}
+// Get references to userspace objects held by the kernel binder driver
+// Writes up to count elements into buf, and returns the total number
+// of references the kernel has, which may be larger than count.
+// buf may be NULL if count is 0. The pointers returned by this method
+// should only be used for debugging and not dereferenced, they may
+// already be invalid.
+ssize_t ProcessState::getKernelReferences(size_t buf_count, uintptr_t* buf)
+{
+ // TODO: remove these when they are defined by bionic's binder.h
+ struct binder_node_debug_info {
+ binder_uintptr_t ptr;
+ binder_uintptr_t cookie;
+ __u32 has_strong_ref;
+ __u32 has_weak_ref;
+ };
+#define BINDER_GET_NODE_DEBUG_INFO _IOWR('b', 11, struct binder_node_debug_info)
+
+ binder_node_debug_info info = {};
+
+ uintptr_t* end = buf ? buf + buf_count : NULL;
+ size_t count = 0;
+
+ do {
+ status_t result = ioctl(mDriverFD, BINDER_GET_NODE_DEBUG_INFO, &info);
+ if (result < 0) {
+ return -1;
+ }
+ if (info.ptr != 0) {
+ if (buf && buf < end)
+ *buf++ = info.ptr;
+ count++;
+ if (buf && buf < end)
+ *buf++ = info.cookie;
+ count++;
+ }
+ } while (info.ptr != 0);
+
+ return count;
+}
+
ProcessState::handle_entry* ProcessState::lookupHandleLocked(int32_t handle)
{
const size_t N=mHandleToObject.size();
@@ -230,7 +276,7 @@
return NULL;
}
- b = new BpBinder(handle);
+ b = BpBinder::create(handle);
e->binder = b;
if (b) e->refs = b->getWeakRefs();
result = b;
@@ -264,7 +310,7 @@
// arriving from the driver.
IBinder* b = e->binder;
if (b == NULL || !e->refs->attemptIncWeak(this)) {
- b = new BpBinder(handle);
+ b = BpBinder::create(handle);
result = b;
e->binder = b;
if (b) e->refs = b->getWeakRefs();
diff --git a/libs/binder/Value.cpp b/libs/binder/Value.cpp
index fd1dfd5..85cd739 100644
--- a/libs/binder/Value.cpp
+++ b/libs/binder/Value.cpp
@@ -182,10 +182,12 @@
Value& Value::operator=(const Value& rhs)
{
- delete mContent;
- mContent = rhs.mContent
- ? rhs.mContent->clone()
- : NULL;
+ if (this != &rhs) {
+ delete mContent;
+ mContent = rhs.mContent
+ ? rhs.mContent->clone()
+ : NULL;
+ }
return *this;
}
diff --git a/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl b/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl
new file mode 100644
index 0000000..3264666
--- /dev/null
+++ b/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl
@@ -0,0 +1,57 @@
+/*
+**
+** 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.
+*/
+
+package android.content.pm;
+
+/**
+ * Parallel implementation of certain {@link PackageManager} APIs that need to
+ * be exposed to native code.
+ * <p>These APIs are a parallel definition to the APIs in PackageManager, so,
+ * they can technically diverge. However, it's good practice to keep these
+ * APIs in sync with each other.
+ * <p>Because these APIs are exposed to native code, it's possible they will
+ * be exposed to privileged components [such as UID 0]. Care should be taken
+ * to avoid exposing potential security holes for methods where permission
+ * checks are bypassed based upon UID alone.
+ *
+ * @hide
+ */
+interface IPackageManagerNative {
+ /**
+ * Returns a set of names for the given UIDs.
+ * IMPORTANT: Unlike the Java version of this API, unknown UIDs are
+ * not represented by 'null's. Instead, they are represented by empty
+ * strings.
+ */
+ @utf8InCpp String[] getNamesForUids(in int[] uids);
+
+ /**
+ * Returns the name of the installer (a package) which installed the named
+ * package. Preloaded packages return the string "preload". Sideloaded packages
+ * return an empty string. Unknown or unknowable are returned as empty strings.
+ */
+
+ @utf8InCpp String getInstallerForPackage(in String packageName);
+
+ /**
+ * Returns the version code of the named package.
+ * Unknown or unknowable versions are returned as 0.
+ */
+
+ int getVersionCodeForPackage(in String packageName);
+
+}
diff --git a/libs/binder/include/binder/BinderService.h b/libs/binder/include/binder/BinderService.h
index ef703bd..4ce82a1 100644
--- a/libs/binder/include/binder/BinderService.h
+++ b/libs/binder/include/binder/BinderService.h
@@ -34,15 +34,17 @@
class BinderService
{
public:
- static status_t publish(bool allowIsolated = false) {
+ static status_t publish(bool allowIsolated = false,
+ int dumpFlags = IServiceManager::DUMP_FLAG_PRIORITY_NORMAL) {
sp<IServiceManager> sm(defaultServiceManager());
- return sm->addService(
- String16(SERVICE::getServiceName()),
- new SERVICE(), allowIsolated);
+ return sm->addService(String16(SERVICE::getServiceName()), new SERVICE(), allowIsolated,
+ dumpFlags);
}
- static void publishAndJoinThreadPool(bool allowIsolated = false) {
- publish(allowIsolated);
+ static void publishAndJoinThreadPool(
+ bool allowIsolated = false,
+ int dumpFlags = IServiceManager::DUMP_FLAG_PRIORITY_NORMAL) {
+ publish(allowIsolated, dumpFlags);
joinThreadPool();
}
diff --git a/libs/binder/include/binder/BpBinder.h b/libs/binder/include/binder/BpBinder.h
index 7ef93aa..8bd297b 100644
--- a/libs/binder/include/binder/BpBinder.h
+++ b/libs/binder/include/binder/BpBinder.h
@@ -19,15 +19,20 @@
#include <binder/IBinder.h>
#include <utils/KeyedVector.h>
+#include <utils/Mutex.h>
#include <utils/threads.h>
+#include <unordered_map>
+
// ---------------------------------------------------------------------------
namespace android {
+using binder_proxy_limit_callback = void(*)(int);
+
class BpBinder : public IBinder
{
public:
- BpBinder(int32_t handle);
+ static BpBinder* create(int32_t handle);
inline int32_t handle() const { return mHandle; }
@@ -61,6 +66,14 @@
status_t setConstantData(const void* data, size_t size);
void sendObituary();
+ static uint32_t getBinderProxyCount(uint32_t uid);
+ static void getCountByUid(Vector<uint32_t>& uids, Vector<uint32_t>& counts);
+ static void enableCountByUid();
+ static void disableCountByUid();
+ static void setCountByUidEnabled(bool enable);
+ static void setLimitCallback(binder_proxy_limit_callback cb);
+ static void setBinderProxyCountWatermarks(int high, int low);
+
class ObjectManager
{
public:
@@ -91,6 +104,7 @@
};
protected:
+ BpBinder(int32_t handle,int32_t trackedUid);
virtual ~BpBinder();
virtual void onFirstRef();
virtual void onLastStrongRef(const void* id);
@@ -115,6 +129,16 @@
ObjectManager mObjects;
Parcel* mConstantData;
mutable String16 mDescriptorCache;
+ int32_t mTrackedUid;
+
+ static Mutex sTrackingLock;
+ static std::unordered_map<int32_t,uint32_t> sTrackingMap;
+ static int sNumTrackedUids;
+ static std::atomic_bool sCountByUidEnabled;
+ static binder_proxy_limit_callback sLimitCallback;
+ static uint32_t sBinderProxyCountHighWatermark;
+ static uint32_t sBinderProxyCountLowWatermark;
+ static bool sBinderProxyThrottleCreate;
};
}; // namespace android
diff --git a/libs/binder/include/binder/Debug.h b/libs/binder/include/binder/Debug.h
index f6a3355..be0266c 100644
--- a/libs/binder/include/binder/Debug.h
+++ b/libs/binder/include/binder/Debug.h
@@ -18,14 +18,13 @@
#define ANDROID_BINDER_DEBUG_H
#include <stdint.h>
+#include <sys/cdefs.h>
#include <sys/types.h>
namespace android {
// ---------------------------------------------------------------------------
-#ifdef __cplusplus
-extern "C" {
-#endif
+__BEGIN_DECLS
const char* stringForIndent(int32_t indentLevel);
@@ -39,9 +38,10 @@
size_t alignment=0, bool cArrayStyle=false,
debugPrintFunc func = 0, void* cookie = 0);
-#ifdef __cplusplus
-}
-#endif
+
+ssize_t getBinderKernelReferences(size_t count, uintptr_t* buf);
+
+__END_DECLS
// ---------------------------------------------------------------------------
}; // namespace android
diff --git a/libs/binder/include/binder/IServiceManager.h b/libs/binder/include/binder/IServiceManager.h
index 3b23f81..19e841a 100644
--- a/libs/binder/include/binder/IServiceManager.h
+++ b/libs/binder/include/binder/IServiceManager.h
@@ -31,6 +31,15 @@
{
public:
DECLARE_META_INTERFACE(ServiceManager)
+ /*
+ * Must match values in IServiceManager.java
+ */
+ static const int DUMP_FLAG_PRIORITY_CRITICAL = 1 << 0;
+ static const int DUMP_FLAG_PRIORITY_HIGH = 1 << 1;
+ static const int DUMP_FLAG_PRIORITY_NORMAL = 1 << 2;
+ static const int DUMP_FLAG_PRIORITY_ALL =
+ DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PRIORITY_HIGH | DUMP_FLAG_PRIORITY_NORMAL;
+ static const int DUMP_FLAG_PROTO = 1 << 3;
/**
* Retrieve an existing service, blocking for a few seconds
@@ -46,14 +55,14 @@
/**
* Register a service.
*/
- virtual status_t addService( const String16& name,
- const sp<IBinder>& service,
- bool allowIsolated = false) = 0;
+ virtual status_t addService(const String16& name, const sp<IBinder>& service,
+ bool allowIsolated = false,
+ int dumpsysFlags = DUMP_FLAG_PRIORITY_NORMAL) = 0;
/**
* Return list of all existing services.
*/
- virtual Vector<String16> listServices() = 0;
+ virtual Vector<String16> listServices(int dumpsysFlags = DUMP_FLAG_PRIORITY_ALL) = 0;
enum {
GET_SERVICE_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION,
diff --git a/libs/binder/include/binder/IShellCallback.h b/libs/binder/include/binder/IShellCallback.h
index fda9ee6..b47e995 100644
--- a/libs/binder/include/binder/IShellCallback.h
+++ b/libs/binder/include/binder/IShellCallback.h
@@ -29,7 +29,8 @@
public:
DECLARE_META_INTERFACE(ShellCallback);
- virtual int openOutputFile(const String16& path, const String16& seLinuxContext) = 0;
+ virtual int openFile(const String16& path, const String16& seLinuxContext,
+ const String16& mode) = 0;
enum {
OP_OPEN_OUTPUT_FILE = IBinder::FIRST_CALL_TRANSACTION
diff --git a/libs/binder/include/binder/ProcessState.h b/libs/binder/include/binder/ProcessState.h
index 1ef045d..f85c261 100644
--- a/libs/binder/include/binder/ProcessState.h
+++ b/libs/binder/include/binder/ProcessState.h
@@ -35,6 +35,7 @@
{
public:
static sp<ProcessState> self();
+ static sp<ProcessState> selfOrNull();
/* initWithDriver() can be used to configure libbinder to use
* a different binder driver dev node. It must be called *before*
* any call to ProcessState::self(). /dev/binder remains the default.
@@ -71,6 +72,8 @@
String8 getDriverName();
+ ssize_t getKernelReferences(size_t count, uintptr_t* buf);
+
private:
friend class IPCThreadState;
diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp
index 853ca16..c451780 100644
--- a/libs/binder/tests/Android.bp
+++ b/libs/binder/tests/Android.bp
@@ -14,6 +14,24 @@
// limitations under the License.
//
+cc_defaults {
+ name: "binder_test_defaults",
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wno-unused-private-field",
+ "-Wno-unused-variable",
+ ],
+}
+
+cc_test {
+ name: "binderDriverInterfaceTest_IPC_32",
+ srcs: ["binderDriverInterfaceTest.cpp"],
+ defaults: ["binder_test_defaults"],
+ compile_multilib: "32",
+ cflags: ["-DBINDER_IPC_32BIT=1"],
+}
+
cc_test {
product_variables: {
binder32bit: {
@@ -23,11 +41,13 @@
name: "binderDriverInterfaceTest",
srcs: ["binderDriverInterfaceTest.cpp"],
+ defaults: ["binder_test_defaults"],
}
cc_test {
name: "binderValueTypeTest",
srcs: ["binderValueTypeTest.cpp"],
+ defaults: ["binder_test_defaults"],
shared_libs: [
"libbinder",
"libutils",
@@ -35,6 +55,25 @@
}
cc_test {
+ name: "binderLibTest_IPC_32",
+ srcs: ["binderLibTest.cpp"],
+ defaults: ["binder_test_defaults"],
+ shared_libs: [
+ "libbinder",
+ "libutils",
+ ],
+ compile_multilib: "32",
+ cflags: ["-DBINDER_IPC_32BIT=1"],
+}
+
+cc_test {
+ product_variables: {
+ binder32bit: {
+ cflags: ["-DBINDER_IPC_32BIT=1"],
+ },
+ },
+
+ defaults: ["binder_test_defaults"],
name: "binderLibTest",
srcs: ["binderLibTest.cpp"],
shared_libs: [
@@ -46,6 +85,7 @@
cc_test {
name: "binderThroughputTest",
srcs: ["binderThroughputTest.cpp"],
+ defaults: ["binder_test_defaults"],
shared_libs: [
"libbinder",
"libutils",
@@ -53,8 +93,6 @@
clang: true,
cflags: [
"-g",
- "-Wall",
- "-Werror",
"-Wno-missing-field-initializers",
"-Wno-sign-compare",
"-O3",
@@ -64,6 +102,7 @@
cc_test {
name: "binderTextOutputTest",
srcs: ["binderTextOutputTest.cpp"],
+ defaults: ["binder_test_defaults"],
shared_libs: [
"libbinder",
"libutils",
@@ -74,6 +113,7 @@
cc_test {
name: "schd-dbg",
srcs: ["schd-dbg.cpp"],
+ defaults: ["binder_test_defaults"],
shared_libs: [
"libbinder",
"libutils",
@@ -84,9 +124,9 @@
cc_test {
name: "binderSafeInterfaceTest",
srcs: ["binderSafeInterfaceTest.cpp"],
+ defaults: ["binder_test_defaults"],
cppflags: [
- "-Werror",
"-Weverything",
"-Wno-c++98-compat",
"-Wno-c++98-compat-pedantic",
diff --git a/libs/binder/tests/binderDriverInterfaceTest.cpp b/libs/binder/tests/binderDriverInterfaceTest.cpp
index ff5912f..b14631d 100644
--- a/libs/binder/tests/binderDriverInterfaceTest.cpp
+++ b/libs/binder/tests/binderDriverInterfaceTest.cpp
@@ -139,6 +139,12 @@
ASSERT_EQ(BINDER_CURRENT_PROTOCOL_VERSION, version.protocol_version);
}
+TEST_F(BinderDriverInterfaceTest, OpenNoMmap) {
+ int binderFd = open(BINDER_DEV_NAME, O_RDWR | O_NONBLOCK | O_CLOEXEC);
+ ASSERT_GE(binderFd, 0);
+ close(binderFd);
+}
+
TEST_F(BinderDriverInterfaceTest, WriteReadNull) {
binderTestIoctlErr1(BINDER_WRITE_READ, NULL, EFAULT);
}
diff --git a/libs/binder/tests/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp
index 757291c..1611e11 100644
--- a/libs/binder/tests/binderLibTest.cpp
+++ b/libs/binder/tests/binderLibTest.cpp
@@ -28,10 +28,19 @@
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
+#include <sys/epoll.h>
+
#define ARRAY_SIZE(array) (sizeof array / sizeof array[0])
using namespace android;
+static ::testing::AssertionResult IsPageAligned(void *buf) {
+ if (((unsigned long)buf & ((unsigned long)PAGE_SIZE - 1)) == 0)
+ return ::testing::AssertionSuccess();
+ else
+ return ::testing::AssertionFailure() << buf << " is not page aligned";
+}
+
static testing::Environment* binder_env;
static char *binderservername;
static char *binderserversuffix;
@@ -43,7 +52,10 @@
BINDER_LIB_TEST_NOP_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION,
BINDER_LIB_TEST_REGISTER_SERVER,
BINDER_LIB_TEST_ADD_SERVER,
+ BINDER_LIB_TEST_ADD_POLL_SERVER,
BINDER_LIB_TEST_CALL_BACK,
+ BINDER_LIB_TEST_CALL_BACK_VERIFY_BUF,
+ BINDER_LIB_TEST_DELAYED_CALL_BACK,
BINDER_LIB_TEST_NOP_CALL_BACK,
BINDER_LIB_TEST_GET_SELF_TRANSACTION,
BINDER_LIB_TEST_GET_ID_TRANSACTION,
@@ -60,7 +72,7 @@
BINDER_LIB_TEST_CREATE_BINDER_TRANSACTION,
};
-pid_t start_server_process(int arg2)
+pid_t start_server_process(int arg2, bool usePoll = false)
{
int ret;
pid_t pid;
@@ -68,11 +80,13 @@
int pipefd[2];
char stri[16];
char strpipefd1[16];
+ char usepoll[2];
char *childargv[] = {
binderservername,
binderserverarg,
stri,
strpipefd1,
+ usepoll,
binderserversuffix,
NULL
};
@@ -83,6 +97,7 @@
snprintf(stri, sizeof(stri), "%d", arg2);
snprintf(strpipefd1, sizeof(strpipefd1), "%d", pipefd[1]);
+ snprintf(usepoll, sizeof(usepoll), "%d", usePoll ? 1 : 0);
pid = fork();
if (pid == -1)
@@ -167,14 +182,14 @@
virtual void TearDown() {
}
protected:
- sp<IBinder> addServer(int32_t *idPtr = NULL)
+ sp<IBinder> addServerEtc(int32_t *idPtr, int code)
{
int ret;
int32_t id;
Parcel data, reply;
sp<IBinder> binder;
- ret = m_server->transact(BINDER_LIB_TEST_ADD_SERVER, data, &reply);
+ ret = m_server->transact(code, data, &reply);
EXPECT_EQ(NO_ERROR, ret);
EXPECT_FALSE(binder != NULL);
@@ -186,6 +201,17 @@
*idPtr = id;
return binder;
}
+
+ sp<IBinder> addServer(int32_t *idPtr = NULL)
+ {
+ return addServerEtc(idPtr, BINDER_LIB_TEST_ADD_SERVER);
+ }
+
+ sp<IBinder> addPollServer(int32_t *idPtr = NULL)
+ {
+ return addServerEtc(idPtr, BINDER_LIB_TEST_ADD_POLL_SERVER);
+ }
+
void waitForReadData(int fd, int timeout_ms) {
int ret;
pollfd pfd = pollfd();
@@ -265,17 +291,23 @@
pthread_mutex_unlock(&m_waitMutex);
return ret;
}
+ pthread_t getTriggeringThread()
+ {
+ return m_triggeringThread;
+ }
protected:
void triggerEvent(void) {
pthread_mutex_lock(&m_waitMutex);
pthread_cond_signal(&m_waitCond);
m_eventTriggered = true;
+ m_triggeringThread = pthread_self();
pthread_mutex_unlock(&m_waitMutex);
};
private:
pthread_mutex_t m_waitMutex;
pthread_cond_t m_waitCond;
bool m_eventTriggered;
+ pthread_t m_triggeringThread;
};
class BinderLibTestCallBack : public BBinder, public BinderLibTestEvent
@@ -283,6 +315,7 @@
public:
BinderLibTestCallBack()
: m_result(NOT_ENOUGH_DATA)
+ , m_prev_end(NULL)
{
}
status_t getResult(void)
@@ -298,16 +331,43 @@
(void)reply;
(void)flags;
switch(code) {
- case BINDER_LIB_TEST_CALL_BACK:
- m_result = data.readInt32();
+ case BINDER_LIB_TEST_CALL_BACK: {
+ status_t status = data.readInt32(&m_result);
+ if (status != NO_ERROR) {
+ m_result = status;
+ }
triggerEvent();
return NO_ERROR;
+ }
+ case BINDER_LIB_TEST_CALL_BACK_VERIFY_BUF: {
+ sp<IBinder> server;
+ int ret;
+ const uint8_t *buf = data.data();
+ size_t size = data.dataSize();
+ if (m_prev_end) {
+ /* 64-bit kernel needs at most 8 bytes to align buffer end */
+ EXPECT_LE((size_t)(buf - m_prev_end), (size_t)8);
+ } else {
+ EXPECT_TRUE(IsPageAligned((void *)buf));
+ }
+
+ m_prev_end = buf + size + data.objectsCount() * sizeof(binder_size_t);
+
+ if (size > 0) {
+ server = static_cast<BinderLibTestEnv *>(binder_env)->getServer();
+ ret = server->transact(BINDER_LIB_TEST_INDIRECT_TRANSACTION,
+ data, reply);
+ EXPECT_EQ(NO_ERROR, ret);
+ }
+ return NO_ERROR;
+ }
default:
return UNKNOWN_TRANSACTION;
}
}
status_t m_result;
+ const uint8_t *m_prev_end;
};
class TestDeathRecipient : public IBinder::DeathRecipient, public BinderLibTestEvent
@@ -606,6 +666,65 @@
}
}
+TEST_F(BinderLibTest, DeathNotificationThread)
+{
+ status_t ret;
+ sp<BinderLibTestCallBack> callback;
+ sp<IBinder> target = addServer();
+ ASSERT_TRUE(target != NULL);
+ sp<IBinder> client = addServer();
+ ASSERT_TRUE(client != NULL);
+
+ sp<TestDeathRecipient> testDeathRecipient = new TestDeathRecipient();
+
+ ret = target->linkToDeath(testDeathRecipient);
+ EXPECT_EQ(NO_ERROR, ret);
+
+ {
+ Parcel data, reply;
+ ret = target->transact(BINDER_LIB_TEST_EXIT_TRANSACTION, data, &reply, TF_ONE_WAY);
+ EXPECT_EQ(0, ret);
+ }
+
+ /* Make sure it's dead */
+ testDeathRecipient->waitEvent(5);
+
+ /* Now, pass the ref to another process and ask that process to
+ * call linkToDeath() on it, and wait for a response. This tests
+ * two things:
+ * 1) You still get death notifications when calling linkToDeath()
+ * on a ref that is already dead when it was passed to you.
+ * 2) That death notifications are not directly pushed to the thread
+ * registering them, but to the threadpool (proc workqueue) instead.
+ *
+ * 2) is tested because the thread handling BINDER_LIB_TEST_DEATH_TRANSACTION
+ * is blocked on a condition variable waiting for the death notification to be
+ * called; therefore, that thread is not available for handling proc work.
+ * So, if the death notification was pushed to the thread workqueue, the callback
+ * would never be called, and the test would timeout and fail.
+ *
+ * Note that we can't do this part of the test from this thread itself, because
+ * the binder driver would only push death notifications to the thread if
+ * it is a looper thread, which this thread is not.
+ *
+ * See b/23525545 for details.
+ */
+ {
+ Parcel data, reply;
+
+ callback = new BinderLibTestCallBack();
+ data.writeStrongBinder(target);
+ data.writeStrongBinder(callback);
+ ret = client->transact(BINDER_LIB_TEST_LINK_DEATH_TRANSACTION, data, &reply, TF_ONE_WAY);
+ EXPECT_EQ(NO_ERROR, ret);
+ }
+
+ ret = callback->waitEvent(5);
+ EXPECT_EQ(NO_ERROR, ret);
+ ret = callback->getResult();
+ EXPECT_EQ(NO_ERROR, ret);
+}
+
TEST_F(BinderLibTest, PassFile) {
int ret;
int pipefd[2];
@@ -681,10 +800,10 @@
const flat_binder_object *fb = reply.readObject(false);
ASSERT_TRUE(fb != NULL);
- EXPECT_EQ(fb->type, BINDER_TYPE_HANDLE);
- EXPECT_EQ(ProcessState::self()->getStrongProxyForHandle(fb->handle), m_server);
- EXPECT_EQ(fb->cookie, (binder_uintptr_t)0);
- EXPECT_EQ(fb->binder >> 32, (binder_uintptr_t)0);
+ EXPECT_EQ(BINDER_TYPE_HANDLE, fb->hdr.type);
+ EXPECT_EQ(m_server, ProcessState::self()->getStrongProxyForHandle(fb->handle));
+ EXPECT_EQ((binder_uintptr_t)0, fb->cookie);
+ EXPECT_EQ((uint64_t)0, (uint64_t)fb->binder >> 32);
}
TEST_F(BinderLibTest, FreedBinder) {
@@ -728,6 +847,61 @@
}
}
+TEST_F(BinderLibTest, CheckNoHeaderMappedInUser) {
+ status_t ret;
+ Parcel data, reply;
+ sp<BinderLibTestCallBack> callBack = new BinderLibTestCallBack();
+ for (int i = 0; i < 2; i++) {
+ BinderLibTestBundle datai;
+ datai.appendFrom(&data, 0, data.dataSize());
+
+ data.freeData();
+ data.writeInt32(1);
+ data.writeStrongBinder(callBack);
+ data.writeInt32(BINDER_LIB_TEST_CALL_BACK_VERIFY_BUF);
+
+ datai.appendTo(&data);
+ }
+ ret = m_server->transact(BINDER_LIB_TEST_INDIRECT_TRANSACTION, data, &reply);
+ EXPECT_EQ(NO_ERROR, ret);
+}
+
+TEST_F(BinderLibTest, OnewayQueueing)
+{
+ status_t ret;
+ Parcel data, data2;
+
+ sp<IBinder> pollServer = addPollServer();
+
+ sp<BinderLibTestCallBack> callBack = new BinderLibTestCallBack();
+ data.writeStrongBinder(callBack);
+ data.writeInt32(500000); // delay in us before calling back
+
+ sp<BinderLibTestCallBack> callBack2 = new BinderLibTestCallBack();
+ data2.writeStrongBinder(callBack2);
+ data2.writeInt32(0); // delay in us
+
+ ret = pollServer->transact(BINDER_LIB_TEST_DELAYED_CALL_BACK, data, NULL, TF_ONE_WAY);
+ EXPECT_EQ(NO_ERROR, ret);
+
+ // The delay ensures that this second transaction will end up on the async_todo list
+ // (for a single-threaded server)
+ ret = pollServer->transact(BINDER_LIB_TEST_DELAYED_CALL_BACK, data2, NULL, TF_ONE_WAY);
+ EXPECT_EQ(NO_ERROR, ret);
+
+ // The server will ensure that the two transactions are handled in the expected order;
+ // If the ordering is not as expected, an error will be returned through the callbacks.
+ ret = callBack->waitEvent(2);
+ EXPECT_EQ(NO_ERROR, ret);
+ ret = callBack->getResult();
+ EXPECT_EQ(NO_ERROR, ret);
+
+ ret = callBack2->waitEvent(2);
+ EXPECT_EQ(NO_ERROR, ret);
+ ret = callBack2->getResult();
+ EXPECT_EQ(NO_ERROR, ret);
+}
+
class BinderLibTestService : public BBinder
{
public:
@@ -735,6 +909,7 @@
: m_id(id)
, m_nextServerId(id + 1)
, m_serverStartRequested(false)
+ , m_callback(NULL)
{
pthread_mutex_init(&m_serverWaitMutex, NULL);
pthread_cond_init(&m_serverWaitCond, NULL);
@@ -743,6 +918,16 @@
{
exit(EXIT_SUCCESS);
}
+
+ void processPendingCall() {
+ if (m_callback != NULL) {
+ Parcel data;
+ data.writeInt32(NO_ERROR);
+ m_callback->transact(BINDER_LIB_TEST_CALL_BACK, data, nullptr, TF_ONE_WAY);
+ m_callback = NULL;
+ }
+ }
+
virtual status_t onTransact(uint32_t code,
const Parcel& data, Parcel* reply,
uint32_t flags = 0) {
@@ -774,6 +959,7 @@
pthread_mutex_unlock(&m_serverWaitMutex);
return NO_ERROR;
}
+ case BINDER_LIB_TEST_ADD_POLL_SERVER:
case BINDER_LIB_TEST_ADD_SERVER: {
int ret;
uint8_t buf[1] = { 0 };
@@ -788,9 +974,10 @@
} else {
serverid = m_nextServerId++;
m_serverStartRequested = true;
+ bool usePoll = code == BINDER_LIB_TEST_ADD_POLL_SERVER;
pthread_mutex_unlock(&m_serverWaitMutex);
- ret = start_server_process(serverid);
+ ret = start_server_process(serverid, usePoll);
pthread_mutex_lock(&m_serverWaitMutex);
}
if (ret > 0) {
@@ -818,6 +1005,42 @@
}
case BINDER_LIB_TEST_NOP_TRANSACTION:
return NO_ERROR;
+ case BINDER_LIB_TEST_DELAYED_CALL_BACK: {
+ // Note: this transaction is only designed for use with a
+ // poll() server. See comments around epoll_wait().
+ if (m_callback != NULL) {
+ // A callback was already pending; this means that
+ // we received a second call while still processing
+ // the first one. Fail the test.
+ sp<IBinder> callback = data.readStrongBinder();
+ Parcel data2;
+ data2.writeInt32(UNKNOWN_ERROR);
+
+ callback->transact(BINDER_LIB_TEST_CALL_BACK, data2, NULL, TF_ONE_WAY);
+ } else {
+ m_callback = data.readStrongBinder();
+ int32_t delayUs = data.readInt32();
+ /*
+ * It's necessary that we sleep here, so the next
+ * transaction the caller makes will be queued to
+ * the async queue.
+ */
+ usleep(delayUs);
+
+ /*
+ * Now when we return, libbinder will tell the kernel
+ * we are done with this transaction, and the kernel
+ * can move the queued transaction to either the
+ * thread todo worklist (for kernels without the fix),
+ * or the proc todo worklist. In case of the former,
+ * the next outbound call will pick up the pending
+ * transaction, which leads to undesired reentrant
+ * behavior. This is caught in the if() branch above.
+ */
+ }
+
+ return NO_ERROR;
+ }
case BINDER_LIB_TEST_NOP_CALL_BACK: {
Parcel data2, reply2;
sp<IBinder> binder;
@@ -825,7 +1048,7 @@
if (binder == NULL) {
return BAD_VALUE;
}
- reply2.writeInt32(NO_ERROR);
+ data2.writeInt32(NO_ERROR);
binder->transact(BINDER_LIB_TEST_CALL_BACK, data2, &reply2);
return NO_ERROR;
}
@@ -967,16 +1190,26 @@
bool m_serverStartRequested;
sp<IBinder> m_serverStarted;
sp<IBinder> m_strongRef;
+ bool m_callbackPending;
+ sp<IBinder> m_callback;
};
-int run_server(int index, int readypipefd)
+int run_server(int index, int readypipefd, bool usePoll)
{
binderLibTestServiceName += String16(binderserversuffix);
status_t ret;
sp<IServiceManager> sm = defaultServiceManager();
+ BinderLibTestService* testServicePtr;
{
sp<BinderLibTestService> testService = new BinderLibTestService(index);
+ /*
+ * We need this below, but can't hold a sp<> because it prevents the
+ * node from being cleaned up automatically. It's safe in this case
+ * because of how the tests are written.
+ */
+ testServicePtr = testService.get();
+
if (index == 0) {
ret = sm->addService(binderLibTestServiceName, testService);
} else {
@@ -994,8 +1227,53 @@
if (ret)
return 1;
//printf("%s: joinThreadPool\n", __func__);
- ProcessState::self()->startThreadPool();
- IPCThreadState::self()->joinThreadPool();
+ if (usePoll) {
+ int fd;
+ struct epoll_event ev;
+ int epoll_fd;
+ IPCThreadState::self()->setupPolling(&fd);
+ if (fd < 0) {
+ return 1;
+ }
+ IPCThreadState::self()->flushCommands(); // flush BC_ENTER_LOOPER
+
+ epoll_fd = epoll_create1(0);
+ if (epoll_fd == -1) {
+ return 1;
+ }
+
+ ev.events = EPOLLIN;
+ if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev) == -1) {
+ return 1;
+ }
+
+ while (1) {
+ /*
+ * We simulate a single-threaded process using the binder poll
+ * interface; besides handling binder commands, it can also
+ * issue outgoing transactions, by storing a callback in
+ * m_callback and setting m_callbackPending.
+ *
+ * processPendingCall() will then issue that transaction.
+ */
+ struct epoll_event events[1];
+ int numEvents = epoll_wait(epoll_fd, events, 1, 1000);
+ if (numEvents < 0) {
+ if (errno == EINTR) {
+ continue;
+ }
+ return 1;
+ }
+ if (numEvents > 0) {
+ IPCThreadState::self()->handlePolledCommands();
+ IPCThreadState::self()->flushCommands(); // flush BC_FREE_BUFFER
+ testServicePtr->processPendingCall();
+ }
+ }
+ } else {
+ ProcessState::self()->startThreadPool();
+ IPCThreadState::self()->joinThreadPool();
+ }
//printf("%s: joinThreadPool returned\n", __func__);
return 1; /* joinThreadPool should not return */
}
@@ -1009,9 +1287,9 @@
binderservername = argv[0];
}
- if (argc == 5 && !strcmp(argv[1], binderserverarg)) {
- binderserversuffix = argv[4];
- return run_server(atoi(argv[2]), atoi(argv[3]));
+ if (argc == 6 && !strcmp(argv[1], binderserverarg)) {
+ binderserversuffix = argv[5];
+ return run_server(atoi(argv[2]), atoi(argv[3]), atoi(argv[4]) == 1);
}
binderserversuffix = new char[16];
snprintf(binderserversuffix, 16, "%d", getpid());
diff --git a/libs/binder/tests/binderThroughputTest.cpp b/libs/binder/tests/binderThroughputTest.cpp
index 6e8f7df..bf41e0b 100644
--- a/libs/binder/tests/binderThroughputTest.cpp
+++ b/libs/binder/tests/binderThroughputTest.cpp
@@ -101,18 +101,21 @@
};
static const uint32_t num_buckets = 128;
-static const uint64_t max_time_bucket = 50ull * 1000000;
-static const uint64_t time_per_bucket = max_time_bucket / num_buckets;
-static constexpr float time_per_bucket_ms = time_per_bucket / 1.0E6;
+static uint64_t max_time_bucket = 50ull * 1000000;
+static uint64_t time_per_bucket = max_time_bucket / num_buckets;
struct ProcResults {
- uint64_t m_best = max_time_bucket;
uint64_t m_worst = 0;
uint32_t m_buckets[num_buckets] = {0};
uint64_t m_transactions = 0;
+ uint64_t m_long_transactions = 0;
uint64_t m_total_time = 0;
+ uint64_t m_best = max_time_bucket;
void add_time(uint64_t time) {
+ if (time > max_time_bucket) {
+ m_long_transactions++;
+ }
m_buckets[min(time, max_time_bucket-1) / time_per_bucket] += 1;
m_best = min(time, m_best);
m_worst = max(time, m_worst);
@@ -127,16 +130,24 @@
ret.m_worst = max(a.m_worst, b.m_worst);
ret.m_best = min(a.m_best, b.m_best);
ret.m_transactions = a.m_transactions + b.m_transactions;
+ ret.m_long_transactions = a.m_long_transactions + b.m_long_transactions;
ret.m_total_time = a.m_total_time + b.m_total_time;
return ret;
}
void dump() {
+ if (m_long_transactions > 0) {
+ cout << (double)m_long_transactions / m_transactions << "% of transactions took longer "
+ "than estimated max latency. Consider setting -m to be higher than "
+ << m_worst / 1000 << " microseconds" << endl;
+ }
+
double best = (double)m_best / 1.0E6;
double worst = (double)m_worst / 1.0E6;
double average = (double)m_total_time / m_transactions / 1.0E6;
cout << "average:" << average << "ms worst:" << worst << "ms best:" << best << "ms" << endl;
uint64_t cur_total = 0;
+ float time_per_bucket_ms = time_per_bucket / 1.0E6;
for (int i = 0; i < num_buckets; i++) {
float cur_time = time_per_bucket_ms * i + 0.5f * time_per_bucket_ms;
if ((cur_total < 0.5f * m_transactions) && (cur_total + m_buckets[i] >= 0.5f * m_transactions)) {
@@ -154,7 +165,6 @@
cur_total += m_buckets[i];
}
cout << endl;
-
}
};
@@ -166,13 +176,12 @@
return serviceName;
}
-void worker_fx(
- int num,
- int worker_count,
- int iterations,
- int payload_size,
- bool cs_pair,
- Pipe p)
+void worker_fx(int num,
+ int worker_count,
+ int iterations,
+ int payload_size,
+ bool cs_pair,
+ Pipe p)
{
// Create BinderWorkerService and for go.
ProcessState::self()->startThreadPool();
@@ -204,12 +213,12 @@
for (int i = 0; (!cs_pair || num >= server_count) && i < iterations; i++) {
Parcel data, reply;
int target = cs_pair ? num % server_count : rand() % workers.size();
- int sz = payload_size;
+ int sz = payload_size;
- while (sz > sizeof(uint32_t)) {
- data.writeInt32(0);
- sz -= sizeof(uint32_t);
- }
+ while (sz >= sizeof(uint32_t)) {
+ data.writeInt32(0);
+ sz -= sizeof(uint32_t);
+ }
start = chrono::high_resolution_clock::now();
status_t ret = workers[target]->transact(BINDER_NOP, data, &reply);
end = chrono::high_resolution_clock::now();
@@ -264,47 +273,19 @@
}
}
-int main(int argc, char *argv[])
+void run_main(int iterations,
+ int workers,
+ int payload_size,
+ int cs_pair,
+ bool training_round=false)
{
- int workers = 2;
- int iterations = 10000;
- int payload_size = 0;
- bool cs_pair = false;
- (void)argc;
- (void)argv;
vector<Pipe> pipes;
-
- // Parse arguments.
- for (int i = 1; i < argc; i++) {
- if (string(argv[i]) == "-w") {
- workers = atoi(argv[i+1]);
- i++;
- continue;
- }
- if (string(argv[i]) == "-i") {
- iterations = atoi(argv[i+1]);
- i++;
- continue;
- }
- if (string(argv[i]) == "-s") {
- payload_size = atoi(argv[i+1]);
- i++;
- }
- if (string(argv[i]) == "-p") {
- // client/server pairs instead of spreading
- // requests to all workers. If true, half
- // the workers become clients and half servers
- cs_pair = true;
- }
- }
-
// Create all the workers and wait for them to spawn.
for (int i = 0; i < workers; i++) {
pipes.push_back(make_worker(i, iterations, workers, payload_size, cs_pair));
}
wait_all(pipes);
-
// Run the workers and wait for completion.
chrono::time_point<chrono::high_resolution_clock> start, end;
cout << "waiting for workers to complete" << endl;
@@ -326,7 +307,6 @@
pipes[i].recv(tmp_results);
tot_results = ProcResults::combine(tot_results, tmp_results);
}
- tot_results.dump();
// Kill all the workers.
cout << "killing workers" << endl;
@@ -338,5 +318,84 @@
cout << "nonzero child status" << status << endl;
}
}
+ if (training_round) {
+ // sets max_time_bucket to 2 * m_worst from the training round.
+ // Also needs to adjust time_per_bucket accordingly.
+ max_time_bucket = 2 * tot_results.m_worst;
+ time_per_bucket = max_time_bucket / num_buckets;
+ cout << "Max latency during training: " << tot_results.m_worst / 1.0E6 << "ms" << endl;
+ } else {
+ tot_results.dump();
+ }
+}
+
+int main(int argc, char *argv[])
+{
+ int workers = 2;
+ int iterations = 10000;
+ int payload_size = 0;
+ bool cs_pair = false;
+ bool training_round = false;
+ (void)argc;
+ (void)argv;
+
+ // Parse arguments.
+ for (int i = 1; i < argc; i++) {
+ if (string(argv[i]) == "--help") {
+ cout << "Usage: binderThroughputTest [OPTIONS]" << endl;
+ cout << "\t-i N : Specify number of iterations." << endl;
+ cout << "\t-m N : Specify expected max latency in microseconds." << endl;
+ cout << "\t-p : Split workers into client/server pairs." << endl;
+ cout << "\t-s N : Specify payload size." << endl;
+ cout << "\t-t N : Run training round." << endl;
+ cout << "\t-w N : Specify total number of workers." << endl;
+ return 0;
+ }
+ if (string(argv[i]) == "-w") {
+ workers = atoi(argv[i+1]);
+ i++;
+ continue;
+ }
+ if (string(argv[i]) == "-i") {
+ iterations = atoi(argv[i+1]);
+ i++;
+ continue;
+ }
+ if (string(argv[i]) == "-s") {
+ payload_size = atoi(argv[i+1]);
+ i++;
+ }
+ if (string(argv[i]) == "-p") {
+ // client/server pairs instead of spreading
+ // requests to all workers. If true, half
+ // the workers become clients and half servers
+ cs_pair = true;
+ }
+ if (string(argv[i]) == "-t") {
+ // Run one training round before actually collecting data
+ // to get an approximation of max latency.
+ training_round = true;
+ }
+ if (string(argv[i]) == "-m") {
+ // Caller specified the max latency in microseconds.
+ // No need to run training round in this case.
+ if (atoi(argv[i+1]) > 0) {
+ max_time_bucket = strtoull(argv[i+1], (char **)NULL, 10) * 1000;
+ time_per_bucket = max_time_bucket / num_buckets;
+ i++;
+ } else {
+ cout << "Max latency -m must be positive." << endl;
+ exit(EXIT_FAILURE);
+ }
+ }
+ }
+
+ if (training_round) {
+ cout << "Start training round" << endl;
+ run_main(iterations, workers, payload_size, cs_pair, training_round=true);
+ cout << "Completed training round" << endl << endl;
+ }
+
+ run_main(iterations, workers, payload_size, cs_pair);
return 0;
}
diff --git a/libs/diskusage/Android.bp b/libs/diskusage/Android.bp
index 156ddff..a826306 100644
--- a/libs/diskusage/Android.bp
+++ b/libs/diskusage/Android.bp
@@ -15,4 +15,5 @@
cc_library_static {
name: "libdiskusage",
srcs: ["dirsize.c"],
+ cflags: ["-Wall", "-Werror"],
}
diff --git a/libs/graphicsenv/Android.bp b/libs/graphicsenv/Android.bp
index f2686d5..9f99538 100644
--- a/libs/graphicsenv/Android.bp
+++ b/libs/graphicsenv/Android.bp
@@ -19,6 +19,8 @@
"GraphicsEnv.cpp",
],
+ cflags: ["-Wall", "-Werror"],
+
shared_libs: [
"libnativeloader",
"liblog",
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index c0ae3d7..cf72d55 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -11,14 +11,26 @@
// 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.
+cc_library_headers {
+ name: "libgui_headers",
+ vendor_available: true,
+ export_include_dirs: ["include"],
+}
cc_library_shared {
name: "libgui",
+ vendor_available: true,
+ vndk: {
+ enabled: true,
+ },
clang: true,
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
cppflags: [
"-Weverything",
- "-Werror",
// The static constructors and destructors in this library have not been noted to
// introduce significant overheads
@@ -57,7 +69,7 @@
brillo: {
cflags: ["-DHAVE_NO_SURFACE_FLINGER"],
},
- debuggable: {
+ eng: {
cppflags: [
"-UDEBUG_ONLY_CODE",
"-DDEBUG_ONLY_CODE=1",
@@ -87,6 +99,7 @@
"IProducerListener.cpp",
"ISurfaceComposer.cpp",
"ISurfaceComposerClient.cpp",
+ "LayerDebugInfo.cpp",
"LayerState.cpp",
"OccupancyTracker.cpp",
"StreamSplitter.cpp",
@@ -119,16 +132,22 @@
header_libs: [
"libnativebase_headers",
+ "libgui_headers",
],
export_shared_lib_headers: [
"libbinder",
- "libui",
+ "libEGL",
"libnativewindow",
+ "libui",
"android.hidl.token@1.0-utils",
"android.hardware.graphics.bufferqueue@1.0",
],
+ export_header_lib_headers: [
+ "libgui_headers",
+ ],
+
export_include_dirs: [
"include",
],
diff --git a/libs/gui/BufferItemConsumer.cpp b/libs/gui/BufferItemConsumer.cpp
index d9d50db..da42956 100644
--- a/libs/gui/BufferItemConsumer.cpp
+++ b/libs/gui/BufferItemConsumer.cpp
@@ -19,6 +19,8 @@
//#define ATRACE_TAG ATRACE_TAG_GRAPHICS
#include <utils/Log.h>
+#include <inttypes.h>
+
#include <gui/BufferItem.h>
#include <gui/BufferItemConsumer.h>
@@ -31,13 +33,13 @@
namespace android {
BufferItemConsumer::BufferItemConsumer(
- const sp<IGraphicBufferConsumer>& consumer, uint32_t consumerUsage,
+ const sp<IGraphicBufferConsumer>& consumer, uint64_t consumerUsage,
int bufferCount, bool controlledByApp) :
ConsumerBase(consumer, controlledByApp)
{
status_t err = mConsumer->setConsumerUsageBits(consumerUsage);
LOG_ALWAYS_FATAL_IF(err != OK,
- "Failed to set consumer usage bits to %#x", consumerUsage);
+ "Failed to set consumer usage bits to %#" PRIx64, consumerUsage);
if (bufferCount != DEFAULT_MAX_BUFFERS) {
err = mConsumer->setMaxAcquiredBufferCount(bufferCount);
LOG_ALWAYS_FATAL_IF(err != OK,
diff --git a/libs/gui/BufferQueueConsumer.cpp b/libs/gui/BufferQueueConsumer.cpp
index be754c2..17cf677 100644
--- a/libs/gui/BufferQueueConsumer.cpp
+++ b/libs/gui/BufferQueueConsumer.cpp
@@ -15,6 +15,8 @@
*/
#include <inttypes.h>
+#include <pwd.h>
+#include <sys/types.h>
#define LOG_TAG "BufferQueueConsumer"
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
@@ -34,7 +36,6 @@
#include <binder/IPCThreadState.h>
#include <binder/PermissionCache.h>
-#include <private/android_filesystem_config.h>
#include <system/window.h>
@@ -703,9 +704,9 @@
return NO_ERROR;
}
-status_t BufferQueueConsumer::setConsumerUsageBits(uint32_t usage) {
+status_t BufferQueueConsumer::setConsumerUsageBits(uint64_t usage) {
ATRACE_CALL();
- BQ_LOGV("setConsumerUsageBits: %#x", usage);
+ BQ_LOGV("setConsumerUsageBits: %#" PRIx64, usage);
Mutex::Autolock lock(mCore->mMutex);
mCore->mConsumerUsageBits = usage;
return NO_ERROR;
@@ -747,12 +748,19 @@
}
status_t BufferQueueConsumer::dumpState(const String8& prefix, String8* outResult) const {
+ struct passwd* pwd = getpwnam("shell");
+ uid_t shellUid = pwd ? pwd->pw_uid : 0;
+ if (!shellUid) {
+ int savedErrno = errno;
+ BQ_LOGE("Cannot get AID_SHELL");
+ return savedErrno ? -savedErrno : UNKNOWN_ERROR;
+ }
+
const IPCThreadState* ipc = IPCThreadState::self();
const pid_t pid = ipc->getCallingPid();
const uid_t uid = ipc->getCallingUid();
- if ((uid != AID_SHELL)
- && !PermissionCache::checkPermission(String16(
- "android.permission.DUMP"), pid, uid)) {
+ if ((uid != shellUid) &&
+ !PermissionCache::checkPermission(String16("android.permission.DUMP"), pid, uid)) {
outResult->appendFormat("Permission Denial: can't dump BufferQueueConsumer "
"from pid=%d, uid=%d\n", pid, uid);
android_errorWriteWithInfoLog(0x534e4554, "27046057",
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index 7510069..c5cab2d 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -347,10 +347,10 @@
return NO_ERROR;
}
-status_t BufferQueueProducer::dequeueBuffer(int *outSlot,
- sp<android::Fence> *outFence, uint32_t width, uint32_t height,
- PixelFormat format, uint32_t usage,
- FrameEventHistoryDelta* outTimestamps) {
+status_t BufferQueueProducer::dequeueBuffer(int* outSlot, sp<android::Fence>* outFence,
+ uint32_t width, uint32_t height, PixelFormat format,
+ uint64_t usage, uint64_t* outBufferAge,
+ FrameEventHistoryDelta* outTimestamps) {
ATRACE_CALL();
{ // Autolock scope
Mutex::Autolock lock(mCore->mMutex);
@@ -367,8 +367,7 @@
}
} // Autolock scope
- BQ_LOGV("dequeueBuffer: w=%u h=%u format=%#x, usage=%#x", width, height,
- format, usage);
+ BQ_LOGV("dequeueBuffer: w=%u h=%u format=%#x, usage=%#" PRIx64, width, height, format, usage);
if ((width && !height) || (!width && height)) {
BQ_LOGE("dequeueBuffer: invalid size: w=%u h=%u", width, height);
@@ -418,11 +417,9 @@
// buffer. If this buffer would require reallocation to meet the
// requested attributes, we free it and attempt to get another one.
if (!mCore->mAllowAllocation) {
- if (buffer->needsReallocation(width, height, format,
- BQ_LAYER_COUNT, usage)) {
+ if (buffer->needsReallocation(width, height, format, BQ_LAYER_COUNT, usage)) {
if (mCore->mSharedBufferSlot == found) {
- BQ_LOGE("dequeueBuffer: cannot re-allocate a shared"
- "buffer");
+ BQ_LOGE("dequeueBuffer: cannot re-allocate a sharedbuffer");
return BAD_VALUE;
}
mCore->mFreeSlots.insert(found);
@@ -435,8 +432,7 @@
const sp<GraphicBuffer>& buffer(mSlots[found].mGraphicBuffer);
if (mCore->mSharedBufferSlot == found &&
- buffer->needsReallocation(width, height, format,
- BQ_LAYER_COUNT, usage)) {
+ buffer->needsReallocation(width, height, format, BQ_LAYER_COUNT, usage)) {
BQ_LOGE("dequeueBuffer: cannot re-allocate a shared"
"buffer");
@@ -470,8 +466,7 @@
} else {
// We add 1 because that will be the frame number when this buffer
// is queued
- mCore->mBufferAge =
- mCore->mFrameCounter + 1 - mSlots[found].mFrameNumber;
+ mCore->mBufferAge = mCore->mFrameCounter + 1 - mSlots[found].mFrameNumber;
}
BQ_LOGV("dequeueBuffer: setting buffer age to %" PRIu64,
@@ -563,6 +558,9 @@
mSlots[*outSlot].mFrameNumber,
mSlots[*outSlot].mGraphicBuffer->handle, returnFlags);
+ if (outBufferAge) {
+ *outBufferAge = mCore->mBufferAge;
+ }
addAndGetFrameTimestamps(nullptr, outTimestamps);
return returnFlags;
@@ -634,41 +632,49 @@
return BAD_VALUE;
}
- Mutex::Autolock lock(mCore->mMutex);
+ sp<IConsumerListener> listener;
+ {
+ Mutex::Autolock lock(mCore->mMutex);
- if (mCore->mIsAbandoned) {
- BQ_LOGE("detachNextBuffer: BufferQueue has been abandoned");
- return NO_INIT;
+ if (mCore->mIsAbandoned) {
+ BQ_LOGE("detachNextBuffer: BufferQueue has been abandoned");
+ return NO_INIT;
+ }
+
+ if (mCore->mConnectedApi == BufferQueueCore::NO_CONNECTED_API) {
+ BQ_LOGE("detachNextBuffer: BufferQueue has no connected producer");
+ return NO_INIT;
+ }
+
+ if (mCore->mSharedBufferMode) {
+ BQ_LOGE("detachNextBuffer: cannot detach a buffer in shared buffer "
+ "mode");
+ return BAD_VALUE;
+ }
+
+ mCore->waitWhileAllocatingLocked();
+
+ if (mCore->mFreeBuffers.empty()) {
+ return NO_MEMORY;
+ }
+
+ int found = mCore->mFreeBuffers.front();
+ mCore->mFreeBuffers.remove(found);
+ mCore->mFreeSlots.insert(found);
+
+ BQ_LOGV("detachNextBuffer detached slot %d", found);
+
+ *outBuffer = mSlots[found].mGraphicBuffer;
+ *outFence = mSlots[found].mFence;
+ mCore->clearBufferSlotLocked(found);
+ VALIDATE_CONSISTENCY();
+ listener = mCore->mConsumerListener;
}
- if (mCore->mConnectedApi == BufferQueueCore::NO_CONNECTED_API) {
- BQ_LOGE("detachNextBuffer: BufferQueue has no connected producer");
- return NO_INIT;
+ if (listener != NULL) {
+ listener->onBuffersReleased();
}
- if (mCore->mSharedBufferMode) {
- BQ_LOGE("detachNextBuffer: cannot detach a buffer in shared buffer "
- "mode");
- return BAD_VALUE;
- }
-
- mCore->waitWhileAllocatingLocked();
-
- if (mCore->mFreeBuffers.empty()) {
- return NO_MEMORY;
- }
-
- int found = mCore->mFreeBuffers.front();
- mCore->mFreeBuffers.remove(found);
- mCore->mFreeSlots.insert(found);
-
- BQ_LOGV("detachNextBuffer detached slot %d", found);
-
- *outBuffer = mSlots[found].mGraphicBuffer;
- *outFence = mSlots[found].mFence;
- mCore->clearBufferSlotLocked(found);
- VALIDATE_CONSISTENCY();
-
return NO_ERROR;
}
@@ -758,7 +764,7 @@
input.deflate(&requestedPresentTimestamp, &isAutoTimestamp, &dataSpace,
&crop, &scalingMode, &transform, &acquireFence, &stickyTransform,
&getFrameTimestamps);
- Region surfaceDamage = input.getSurfaceDamage();
+ const Region& surfaceDamage = input.getSurfaceDamage();
if (acquireFence == NULL) {
BQ_LOGE("queueBuffer: fence is NULL");
@@ -1096,6 +1102,7 @@
value = (mCore->mQueue.size() > 1);
break;
case NATIVE_WINDOW_CONSUMER_USAGE_BITS:
+ // deprecated; higher 32 bits are truncated
value = static_cast<int32_t>(mCore->mConsumerUsageBits);
break;
case NATIVE_WINDOW_DEFAULT_DATASPACE:
@@ -1313,14 +1320,14 @@
}
void BufferQueueProducer::allocateBuffers(uint32_t width, uint32_t height,
- PixelFormat format, uint32_t usage) {
+ PixelFormat format, uint64_t usage) {
ATRACE_CALL();
while (true) {
size_t newBufferCount = 0;
uint32_t allocWidth = 0;
uint32_t allocHeight = 0;
PixelFormat allocFormat = PIXEL_FORMAT_UNKNOWN;
- uint32_t allocUsage = 0;
+ uint64_t allocUsage = 0;
{ // Autolock scope
Mutex::Autolock lock(mCore->mMutex);
mCore->waitWhileAllocatingLocked();
@@ -1354,7 +1361,7 @@
if (result != NO_ERROR) {
BQ_LOGE("allocateBuffers: failed to allocate buffer (%u x %u, format"
- " %u, usage %u)", width, height, format, usage);
+ " %u, usage %#" PRIx64 ")", width, height, format, usage);
Mutex::Autolock lock(mCore->mMutex);
mCore->mIsAllocating = false;
mCore->mIsAllocatingCondition.broadcast();
@@ -1369,7 +1376,7 @@
uint32_t checkHeight = height > 0 ? height : mCore->mDefaultHeight;
PixelFormat checkFormat = format != 0 ?
format : mCore->mDefaultBufferFormat;
- uint32_t checkUsage = usage | mCore->mConsumerUsageBits;
+ uint64_t checkUsage = usage | mCore->mConsumerUsageBits;
if (checkWidth != allocWidth || checkHeight != allocHeight ||
checkFormat != allocFormat || checkUsage != allocUsage) {
// Something changed while we released the lock. Retry.
@@ -1541,4 +1548,12 @@
return NO_ERROR;
}
+status_t BufferQueueProducer::getConsumerUsage(uint64_t* outUsage) const {
+ BQ_LOGV("getConsumerUsage");
+
+ Mutex::Autolock lock(mCore->mMutex);
+ *outUsage = mCore->mConsumerUsageBits;
+ return NO_ERROR;
+}
+
} // namespace android
diff --git a/libs/gui/ConsumerBase.cpp b/libs/gui/ConsumerBase.cpp
index 5c6158c..7aa7872 100644
--- a/libs/gui/ConsumerBase.cpp
+++ b/libs/gui/ConsumerBase.cpp
@@ -106,7 +106,7 @@
sp<FrameAvailableListener> listener;
{ // scope for the lock
- Mutex::Autolock lock(mMutex);
+ Mutex::Autolock lock(mFrameAvailableMutex);
listener = mFrameAvailableListener.promote();
}
@@ -121,7 +121,7 @@
sp<FrameAvailableListener> listener;
{
- Mutex::Autolock lock(mMutex);
+ Mutex::Autolock lock(mFrameAvailableMutex);
listener = mFrameAvailableListener.promote();
}
@@ -185,7 +185,7 @@
void ConsumerBase::setFrameAvailableListener(
const wp<FrameAvailableListener>& listener) {
CB_LOGV("setFrameAvailableListener");
- Mutex::Autolock lock(mMutex);
+ Mutex::Autolock lock(mFrameAvailableMutex);
mFrameAvailableListener = listener;
}
@@ -253,7 +253,18 @@
CB_LOGE("discardFreeBuffers: ConsumerBase is abandoned!");
return NO_INIT;
}
- return mConsumer->discardFreeBuffers();
+ status_t err = mConsumer->discardFreeBuffers();
+ if (err != OK) {
+ return err;
+ }
+ uint64_t mask;
+ mConsumer->getReleasedBuffers(&mask);
+ for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
+ if (mask & (1ULL << i)) {
+ freeBufferLocked(i);
+ }
+ }
+ return OK;
}
void ConsumerBase::dumpState(String8& result) const {
@@ -324,16 +335,25 @@
return OK;
}
- auto status = mSlots[slot].mFence->getStatus();
-
- if (status == Fence::Status::Invalid) {
- CB_LOGE("fence has invalid state");
+ // Check status of fences first because merging is expensive.
+ // Merging an invalid fence with any other fence results in an
+ // invalid fence.
+ auto currentStatus = mSlots[slot].mFence->getStatus();
+ if (currentStatus == Fence::Status::Invalid) {
+ CB_LOGE("Existing fence has invalid state");
return BAD_VALUE;
}
- if (status == Fence::Status::Signaled) {
+ auto incomingStatus = fence->getStatus();
+ if (incomingStatus == Fence::Status::Invalid) {
+ CB_LOGE("New fence has invalid state");
mSlots[slot].mFence = fence;
- } else { // status == Fence::Status::Unsignaled
+ return BAD_VALUE;
+ }
+
+ // If both fences are signaled or both are unsignaled, we need to merge
+ // them to get an accurate timestamp.
+ if (currentStatus == incomingStatus) {
char fenceName[32] = {};
snprintf(fenceName, 32, "%.28s:%d", mName.string(), slot);
sp<Fence> mergedFence = Fence::merge(
@@ -346,7 +366,17 @@
return BAD_VALUE;
}
mSlots[slot].mFence = mergedFence;
+ } else if (incomingStatus == Fence::Status::Unsignaled) {
+ // If one fence has signaled and the other hasn't, the unsignaled
+ // fence will approximately correspond with the correct timestamp.
+ // There's a small race if both fences signal at about the same time
+ // and their statuses are retrieved with unfortunate timing. However,
+ // by this point, they will have both signaled and only the timestamp
+ // will be slightly off; any dependencies after this point will
+ // already have been met.
+ mSlots[slot].mFence = fence;
}
+ // else if (currentStatus == Fence::Status::Unsignaled) is a no-op.
return OK;
}
diff --git a/libs/gui/DisplayEventReceiver.cpp b/libs/gui/DisplayEventReceiver.cpp
index 1507d51..1757ec1 100644
--- a/libs/gui/DisplayEventReceiver.cpp
+++ b/libs/gui/DisplayEventReceiver.cpp
@@ -32,10 +32,10 @@
// ---------------------------------------------------------------------------
-DisplayEventReceiver::DisplayEventReceiver() {
+DisplayEventReceiver::DisplayEventReceiver(ISurfaceComposer::VsyncSource vsyncSource) {
sp<ISurfaceComposer> sf(ComposerService::getComposerService());
if (sf != NULL) {
- mEventConnection = sf->createDisplayEventConnection();
+ mEventConnection = sf->createDisplayEventConnection(vsyncSource);
if (mEventConnection != NULL) {
mDataChannel = std::make_unique<gui::BitTube>();
mEventConnection->stealReceiveChannel(mDataChannel.get());
diff --git a/libs/gui/GLConsumer.cpp b/libs/gui/GLConsumer.cpp
index c654f08..14d9937 100644
--- a/libs/gui/GLConsumer.cpp
+++ b/libs/gui/GLConsumer.cpp
@@ -21,6 +21,8 @@
#define GL_GLEXT_PROTOTYPES
#define EGL_EGLEXT_PROTOTYPES
+#include <inttypes.h>
+
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <GLES2/gl2.h>
@@ -41,7 +43,7 @@
#include <utils/String8.h>
#include <utils/Trace.h>
-EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name);
+extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name);
#define CROP_EXT_STR "EGL_ANDROID_image_crop"
#define PROT_CONTENT_EXT_STR "EGL_EXT_protected_content"
#define EGL_PROTECTED_CONTENT_EXT 0x32C0
@@ -1113,7 +1115,7 @@
return mConsumer->setDefaultBufferDataSpace(defaultDataSpace);
}
-status_t GLConsumer::setConsumerUsageBits(uint32_t usage) {
+status_t GLConsumer::setConsumerUsageBits(uint64_t usage) {
Mutex::Autolock lock(mMutex);
if (mAbandoned) {
GLC_LOGE("setConsumerUsageBits: GLConsumer is abandoned!");
@@ -1219,7 +1221,7 @@
mEglDisplay = EGL_NO_DISPLAY;
mCropRect.makeInvalid();
const sp<GraphicBuffer>& buffer = mGraphicBuffer;
- ALOGE("Failed to create image. size=%ux%u st=%u usage=0x%x fmt=%d",
+ ALOGE("Failed to create image. size=%ux%u st=%u usage=%#" PRIx64 " fmt=%d",
buffer->getWidth(), buffer->getHeight(), buffer->getStride(),
buffer->getUsage(), buffer->getPixelFormat());
return UNKNOWN_ERROR;
diff --git a/libs/gui/IGraphicBufferConsumer.cpp b/libs/gui/IGraphicBufferConsumer.cpp
index a573bee..c705d39 100644
--- a/libs/gui/IGraphicBufferConsumer.cpp
+++ b/libs/gui/IGraphicBufferConsumer.cpp
@@ -132,7 +132,7 @@
return callRemote<Signature>(Tag::SET_DEFAULT_BUFFER_DATA_SPACE, defaultDataSpace);
}
- status_t setConsumerUsageBits(uint32_t usage) override {
+ status_t setConsumerUsageBits(uint64_t usage) override {
using Signature = decltype(&IGraphicBufferConsumer::setConsumerUsageBits);
return callRemote<Signature>(Tag::SET_CONSUMER_USAGE_BITS, usage);
}
diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp
index 8481b50..71e22ce 100644
--- a/libs/gui/IGraphicBufferProducer.cpp
+++ b/libs/gui/IGraphicBufferProducer.cpp
@@ -62,7 +62,8 @@
SET_DEQUEUE_TIMEOUT,
GET_LAST_QUEUED_BUFFER,
GET_FRAME_TIMESTAMPS,
- GET_UNIQUE_ID
+ GET_UNIQUE_ID,
+ GET_CONSUMER_USAGE,
};
class BpGraphicBufferProducer : public BpInterface<IGraphicBufferProducer>
@@ -124,9 +125,9 @@
return result;
}
- virtual status_t dequeueBuffer(int *buf, sp<Fence>* fence, uint32_t width,
- uint32_t height, PixelFormat format, uint32_t usage,
- FrameEventHistoryDelta* outTimestamps) {
+ virtual status_t dequeueBuffer(int* buf, sp<Fence>* fence, uint32_t width, uint32_t height,
+ PixelFormat format, uint64_t usage, uint64_t* outBufferAge,
+ FrameEventHistoryDelta* outTimestamps) {
Parcel data, reply;
bool getFrameTimestamps = (outTimestamps != nullptr);
@@ -134,7 +135,7 @@
data.writeUint32(width);
data.writeUint32(height);
data.writeInt32(static_cast<int32_t>(format));
- data.writeUint32(usage);
+ data.writeUint64(usage);
data.writeBool(getFrameTimestamps);
status_t result = remote()->transact(DEQUEUE_BUFFER, data, &reply);
@@ -149,6 +150,17 @@
fence->clear();
return result;
}
+ if (outBufferAge) {
+ result = reply.readUint64(outBufferAge);
+ } else {
+ // Read the value even if outBufferAge is nullptr:
+ uint64_t bufferAge;
+ result = reply.readUint64(&bufferAge);
+ }
+ if (result != NO_ERROR) {
+ ALOGE("IGBP::dequeueBuffer failed to read buffer age: %d", result);
+ return result;
+ }
if (getFrameTimestamps) {
result = reply.read(*outTimestamps);
if (result != NO_ERROR) {
@@ -333,13 +345,13 @@
}
virtual void allocateBuffers(uint32_t width, uint32_t height,
- PixelFormat format, uint32_t usage) {
+ PixelFormat format, uint64_t usage) {
Parcel data, reply;
data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor());
data.writeUint32(width);
data.writeUint32(height);
data.writeInt32(static_cast<int32_t>(format));
- data.writeUint32(usage);
+ data.writeUint64(usage);
status_t result = remote()->transact(ALLOCATE_BUFFERS, data, &reply);
if (result != NO_ERROR) {
ALOGE("allocateBuffers failed to transact: %d", result);
@@ -493,6 +505,25 @@
}
return actualResult;
}
+
+ virtual status_t getConsumerUsage(uint64_t* outUsage) const {
+ Parcel data, reply;
+ data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor());
+ status_t result = remote()->transact(GET_CONSUMER_USAGE, data, &reply);
+ if (result != NO_ERROR) {
+ ALOGE("getConsumerUsage failed to transact: %d", result);
+ }
+ status_t actualResult = NO_ERROR;
+ result = reply.readInt32(&actualResult);
+ if (result != NO_ERROR) {
+ return result;
+ }
+ result = reply.readUint64(outUsage);
+ if (result != NO_ERROR) {
+ return result;
+ }
+ return actualResult;
+ }
};
// Out-of-line virtual method definition to trigger vtable emission in this
@@ -516,11 +547,10 @@
return mBase->setAsyncMode(async);
}
- status_t dequeueBuffer(int* slot, sp<Fence>* fence, uint32_t w, uint32_t h,
- PixelFormat format, uint32_t usage,
- FrameEventHistoryDelta* outTimestamps) override {
- return mBase->dequeueBuffer(
- slot, fence, w, h, format, usage, outTimestamps);
+ status_t dequeueBuffer(int* slot, sp<Fence>* fence, uint32_t w, uint32_t h, PixelFormat format,
+ uint64_t usage, uint64_t* outBufferAge,
+ FrameEventHistoryDelta* outTimestamps) override {
+ return mBase->dequeueBuffer(slot, fence, w, h, format, usage, outBufferAge, outTimestamps);
}
status_t detachBuffer(int slot) override {
@@ -569,7 +599,7 @@
}
void allocateBuffers(uint32_t width, uint32_t height,
- PixelFormat format, uint32_t usage) override {
+ PixelFormat format, uint64_t usage) override {
return mBase->allocateBuffers(width, height, format, usage);
}
@@ -612,6 +642,10 @@
status_t getUniqueId(uint64_t* outId) const override {
return mBase->getUniqueId(outId);
}
+
+ status_t getConsumerUsage(uint64_t* outUsage) const override {
+ return mBase->getConsumerUsage(outUsage);
+ }
};
IMPLEMENT_HYBRID_META_INTERFACE(GraphicBufferProducer, HGraphicBufferProducer,
@@ -654,17 +688,19 @@
uint32_t width = data.readUint32();
uint32_t height = data.readUint32();
PixelFormat format = static_cast<PixelFormat>(data.readInt32());
- uint32_t usage = data.readUint32();
+ uint64_t usage = data.readUint64();
+ uint64_t bufferAge = 0;
bool getTimestamps = data.readBool();
int buf = 0;
sp<Fence> fence = Fence::NO_FENCE;
FrameEventHistoryDelta frameTimestamps;
- int result = dequeueBuffer(&buf, &fence, width, height, format,
- usage, getTimestamps ? &frameTimestamps : nullptr);
+ int result = dequeueBuffer(&buf, &fence, width, height, format, usage, &bufferAge,
+ getTimestamps ? &frameTimestamps : nullptr);
reply->writeInt32(buf);
reply->write(*fence);
+ reply->writeUint64(bufferAge);
if (getTimestamps) {
reply->write(frameTimestamps);
}
@@ -777,7 +813,7 @@
uint32_t width = data.readUint32();
uint32_t height = data.readUint32();
PixelFormat format = static_cast<PixelFormat>(data.readInt32());
- uint32_t usage = data.readUint32();
+ uint64_t usage = data.readUint64();
allocateBuffers(width, height, format, usage);
return NO_ERROR;
}
@@ -877,6 +913,20 @@
}
return NO_ERROR;
}
+ case GET_CONSUMER_USAGE: {
+ CHECK_INTERFACE(IGraphicBufferProducer, data, reply);
+ uint64_t outUsage = 0;
+ status_t actualResult = getConsumerUsage(&outUsage);
+ status_t result = reply->writeInt32(actualResult);
+ if (result != NO_ERROR) {
+ return result;
+ }
+ result = reply->writeUint64(outUsage);
+ if (result != NO_ERROR) {
+ return result;
+ }
+ return NO_ERROR;
+ }
}
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index 2516fb8..973302c 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -28,8 +28,8 @@
#include <gui/IGraphicBufferProducer.h>
#include <gui/ISurfaceComposer.h>
#include <gui/ISurfaceComposerClient.h>
-
-#include <private/gui/LayerState.h>
+#include <gui/LayerDebugInfo.h>
+#include <gui/LayerState.h>
#include <system/graphics.h>
@@ -122,6 +122,18 @@
return reply.readInt32();
}
+ virtual status_t captureLayers(const sp<IBinder>& layerHandleBinder,
+ const sp<IGraphicBufferProducer>& producer,
+ ISurfaceComposer::Rotation rotation) {
+ Parcel data, reply;
+ data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+ data.writeStrongBinder(layerHandleBinder);
+ data.writeStrongBinder(IInterface::asBinder(producer));
+ data.writeInt32(static_cast<int32_t>(rotation));
+ remote()->transact(BnSurfaceComposer::CAPTURE_LAYERS, data, &reply);
+ return reply.readInt32();
+ }
+
virtual bool authenticateSurfaceTexture(
const sp<IGraphicBufferProducer>& bufferProducer) const
{
@@ -201,7 +213,7 @@
return NO_ERROR;
}
- virtual sp<IDisplayEventConnection> createDisplayEventConnection()
+ virtual sp<IDisplayEventConnection> createDisplayEventConnection(VsyncSource vsyncSource)
{
Parcel data, reply;
sp<IDisplayEventConnection> result;
@@ -210,6 +222,7 @@
if (err != NO_ERROR) {
return result;
}
+ data.writeInt32(static_cast<int32_t>(vsyncSource));
err = remote()->transact(
BnSurfaceComposer::CREATE_DISPLAY_EVENT_CONNECTION,
data, &reply);
@@ -468,6 +481,36 @@
return result;
}
+ virtual status_t getLayerDebugInfo(std::vector<LayerDebugInfo>* outLayers) const
+ {
+ if (!outLayers) {
+ return UNEXPECTED_NULL;
+ }
+
+ Parcel data, reply;
+
+ status_t err = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+ if (err != NO_ERROR) {
+ return err;
+ }
+
+ err = remote()->transact(BnSurfaceComposer::GET_LAYER_DEBUG_INFO, data, &reply);
+ if (err != NO_ERROR) {
+ return err;
+ }
+
+ int32_t result = 0;
+ err = reply.readInt32(&result);
+ if (err != NO_ERROR) {
+ return err;
+ }
+ if (result != NO_ERROR) {
+ return result;
+ }
+
+ outLayers->clear();
+ return reply.readParcelableVector(outLayers);
+ }
};
// Out-of-line virtual method definition to trigger vtable emission in this
@@ -557,6 +600,18 @@
reply->writeInt32(res);
return NO_ERROR;
}
+ case CAPTURE_LAYERS: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
+ sp<IBinder> layerHandleBinder = data.readStrongBinder();
+ sp<IGraphicBufferProducer> producer =
+ interface_cast<IGraphicBufferProducer>(data.readStrongBinder());
+ int32_t rotation = data.readInt32();
+
+ status_t res = captureLayers(layerHandleBinder, producer,
+ static_cast<ISurfaceComposer::Rotation>(rotation));
+ reply->writeInt32(res);
+ return NO_ERROR;
+ }
case AUTHENTICATE_SURFACE: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
sp<IGraphicBufferProducer> bufferProducer =
@@ -586,7 +641,8 @@
}
case CREATE_DISPLAY_EVENT_CONNECTION: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
- sp<IDisplayEventConnection> connection(createDisplayEventConnection());
+ sp<IDisplayEventConnection> connection(createDisplayEventConnection(
+ static_cast<ISurfaceComposer::VsyncSource>(data.readInt32())));
reply->writeStrongBinder(IInterface::asBinder(connection));
return NO_ERROR;
}
@@ -761,6 +817,17 @@
}
return injectVSync(when);
}
+ case GET_LAYER_DEBUG_INFO: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
+ std::vector<LayerDebugInfo> outLayers;
+ status_t result = getLayerDebugInfo(&outLayers);
+ reply->writeInt32(result);
+ if (result == NO_ERROR)
+ {
+ result = reply->writeParcelableVector(outLayers);
+ }
+ return result;
+ }
default: {
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/libs/gui/LayerDebugInfo.cpp b/libs/gui/LayerDebugInfo.cpp
new file mode 100644
index 0000000..d3dc16d
--- /dev/null
+++ b/libs/gui/LayerDebugInfo.cpp
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 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 <gui/LayerDebugInfo.h>
+
+#include <ui/DebugUtils.h>
+
+#include <binder/Parcel.h>
+
+#include <utils/String8.h>
+
+using namespace android;
+
+#define RETURN_ON_ERROR(X) do {status_t res = (X); if (res != NO_ERROR) return res;} while(false)
+
+namespace android {
+
+status_t LayerDebugInfo::writeToParcel(Parcel* parcel) const {
+ RETURN_ON_ERROR(parcel->writeCString(mName.c_str()));
+ RETURN_ON_ERROR(parcel->writeCString(mParentName.c_str()));
+ RETURN_ON_ERROR(parcel->writeCString(mType.c_str()));
+ RETURN_ON_ERROR(parcel->write(mTransparentRegion));
+ RETURN_ON_ERROR(parcel->write(mVisibleRegion));
+ RETURN_ON_ERROR(parcel->write(mSurfaceDamageRegion));
+ RETURN_ON_ERROR(parcel->writeUint32(mLayerStack));
+ RETURN_ON_ERROR(parcel->writeFloat(mX));
+ RETURN_ON_ERROR(parcel->writeFloat(mY));
+ RETURN_ON_ERROR(parcel->writeUint32(mZ));
+ RETURN_ON_ERROR(parcel->writeInt32(mWidth));
+ RETURN_ON_ERROR(parcel->writeInt32(mHeight));
+ RETURN_ON_ERROR(parcel->write(mCrop));
+ RETURN_ON_ERROR(parcel->write(mFinalCrop));
+ RETURN_ON_ERROR(parcel->writeFloat(mColor.r));
+ RETURN_ON_ERROR(parcel->writeFloat(mColor.g));
+ RETURN_ON_ERROR(parcel->writeFloat(mColor.b));
+ RETURN_ON_ERROR(parcel->writeFloat(mColor.a));
+ RETURN_ON_ERROR(parcel->writeUint32(mFlags));
+ RETURN_ON_ERROR(parcel->writeInt32(mPixelFormat));
+ RETURN_ON_ERROR(parcel->writeUint32(static_cast<uint32_t>(mDataSpace)));
+ for (size_t index = 0; index < 4; index++) {
+ RETURN_ON_ERROR(parcel->writeFloat(mMatrix[index / 2][index % 2]));
+ }
+ RETURN_ON_ERROR(parcel->writeInt32(mActiveBufferWidth));
+ RETURN_ON_ERROR(parcel->writeInt32(mActiveBufferHeight));
+ RETURN_ON_ERROR(parcel->writeInt32(mActiveBufferStride));
+ RETURN_ON_ERROR(parcel->writeInt32(mActiveBufferFormat));
+ RETURN_ON_ERROR(parcel->writeInt32(mNumQueuedFrames));
+ RETURN_ON_ERROR(parcel->writeBool(mRefreshPending));
+ RETURN_ON_ERROR(parcel->writeBool(mIsOpaque));
+ RETURN_ON_ERROR(parcel->writeBool(mContentDirty));
+ return NO_ERROR;
+}
+
+status_t LayerDebugInfo::readFromParcel(const Parcel* parcel) {
+ mName = parcel->readCString();
+ RETURN_ON_ERROR(parcel->errorCheck());
+ mParentName = parcel->readCString();
+ RETURN_ON_ERROR(parcel->errorCheck());
+ mType = parcel->readCString();
+ RETURN_ON_ERROR(parcel->errorCheck());
+ RETURN_ON_ERROR(parcel->read(mTransparentRegion));
+ RETURN_ON_ERROR(parcel->read(mVisibleRegion));
+ RETURN_ON_ERROR(parcel->read(mSurfaceDamageRegion));
+ RETURN_ON_ERROR(parcel->readUint32(&mLayerStack));
+ RETURN_ON_ERROR(parcel->readFloat(&mX));
+ RETURN_ON_ERROR(parcel->readFloat(&mY));
+ RETURN_ON_ERROR(parcel->readUint32(&mZ));
+ RETURN_ON_ERROR(parcel->readInt32(&mWidth));
+ RETURN_ON_ERROR(parcel->readInt32(&mHeight));
+ RETURN_ON_ERROR(parcel->read(mCrop));
+ RETURN_ON_ERROR(parcel->read(mFinalCrop));
+ mColor.r = parcel->readFloat();
+ RETURN_ON_ERROR(parcel->errorCheck());
+ mColor.g = parcel->readFloat();
+ RETURN_ON_ERROR(parcel->errorCheck());
+ mColor.b = parcel->readFloat();
+ RETURN_ON_ERROR(parcel->errorCheck());
+ mColor.a = parcel->readFloat();
+ RETURN_ON_ERROR(parcel->errorCheck());
+ RETURN_ON_ERROR(parcel->readUint32(&mFlags));
+ RETURN_ON_ERROR(parcel->readInt32(&mPixelFormat));
+ // \todo [2017-07-25 kraita]: Static casting mDataSpace pointer to an uint32 does work. Better ways?
+ mDataSpace = static_cast<android_dataspace>(parcel->readUint32());
+ RETURN_ON_ERROR(parcel->errorCheck());
+ for (size_t index = 0; index < 4; index++) {
+ RETURN_ON_ERROR(parcel->readFloat(&mMatrix[index / 2][index % 2]));
+ }
+ RETURN_ON_ERROR(parcel->readInt32(&mActiveBufferWidth));
+ RETURN_ON_ERROR(parcel->readInt32(&mActiveBufferHeight));
+ RETURN_ON_ERROR(parcel->readInt32(&mActiveBufferStride));
+ RETURN_ON_ERROR(parcel->readInt32(&mActiveBufferFormat));
+ RETURN_ON_ERROR(parcel->readInt32(&mNumQueuedFrames));
+ RETURN_ON_ERROR(parcel->readBool(&mRefreshPending));
+ RETURN_ON_ERROR(parcel->readBool(&mIsOpaque));
+ RETURN_ON_ERROR(parcel->readBool(&mContentDirty));
+ return NO_ERROR;
+}
+
+std::string to_string(const LayerDebugInfo& info) {
+ String8 result;
+
+ result.appendFormat("+ %s (%s)\n", info.mType.c_str(), info.mName.c_str());
+ info.mTransparentRegion.dump(result, "TransparentRegion");
+ info.mVisibleRegion.dump(result, "VisibleRegion");
+ info.mSurfaceDamageRegion.dump(result, "SurfaceDamageRegion");
+
+ result.appendFormat(" layerStack=%4d, z=%9d, pos=(%g,%g), size=(%4d,%4d), ",
+ info.mLayerStack, info.mZ, static_cast<double>(info.mX), static_cast<double>(info.mY),
+ info.mWidth, info.mHeight);
+
+ result.appendFormat("crop=%s, finalCrop=%s, ",
+ to_string(info.mCrop).c_str(), to_string(info.mFinalCrop).c_str());
+ result.appendFormat("isOpaque=%1d, invalidate=%1d, ", info.mIsOpaque, info.mContentDirty);
+ result.appendFormat("dataspace=%s, ", dataspaceDetails(info.mDataSpace).c_str());
+ result.appendFormat("pixelformat=%s, ", decodePixelFormat(info.mPixelFormat).c_str());
+ result.appendFormat("color=(%.3f,%.3f,%.3f,%.3f), flags=0x%08x, ",
+ static_cast<double>(info.mColor.r), static_cast<double>(info.mColor.g),
+ static_cast<double>(info.mColor.b), static_cast<double>(info.mColor.a),
+ info.mFlags);
+ result.appendFormat("tr=[%.2f, %.2f][%.2f, %.2f]",
+ static_cast<double>(info.mMatrix[0][0]), static_cast<double>(info.mMatrix[0][1]),
+ static_cast<double>(info.mMatrix[1][0]), static_cast<double>(info.mMatrix[1][1]));
+ result.append("\n");
+ result.appendFormat(" parent=%s\n", info.mParentName.c_str());
+ result.appendFormat(" activeBuffer=[%4ux%4u:%4u,%s],",
+ info.mActiveBufferWidth, info.mActiveBufferHeight,
+ info.mActiveBufferStride,
+ decodePixelFormat(info.mActiveBufferFormat).c_str());
+ result.appendFormat(" queued-frames=%d, mRefreshPending=%d",
+ info.mNumQueuedFrames, info.mRefreshPending);
+ result.append("\n");
+ return std::string(result.c_str());
+}
+
+} // android
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index 9b06e63..b5295f2 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -18,7 +18,7 @@
#include <binder/Parcel.h>
#include <gui/ISurfaceComposerClient.h>
#include <gui/IGraphicBufferProducer.h>
-#include <private/gui/LayerState.h>
+#include <gui/LayerState.h>
namespace android {
@@ -45,6 +45,10 @@
output.writeInt32(overrideScalingMode);
output.writeStrongBinder(IInterface::asBinder(barrierGbp));
output.writeStrongBinder(relativeLayerHandle);
+ output.writeStrongBinder(parentHandleForChild);
+ output.writeFloat(color.r);
+ output.writeFloat(color.g);
+ output.writeFloat(color.b);
output.write(transparentRegion);
return NO_ERROR;
}
@@ -77,6 +81,10 @@
barrierGbp =
interface_cast<IGraphicBufferProducer>(input.readStrongBinder());
relativeLayerHandle = input.readStrongBinder();
+ parentHandleForChild = input.readStrongBinder();
+ color.r = input.readFloat();
+ color.g = input.readFloat();
+ color.b = input.readFloat();
input.read(transparentRegion);
return NO_ERROR;
}
@@ -128,5 +136,101 @@
return NO_ERROR;
}
+void DisplayState::merge(const DisplayState& other) {
+ if (other.what & eSurfaceChanged) {
+ what |= eSurfaceChanged;
+ surface = other.surface;
+ }
+ if (other.what & eLayerStackChanged) {
+ what |= eLayerStackChanged;
+ layerStack = other.layerStack;
+ }
+ if (other.what & eDisplayProjectionChanged) {
+ what |= eDisplayProjectionChanged;
+ orientation = other.orientation;
+ viewport = other.viewport;
+ frame = other.frame;
+ }
+ if (other.what & eDisplaySizeChanged) {
+ what |= eDisplaySizeChanged;
+ width = other.width;
+ height = other.height;
+ }
+}
+
+void layer_state_t::merge(const layer_state_t& other) {
+ if (other.what & ePositionChanged) {
+ what |= ePositionChanged;
+ x = other.x;
+ y = other.y;
+ }
+ if (other.what & eLayerChanged) {
+ what |= eLayerChanged;
+ z = other.z;
+ }
+ if (other.what & eSizeChanged) {
+ what |= eSizeChanged;
+ w = other.w;
+ h = other.h;
+ }
+ if (other.what & eAlphaChanged) {
+ what |= eAlphaChanged;
+ alpha = other.alpha;
+ }
+ if (other.what & eMatrixChanged) {
+ what |= eMatrixChanged;
+ matrix = other.matrix;
+ }
+ if (other.what & eTransparentRegionChanged) {
+ what |= eTransparentRegionChanged;
+ transparentRegion = other.transparentRegion;
+ }
+ if (other.what & eFlagsChanged) {
+ what |= eFlagsChanged;
+ flags = other.flags;
+ mask = other.mask;
+ }
+ if (other.what & eLayerStackChanged) {
+ what |= eLayerStackChanged;
+ layerStack = other.layerStack;
+ }
+ if (other.what & eCropChanged) {
+ what |= eCropChanged;
+ crop = other.crop;
+ }
+ if (other.what & eDeferTransaction) {
+ what |= eDeferTransaction;
+ barrierHandle = other.barrierHandle;
+ barrierGbp = other.barrierGbp;
+ frameNumber = other.frameNumber;
+ }
+ if (other.what & eFinalCropChanged) {
+ what |= eFinalCropChanged;
+ finalCrop = other.finalCrop;
+ }
+ if (other.what & eOverrideScalingModeChanged) {
+ what |= eOverrideScalingModeChanged;
+ overrideScalingMode = other.overrideScalingMode;
+ }
+ if (other.what & eGeometryAppliesWithResize) {
+ what |= eGeometryAppliesWithResize;
+ }
+ if (other.what & eReparentChildren) {
+ what |= eReparentChildren;
+ reparentHandle = other.reparentHandle;
+ }
+ if (other.what & eDetachChildren) {
+ what |= eDetachChildren;
+ }
+ if (other.what & eRelativeLayerChanged) {
+ what |= eRelativeLayerChanged;
+ z = other.z;
+ relativeLayerHandle = other.relativeLayerHandle;
+ }
+ if (other.what & eReparent) {
+ what |= eReparent;
+ parentHandleForChild = other.parentHandleForChild;
+ }
+}
}; // namespace android
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index 83ebbe8..e939383 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -20,6 +20,8 @@
#include <gui/Surface.h>
+#include <inttypes.h>
+
#include <android/native_window.h>
#include <utils/Log.h>
@@ -42,21 +44,19 @@
namespace android {
-Surface::Surface(
- const sp<IGraphicBufferProducer>& bufferProducer,
- bool controlledByApp)
- : mGraphicBufferProducer(bufferProducer),
- mCrop(Rect::EMPTY_RECT),
- mGenerationNumber(0),
- mSharedBufferMode(false),
- mAutoRefresh(false),
- mSharedBufferSlot(BufferItem::INVALID_BUFFER_SLOT),
- mSharedBufferHasBeenQueued(false),
- mQueriedSupportedTimestamps(false),
- mFrameTimestampsSupportsPresent(false),
- mEnableFrameTimestamps(false),
- mFrameEventHistory(std::make_unique<ProducerFrameEventHistory>())
-{
+Surface::Surface(const sp<IGraphicBufferProducer>& bufferProducer, bool controlledByApp)
+ : mGraphicBufferProducer(bufferProducer),
+ mCrop(Rect::EMPTY_RECT),
+ mBufferAge(0),
+ mGenerationNumber(0),
+ mSharedBufferMode(false),
+ mAutoRefresh(false),
+ mSharedBufferSlot(BufferItem::INVALID_BUFFER_SLOT),
+ mSharedBufferHasBeenQueued(false),
+ mQueriedSupportedTimestamps(false),
+ mFrameTimestampsSupportsPresent(false),
+ mEnableFrameTimestamps(false),
+ mFrameEventHistory(std::make_unique<ProducerFrameEventHistory>()) {
// Initialize the ANativeWindow function pointers.
ANativeWindow::setSwapInterval = hook_setSwapInterval;
ANativeWindow::dequeueBuffer = hook_dequeueBuffer;
@@ -153,7 +153,10 @@
ATRACE_CALL();
DisplayStatInfo stats;
- status_t err = composerService()->getDisplayStats(NULL, &stats);
+ status_t result = composerService()->getDisplayStats(NULL, &stats);
+ if (result != NO_ERROR) {
+ return result;
+ }
*outRefreshDuration = stats.vsyncPeriod;
@@ -471,7 +474,7 @@
uint32_t reqWidth;
uint32_t reqHeight;
PixelFormat reqFormat;
- uint32_t reqUsage;
+ uint64_t reqUsage;
bool enableFrameTimestamps;
{
@@ -501,18 +504,19 @@
int buf = -1;
sp<Fence> fence;
- nsecs_t now = systemTime();
+ nsecs_t startTime = systemTime();
FrameEventHistoryDelta frameTimestamps;
- status_t result = mGraphicBufferProducer->dequeueBuffer(&buf, &fence,
- reqWidth, reqHeight, reqFormat, reqUsage,
- enableFrameTimestamps ? &frameTimestamps : nullptr);
- mLastDequeueDuration = systemTime() - now;
+ status_t result = mGraphicBufferProducer->dequeueBuffer(&buf, &fence, reqWidth, reqHeight,
+ reqFormat, reqUsage, &mBufferAge,
+ enableFrameTimestamps ? &frameTimestamps
+ : nullptr);
+ mLastDequeueDuration = systemTime() - startTime;
if (result < 0) {
ALOGV("dequeueBuffer: IGraphicBufferProducer::dequeueBuffer"
- "(%d, %d, %d, %d) failed: %d", reqWidth, reqHeight, reqFormat,
- reqUsage, result);
+ "(%d, %d, %d, %#" PRIx64 ") failed: %d",
+ reqWidth, reqHeight, reqFormat, reqUsage, result);
return result;
}
@@ -524,6 +528,9 @@
Mutex::Autolock lock(mMutex);
+ // Write this while holding the mutex
+ mLastDequeueStartTime = startTime;
+
sp<GraphicBuffer>& gbuf(mSlots[buf].buffer);
// this should never happen
@@ -840,6 +847,14 @@
}
return err;
}
+ case NATIVE_WINDOW_BUFFER_AGE: {
+ if (mBufferAge > INT32_MAX) {
+ *value = 0;
+ } else {
+ *value = static_cast<int32_t>(mBufferAge);
+ }
+ return NO_ERROR;
+ }
case NATIVE_WINDOW_LAST_DEQUEUE_DURATION: {
int64_t durationUs = mLastDequeueDuration / 1000;
*value = durationUs > std::numeric_limits<int>::max() ?
@@ -959,6 +974,12 @@
case NATIVE_WINDOW_GET_HDR_SUPPORT:
res = dispatchGetHdrSupport(args);
break;
+ case NATIVE_WINDOW_SET_USAGE64:
+ res = dispatchSetUsage64(args);
+ break;
+ case NATIVE_WINDOW_GET_CONSUMER_USAGE64:
+ res = dispatchGetConsumerUsage64(args);
+ break;
default:
res = NAME_NOT_FOUND;
break;
@@ -977,8 +998,13 @@
}
int Surface::dispatchSetUsage(va_list args) {
- int usage = va_arg(args, int);
- return setUsage(static_cast<uint32_t>(usage));
+ uint64_t usage = va_arg(args, uint32_t);
+ return setUsage(usage);
+}
+
+int Surface::dispatchSetUsage64(va_list args) {
+ uint64_t usage = va_arg(args, uint64_t);
+ return setUsage(usage);
}
int Surface::dispatchSetCrop(va_list args) {
@@ -1132,6 +1158,11 @@
return getHdrSupport(outSupport);
}
+int Surface::dispatchGetConsumerUsage64(va_list args) {
+ uint64_t* usage = va_arg(args, uint64_t*);
+ return getConsumerUsage(usage);
+}
+
int Surface::connect(int api) {
static sp<IProducerListener> listener = new DummyProducerListener();
return connect(api, listener);
@@ -1256,8 +1287,7 @@
uint32_t priorGeneration = graphicBuffer->mGenerationNumber;
graphicBuffer->mGenerationNumber = mGenerationNumber;
int32_t attachedSlot = -1;
- status_t result = mGraphicBufferProducer->attachBuffer(
- &attachedSlot, graphicBuffer);
+ status_t result = mGraphicBufferProducer->attachBuffer(&attachedSlot, graphicBuffer);
if (result != NO_ERROR) {
ALOGE("attachBuffer: IGraphicBufferProducer call failed (%d)", result);
graphicBuffer->mGenerationNumber = priorGeneration;
@@ -1271,7 +1301,7 @@
return NO_ERROR;
}
-int Surface::setUsage(uint32_t reqUsage)
+int Surface::setUsage(uint64_t reqUsage)
{
ALOGV("Surface::setUsage");
Mutex::Autolock lock(mMutex);
@@ -1482,6 +1512,12 @@
return NO_ERROR;
}
+android_dataspace_t Surface::getBuffersDataSpace() {
+ ALOGV("Surface::getBuffersDataSpace");
+ Mutex::Autolock lock(mMutex);
+ return mDataSpace;
+}
+
void Surface::freeAllBuffers() {
for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
mSlots[i].buffer = 0;
@@ -1702,6 +1738,16 @@
return mGraphicBufferProducer->getUniqueId(outId);
}
+int Surface::getConsumerUsage(uint64_t* outUsage) const {
+ Mutex::Autolock lock(mMutex);
+ return mGraphicBufferProducer->getConsumerUsage(outUsage);
+}
+
+nsecs_t Surface::getLastDequeueStartTime() const {
+ Mutex::Autolock lock(mMutex);
+ return mLastDequeueStartTime;
+}
+
status_t Surface::getAndFlushRemovedBuffers(std::vector<sp<GraphicBuffer>>* out) {
if (out == nullptr) {
ALOGE("%s: out must not be null!", __FUNCTION__);
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 8c83843..2adc273 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -21,7 +21,6 @@
#include <utils/Errors.h>
#include <utils/Log.h>
-#include <utils/Singleton.h>
#include <utils/SortedVector.h>
#include <utils/String8.h>
#include <utils/threads.h>
@@ -37,11 +36,11 @@
#include <gui/IGraphicBufferProducer.h>
#include <gui/ISurfaceComposer.h>
#include <gui/ISurfaceComposerClient.h>
+#include <gui/LayerState.h>
#include <gui/Surface.h>
#include <gui/SurfaceComposerClient.h>
#include <private/gui/ComposerService.h>
-#include <private/gui/LayerState.h>
namespace android {
// ---------------------------------------------------------------------------
@@ -97,204 +96,95 @@
// ---------------------------------------------------------------------------
-static inline
-int compare_type(const ComposerState& lhs, const ComposerState& rhs) {
- if (lhs.client < rhs.client) return -1;
- if (lhs.client > rhs.client) return 1;
- if (lhs.state.surface < rhs.state.surface) return -1;
- if (lhs.state.surface > rhs.state.surface) return 1;
- return 0;
+SurfaceComposerClient::Transaction::Transaction(const Transaction& other) :
+ mForceSynchronous(other.mForceSynchronous),
+ mTransactionNestCount(other.mTransactionNestCount),
+ mAnimation(other.mAnimation) {
+ mDisplayStates = other.mDisplayStates;
+ mComposerStates = other.mComposerStates;
}
-static inline
-int compare_type(const DisplayState& lhs, const DisplayState& rhs) {
- return compare_type(lhs.token, rhs.token);
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::merge(Transaction&& other) {
+ for (auto const& state : other.mComposerStates) {
+ ssize_t index = mComposerStates.indexOf(state);
+ if (index < 0) {
+ mComposerStates.add(state);
+ } else {
+ mComposerStates.editItemAt(static_cast<size_t>(index)).state.merge(state.state);
+ }
+ }
+ other.mComposerStates.clear();
+
+ for (auto const& state : other.mDisplayStates) {
+ ssize_t index = mDisplayStates.indexOf(state);
+ if (index < 0) {
+ mDisplayStates.add(state);
+ } else {
+ mDisplayStates.editItemAt(static_cast<size_t>(index)).merge(state);
+ }
+ }
+ other.mDisplayStates.clear();
+
+ return *this;
}
-class Composer : public Singleton<Composer>
-{
- friend class Singleton<Composer>;
-
- mutable Mutex mLock;
- SortedVector<ComposerState> mComposerStates;
- SortedVector<DisplayState > mDisplayStates;
- uint32_t mForceSynchronous;
- uint32_t mTransactionNestCount;
- bool mAnimation;
-
- Composer() : Singleton<Composer>(),
- mForceSynchronous(0), mTransactionNestCount(0),
- mAnimation(false)
- { }
-
- void openGlobalTransactionImpl();
- void closeGlobalTransactionImpl(bool synchronous);
- void setAnimationTransactionImpl();
- status_t enableVSyncInjectionsImpl(bool enable);
- status_t injectVSyncImpl(nsecs_t when);
-
- layer_state_t* getLayerStateLocked(
- const sp<SurfaceComposerClient>& client, const sp<IBinder>& id);
-
- DisplayState& getDisplayStateLocked(const sp<IBinder>& token);
-
-public:
- sp<IBinder> createDisplay(const String8& displayName, bool secure);
- void destroyDisplay(const sp<IBinder>& display);
- sp<IBinder> getBuiltInDisplay(int32_t id);
-
- status_t setPosition(const sp<SurfaceComposerClient>& client, const sp<IBinder>& id,
- float x, float y);
- status_t setSize(const sp<SurfaceComposerClient>& client, const sp<IBinder>& id,
- uint32_t w, uint32_t h);
- status_t setLayer(const sp<SurfaceComposerClient>& client, const sp<IBinder>& id,
- int32_t z);
- status_t setRelativeLayer(const sp<SurfaceComposerClient>& client, const sp<IBinder>& id,
- const sp<IBinder>& relativeTo, int32_t z);
- status_t setFlags(const sp<SurfaceComposerClient>& client, const sp<IBinder>& id,
- uint32_t flags, uint32_t mask);
- status_t setTransparentRegionHint(
- const sp<SurfaceComposerClient>& client, const sp<IBinder>& id,
- const Region& transparentRegion);
- status_t setAlpha(const sp<SurfaceComposerClient>& client, const sp<IBinder>& id,
- float alpha);
- status_t setMatrix(const sp<SurfaceComposerClient>& client, const sp<IBinder>& id,
- float dsdx, float dtdx, float dtdy, float dsdy);
- status_t setOrientation(int orientation);
- status_t setCrop(const sp<SurfaceComposerClient>& client, const sp<IBinder>& id,
- const Rect& crop);
- status_t setFinalCrop(const sp<SurfaceComposerClient>& client,
- const sp<IBinder>& id, const Rect& crop);
- status_t setLayerStack(const sp<SurfaceComposerClient>& client,
- const sp<IBinder>& id, uint32_t layerStack);
- status_t deferTransactionUntil(const sp<SurfaceComposerClient>& client,
- const sp<IBinder>& id, const sp<IBinder>& handle,
- uint64_t frameNumber);
- status_t deferTransactionUntil(const sp<SurfaceComposerClient>& client,
- const sp<IBinder>& id, const sp<Surface>& barrierSurface,
- uint64_t frameNumber);
- status_t reparentChildren(const sp<SurfaceComposerClient>& client,
- const sp<IBinder>& id,
- const sp<IBinder>& newParentHandle);
- status_t detachChildren(const sp<SurfaceComposerClient>& client,
- const sp<IBinder>& id);
- status_t setOverrideScalingMode(const sp<SurfaceComposerClient>& client,
- const sp<IBinder>& id, int32_t overrideScalingMode);
- status_t setGeometryAppliesWithResize(const sp<SurfaceComposerClient>& client,
- const sp<IBinder>& id);
-
- status_t setDisplaySurface(const sp<IBinder>& token,
- sp<IGraphicBufferProducer> bufferProducer);
- void setDisplayLayerStack(const sp<IBinder>& token, uint32_t layerStack);
- void setDisplayProjection(const sp<IBinder>& token,
- uint32_t orientation,
- const Rect& layerStackRect,
- const Rect& displayRect);
- void setDisplaySize(const sp<IBinder>& token, uint32_t width, uint32_t height);
-
- static void setAnimationTransaction() {
- Composer::getInstance().setAnimationTransactionImpl();
+status_t SurfaceComposerClient::Transaction::apply(bool synchronous) {
+ if (mStatus != NO_ERROR) {
+ return mStatus;
}
- static void openGlobalTransaction() {
- Composer::getInstance().openGlobalTransactionImpl();
+ sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+
+ Vector<ComposerState> composerStates;
+ Vector<DisplayState> displayStates;
+ uint32_t flags = 0;
+
+ mForceSynchronous |= synchronous;
+
+ composerStates = mComposerStates;
+ mComposerStates.clear();
+
+ displayStates = mDisplayStates;
+ mDisplayStates.clear();
+
+ if (mForceSynchronous) {
+ flags |= ISurfaceComposer::eSynchronous;
+ }
+ if (mAnimation) {
+ flags |= ISurfaceComposer::eAnimation;
}
- static void closeGlobalTransaction(bool synchronous) {
- Composer::getInstance().closeGlobalTransactionImpl(synchronous);
- }
+ mForceSynchronous = false;
+ mAnimation = false;
- static status_t enableVSyncInjections(bool enable) {
- return Composer::getInstance().enableVSyncInjectionsImpl(enable);
- }
-
- static status_t injectVSync(nsecs_t when) {
- return Composer::getInstance().injectVSyncImpl(when);
- }
-};
-
-ANDROID_SINGLETON_STATIC_INSTANCE(Composer);
+ sf->setTransactionState(composerStates, displayStates, flags);
+ mStatus = NO_ERROR;
+ return NO_ERROR;
+}
// ---------------------------------------------------------------------------
-sp<IBinder> Composer::createDisplay(const String8& displayName, bool secure) {
+sp<IBinder> SurfaceComposerClient::createDisplay(const String8& displayName, bool secure) {
return ComposerService::getComposerService()->createDisplay(displayName,
secure);
}
-void Composer::destroyDisplay(const sp<IBinder>& display) {
+void SurfaceComposerClient::destroyDisplay(const sp<IBinder>& display) {
return ComposerService::getComposerService()->destroyDisplay(display);
}
-sp<IBinder> Composer::getBuiltInDisplay(int32_t id) {
+sp<IBinder> SurfaceComposerClient::getBuiltInDisplay(int32_t id) {
return ComposerService::getComposerService()->getBuiltInDisplay(id);
}
-void Composer::openGlobalTransactionImpl() {
- { // scope for the lock
- Mutex::Autolock _l(mLock);
- mTransactionNestCount += 1;
- }
-}
-
-void Composer::closeGlobalTransactionImpl(bool synchronous) {
- sp<ISurfaceComposer> sm(ComposerService::getComposerService());
-
- Vector<ComposerState> transaction;
- Vector<DisplayState> displayTransaction;
- uint32_t flags = 0;
-
- { // scope for the lock
- Mutex::Autolock _l(mLock);
- mForceSynchronous |= synchronous;
- if (!mTransactionNestCount) {
- ALOGW("At least one call to closeGlobalTransaction() was not matched by a prior "
- "call to openGlobalTransaction().");
- } else if (--mTransactionNestCount) {
- return;
- }
-
- transaction = mComposerStates;
- mComposerStates.clear();
-
- displayTransaction = mDisplayStates;
- mDisplayStates.clear();
-
- if (mForceSynchronous) {
- flags |= ISurfaceComposer::eSynchronous;
- }
- if (mAnimation) {
- flags |= ISurfaceComposer::eAnimation;
- }
-
- mForceSynchronous = false;
- mAnimation = false;
- }
-
- sm->setTransactionState(transaction, displayTransaction, flags);
-}
-
-status_t Composer::enableVSyncInjectionsImpl(bool enable) {
- sp<ISurfaceComposer> sm(ComposerService::getComposerService());
- return sm->enableVSyncInjections(enable);
-}
-
-status_t Composer::injectVSyncImpl(nsecs_t when) {
- sp<ISurfaceComposer> sm(ComposerService::getComposerService());
- return sm->injectVSync(when);
-}
-
-void Composer::setAnimationTransactionImpl() {
- Mutex::Autolock _l(mLock);
+void SurfaceComposerClient::Transaction::setAnimationTransaction() {
mAnimation = true;
}
-layer_state_t* Composer::getLayerStateLocked(
- const sp<SurfaceComposerClient>& client, const sp<IBinder>& id) {
-
+layer_state_t* SurfaceComposerClient::Transaction::getLayerStateLocked(const sp<SurfaceControl>& sc) {
ComposerState s;
- s.client = client->mClient;
- s.state.surface = id;
+ s.client = sc->getClient()->mClient;
+ s.state.surface = sc->getHandle();
ssize_t index = mComposerStates.indexOf(s);
if (index < 0) {
@@ -306,24 +196,36 @@
return &(out[index].state);
}
-status_t Composer::setPosition(const sp<SurfaceComposerClient>& client,
- const sp<IBinder>& id, float x, float y) {
- Mutex::Autolock _l(mLock);
- layer_state_t* s = getLayerStateLocked(client, id);
- if (!s)
- return BAD_INDEX;
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setPosition(
+ const sp<SurfaceControl>& sc, float x, float y) {
+ layer_state_t* s = getLayerStateLocked(sc);
+ if (!s) {
+ mStatus = BAD_INDEX;
+ return *this;
+ }
s->what |= layer_state_t::ePositionChanged;
s->x = x;
s->y = y;
- return NO_ERROR;
+ return *this;
}
-status_t Composer::setSize(const sp<SurfaceComposerClient>& client,
- const sp<IBinder>& id, uint32_t w, uint32_t h) {
- Mutex::Autolock _l(mLock);
- layer_state_t* s = getLayerStateLocked(client, id);
- if (!s)
- return BAD_INDEX;
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::show(
+ const sp<SurfaceControl>& sc) {
+ return setFlags(sc, 0, layer_state_t::eLayerHidden);
+}
+
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::hide(
+ const sp<SurfaceControl>& sc) {
+ return setFlags(sc, layer_state_t::eLayerHidden, layer_state_t::eLayerHidden);
+}
+
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setSize(
+ const sp<SurfaceControl>& sc, uint32_t w, uint32_t h) {
+ layer_state_t* s = getLayerStateLocked(sc);
+ if (!s) {
+ mStatus = BAD_INDEX;
+ return *this;
+ }
s->what |= layer_state_t::eSizeChanged;
s->w = w;
s->h = h;
@@ -331,41 +233,41 @@
// Resizing a surface makes the transaction synchronous.
mForceSynchronous = true;
- return NO_ERROR;
+ return *this;
}
-status_t Composer::setLayer(const sp<SurfaceComposerClient>& client,
- const sp<IBinder>& id, int32_t z) {
- Mutex::Autolock _l(mLock);
- layer_state_t* s = getLayerStateLocked(client, id);
- if (!s)
- return BAD_INDEX;
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setLayer(
+ const sp<SurfaceControl>& sc, int32_t z) {
+ layer_state_t* s = getLayerStateLocked(sc);
+ if (!s) {
+ mStatus = BAD_INDEX;
+ return *this;
+ }
s->what |= layer_state_t::eLayerChanged;
s->z = z;
- return NO_ERROR;
+ return *this;
}
-status_t Composer::setRelativeLayer(const sp<SurfaceComposerClient>& client,
- const sp<IBinder>& id, const sp<IBinder>& relativeTo,
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setRelativeLayer(const sp<SurfaceControl>& sc, const sp<IBinder>& relativeTo,
int32_t z) {
- Mutex::Autolock _l(mLock);
- layer_state_t* s = getLayerStateLocked(client, id);
+ layer_state_t* s = getLayerStateLocked(sc);
if (!s) {
- return BAD_INDEX;
+ mStatus = BAD_INDEX;
}
s->what |= layer_state_t::eRelativeLayerChanged;
s->relativeLayerHandle = relativeTo;
s->z = z;
- return NO_ERROR;
+ return *this;
}
-status_t Composer::setFlags(const sp<SurfaceComposerClient>& client,
- const sp<IBinder>& id, uint32_t flags,
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFlags(
+ const sp<SurfaceControl>& sc, uint32_t flags,
uint32_t mask) {
- Mutex::Autolock _l(mLock);
- layer_state_t* s = getLayerStateLocked(client, id);
- if (!s)
- return BAD_INDEX;
+ layer_state_t* s = getLayerStateLocked(sc);
+ if (!s) {
+ mStatus = BAD_INDEX;
+ return *this;
+ }
if ((mask & layer_state_t::eLayerOpaque) ||
(mask & layer_state_t::eLayerHidden) ||
(mask & layer_state_t::eLayerSecure)) {
@@ -374,50 +276,54 @@
s->flags &= ~mask;
s->flags |= (flags & mask);
s->mask |= mask;
- return NO_ERROR;
+ return *this;
}
-status_t Composer::setTransparentRegionHint(
- const sp<SurfaceComposerClient>& client, const sp<IBinder>& id,
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setTransparentRegionHint(
+ const sp<SurfaceControl>& sc,
const Region& transparentRegion) {
- Mutex::Autolock _l(mLock);
- layer_state_t* s = getLayerStateLocked(client, id);
- if (!s)
- return BAD_INDEX;
+ layer_state_t* s = getLayerStateLocked(sc);
+ if (!s) {
+ mStatus = BAD_INDEX;
+ return *this;
+ }
s->what |= layer_state_t::eTransparentRegionChanged;
s->transparentRegion = transparentRegion;
- return NO_ERROR;
+ return *this;
}
-status_t Composer::setAlpha(const sp<SurfaceComposerClient>& client,
- const sp<IBinder>& id, float alpha) {
- Mutex::Autolock _l(mLock);
- layer_state_t* s = getLayerStateLocked(client, id);
- if (!s)
- return BAD_INDEX;
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setAlpha(
+ const sp<SurfaceControl>& sc, float alpha) {
+ layer_state_t* s = getLayerStateLocked(sc);
+ if (!s) {
+ mStatus = BAD_INDEX;
+ return *this;
+ }
s->what |= layer_state_t::eAlphaChanged;
s->alpha = alpha;
- return NO_ERROR;
+ return *this;
}
-status_t Composer::setLayerStack(const sp<SurfaceComposerClient>& client,
- const sp<IBinder>& id, uint32_t layerStack) {
- Mutex::Autolock _l(mLock);
- layer_state_t* s = getLayerStateLocked(client, id);
- if (!s)
- return BAD_INDEX;
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setLayerStack(
+ const sp<SurfaceControl>& sc, uint32_t layerStack) {
+ layer_state_t* s = getLayerStateLocked(sc);
+ if (!s) {
+ mStatus = BAD_INDEX;
+ return *this;
+ }
s->what |= layer_state_t::eLayerStackChanged;
s->layerStack = layerStack;
- return NO_ERROR;
+ return *this;
}
-status_t Composer::setMatrix(const sp<SurfaceComposerClient>& client,
- const sp<IBinder>& id, float dsdx, float dtdx,
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setMatrix(
+ const sp<SurfaceControl>& sc, float dsdx, float dtdx,
float dtdy, float dsdy) {
- Mutex::Autolock _l(mLock);
- layer_state_t* s = getLayerStateLocked(client, id);
- if (!s)
- return BAD_INDEX;
+ layer_state_t* s = getLayerStateLocked(sc);
+ if (!s) {
+ mStatus = BAD_INDEX;
+ return *this;
+ }
s->what |= layer_state_t::eMatrixChanged;
layer_state_t::matrix22_t matrix;
matrix.dsdx = dsdx;
@@ -425,93 +331,115 @@
matrix.dsdy = dsdy;
matrix.dtdy = dtdy;
s->matrix = matrix;
- return NO_ERROR;
+ return *this;
}
-status_t Composer::setCrop(const sp<SurfaceComposerClient>& client,
- const sp<IBinder>& id, const Rect& crop) {
- Mutex::Autolock _l(mLock);
- layer_state_t* s = getLayerStateLocked(client, id);
- if (!s)
- return BAD_INDEX;
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setCrop(
+ const sp<SurfaceControl>& sc, const Rect& crop) {
+ layer_state_t* s = getLayerStateLocked(sc);
+ if (!s) {
+ mStatus = BAD_INDEX;
+ return *this;
+ }
s->what |= layer_state_t::eCropChanged;
s->crop = crop;
- return NO_ERROR;
+ return *this;
}
-status_t Composer::setFinalCrop(const sp<SurfaceComposerClient>& client,
- const sp<IBinder>& id, const Rect& crop) {
- Mutex::Autolock _l(mLock);
- layer_state_t* s = getLayerStateLocked(client, id);
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFinalCrop(const sp<SurfaceControl>& sc, const Rect& crop) {
+ layer_state_t* s = getLayerStateLocked(sc);
if (!s) {
- return BAD_INDEX;
+ mStatus = BAD_INDEX;
+ return *this;
}
s->what |= layer_state_t::eFinalCropChanged;
s->finalCrop = crop;
- return NO_ERROR;
+ return *this;
}
-status_t Composer::deferTransactionUntil(
- const sp<SurfaceComposerClient>& client, const sp<IBinder>& id,
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::deferTransactionUntil(
+ const sp<SurfaceControl>& sc,
const sp<IBinder>& handle, uint64_t frameNumber) {
- Mutex::Autolock lock(mLock);
- layer_state_t* s = getLayerStateLocked(client, id);
+ layer_state_t* s = getLayerStateLocked(sc);
if (!s) {
- return BAD_INDEX;
+ mStatus = BAD_INDEX;
+ return *this;
}
s->what |= layer_state_t::eDeferTransaction;
s->barrierHandle = handle;
s->frameNumber = frameNumber;
- return NO_ERROR;
+ return *this;
}
-status_t Composer::deferTransactionUntil(
- const sp<SurfaceComposerClient>& client, const sp<IBinder>& id,
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::deferTransactionUntil(
+ const sp<SurfaceControl>& sc,
const sp<Surface>& barrierSurface, uint64_t frameNumber) {
- Mutex::Autolock lock(mLock);
- layer_state_t* s = getLayerStateLocked(client, id);
+ layer_state_t* s = getLayerStateLocked(sc);
if (!s) {
- return BAD_INDEX;
+ mStatus = BAD_INDEX;
+ return *this;
}
s->what |= layer_state_t::eDeferTransaction;
s->barrierGbp = barrierSurface->getIGraphicBufferProducer();
s->frameNumber = frameNumber;
- return NO_ERROR;
+ return *this;
}
-status_t Composer::reparentChildren(
- const sp<SurfaceComposerClient>& client,
- const sp<IBinder>& id,
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::reparentChildren(
+ const sp<SurfaceControl>& sc,
const sp<IBinder>& newParentHandle) {
- Mutex::Autolock lock(mLock);
- layer_state_t* s = getLayerStateLocked(client, id);
+ layer_state_t* s = getLayerStateLocked(sc);
if (!s) {
- return BAD_INDEX;
+ mStatus = BAD_INDEX;
+ return *this;
}
s->what |= layer_state_t::eReparentChildren;
s->reparentHandle = newParentHandle;
- return NO_ERROR;
+ return *this;
}
-status_t Composer::detachChildren(
- const sp<SurfaceComposerClient>& client,
- const sp<IBinder>& id) {
- Mutex::Autolock lock(mLock);
- layer_state_t* s = getLayerStateLocked(client, id);
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::reparent(
+ const sp<SurfaceControl>& sc,
+ const sp<IBinder>& newParentHandle) {
+ layer_state_t* s = getLayerStateLocked(sc);
if (!s) {
- return BAD_INDEX;
+ mStatus = BAD_INDEX;
+ return *this;
+ }
+ s->what |= layer_state_t::eReparent;
+ s->parentHandleForChild = newParentHandle;
+ return *this;
+}
+
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setColor(
+ const sp<SurfaceControl>& sc,
+ const half3& color) {
+ layer_state_t* s = getLayerStateLocked(sc);
+ if (!s) {
+ mStatus = BAD_INDEX;
+ return *this;
+ }
+ s->what |= layer_state_t::eColorChanged;
+ s->color = color;
+ return *this;
+}
+
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::detachChildren(
+ const sp<SurfaceControl>& sc) {
+ layer_state_t* s = getLayerStateLocked(sc);
+ if (!s) {
+ mStatus = BAD_INDEX;
}
s->what |= layer_state_t::eDetachChildren;
- return NO_ERROR;
+ return *this;
}
-status_t Composer::setOverrideScalingMode(
- const sp<SurfaceComposerClient>& client,
- const sp<IBinder>& id, int32_t overrideScalingMode) {
- Mutex::Autolock lock(mLock);
- layer_state_t* s = getLayerStateLocked(client, id);
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setOverrideScalingMode(
+ const sp<SurfaceControl>& sc, int32_t overrideScalingMode) {
+ layer_state_t* s = getLayerStateLocked(sc);
if (!s) {
- return BAD_INDEX;
+ mStatus = BAD_INDEX;
+ return *this;
}
switch (overrideScalingMode) {
@@ -524,29 +452,29 @@
default:
ALOGE("unknown scaling mode: %d",
overrideScalingMode);
- return BAD_VALUE;
+ mStatus = BAD_VALUE;
+ return *this;
}
s->what |= layer_state_t::eOverrideScalingModeChanged;
s->overrideScalingMode = overrideScalingMode;
- return NO_ERROR;
+ return *this;
}
-status_t Composer::setGeometryAppliesWithResize(
- const sp<SurfaceComposerClient>& client,
- const sp<IBinder>& id) {
- Mutex::Autolock lock(mLock);
- layer_state_t* s = getLayerStateLocked(client, id);
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setGeometryAppliesWithResize(
+ const sp<SurfaceControl>& sc) {
+ layer_state_t* s = getLayerStateLocked(sc);
if (!s) {
- return BAD_INDEX;
+ mStatus = BAD_INDEX;
+ return *this;
}
s->what |= layer_state_t::eGeometryAppliesWithResize;
- return NO_ERROR;
+ return *this;
}
// ---------------------------------------------------------------------------
-DisplayState& Composer::getDisplayStateLocked(const sp<IBinder>& token) {
+DisplayState& SurfaceComposerClient::Transaction::getDisplayStateLocked(const sp<IBinder>& token) {
DisplayState s;
s.token = token;
ssize_t index = mDisplayStates.indexOf(s);
@@ -558,8 +486,8 @@
return mDisplayStates.editItemAt(static_cast<size_t>(index));
}
-status_t Composer::setDisplaySurface(const sp<IBinder>& token,
- sp<IGraphicBufferProducer> bufferProducer) {
+status_t SurfaceComposerClient::Transaction::setDisplaySurface(const sp<IBinder>& token,
+ const sp<IGraphicBufferProducer>& bufferProducer) {
if (bufferProducer.get() != nullptr) {
// Make sure that composition can never be stalled by a virtual display
// consumer that isn't processing buffers fast enough.
@@ -571,26 +499,23 @@
return err;
}
}
- Mutex::Autolock _l(mLock);
DisplayState& s(getDisplayStateLocked(token));
s.surface = bufferProducer;
s.what |= DisplayState::eSurfaceChanged;
return NO_ERROR;
}
-void Composer::setDisplayLayerStack(const sp<IBinder>& token,
+void SurfaceComposerClient::Transaction::setDisplayLayerStack(const sp<IBinder>& token,
uint32_t layerStack) {
- Mutex::Autolock _l(mLock);
DisplayState& s(getDisplayStateLocked(token));
s.layerStack = layerStack;
s.what |= DisplayState::eLayerStackChanged;
}
-void Composer::setDisplayProjection(const sp<IBinder>& token,
+void SurfaceComposerClient::Transaction::setDisplayProjection(const sp<IBinder>& token,
uint32_t orientation,
const Rect& layerStackRect,
const Rect& displayRect) {
- Mutex::Autolock _l(mLock);
DisplayState& s(getDisplayStateLocked(token));
s.orientation = orientation;
s.viewport = layerStackRect;
@@ -599,8 +524,7 @@
mForceSynchronous = true; // TODO: do we actually still need this?
}
-void Composer::setDisplaySize(const sp<IBinder>& token, uint32_t width, uint32_t height) {
- Mutex::Autolock _l(mLock);
+void SurfaceComposerClient::Transaction::setDisplaySize(const sp<IBinder>& token, uint32_t width, uint32_t height) {
DisplayState& s(getDisplayStateLocked(token));
s.width = width;
s.height = height;
@@ -610,22 +534,22 @@
// ---------------------------------------------------------------------------
SurfaceComposerClient::SurfaceComposerClient()
- : mStatus(NO_INIT), mComposer(Composer::getInstance())
+ : mStatus(NO_INIT)
{
}
SurfaceComposerClient::SurfaceComposerClient(const sp<IGraphicBufferProducer>& root)
- : mStatus(NO_INIT), mComposer(Composer::getInstance()), mParent(root)
+ : mStatus(NO_INIT), mParent(root)
{
}
void SurfaceComposerClient::onFirstRef() {
- sp<ISurfaceComposer> sm(ComposerService::getComposerService());
- if (sm != 0) {
+ sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+ if (sf != 0) {
auto rootProducer = mParent.promote();
sp<ISurfaceComposerClient> conn;
- conn = (rootProducer != nullptr) ? sm->createScopedConnection(rootProducer) :
- sm->createConnection();
+ conn = (rootProducer != nullptr) ? sf->createScopedConnection(rootProducer) :
+ sf->createConnection();
if (conn != 0) {
mClient = conn;
mStatus = NO_ERROR;
@@ -648,8 +572,8 @@
status_t SurfaceComposerClient::linkToComposerDeath(
const sp<IBinder::DeathRecipient>& recipient,
void* cookie, uint32_t flags) {
- sp<ISurfaceComposer> sm(ComposerService::getComposerService());
- return IInterface::asBinder(sm)->linkToDeath(recipient, cookie, flags);
+ sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+ return IInterface::asBinder(sf)->linkToDeath(recipient, cookie, flags);
}
void SurfaceComposerClient::dispose() {
@@ -692,19 +616,6 @@
return sur;
}
-sp<IBinder> SurfaceComposerClient::createDisplay(const String8& displayName,
- bool secure) {
- return Composer::getInstance().createDisplay(displayName, secure);
-}
-
-void SurfaceComposerClient::destroyDisplay(const sp<IBinder>& display) {
- Composer::getInstance().destroyDisplay(display);
-}
-
-sp<IBinder> SurfaceComposerClient::getBuiltInDisplay(int32_t id) {
- return Composer::getInstance().getBuiltInDisplay(id);
-}
-
status_t SurfaceComposerClient::destroySurface(const sp<IBinder>& sid) {
if (mStatus != NO_ERROR)
return mStatus;
@@ -727,152 +638,18 @@
return mClient->getLayerFrameStats(token, outStats);
}
-inline Composer& SurfaceComposerClient::getComposer() {
- return mComposer;
-}
-
// ----------------------------------------------------------------------------
-void SurfaceComposerClient::openGlobalTransaction() {
- Composer::openGlobalTransaction();
-}
-
-void SurfaceComposerClient::closeGlobalTransaction(bool synchronous) {
- Composer::closeGlobalTransaction(synchronous);
-}
-
-void SurfaceComposerClient::setAnimationTransaction() {
- Composer::setAnimationTransaction();
-}
-
status_t SurfaceComposerClient::enableVSyncInjections(bool enable) {
- return Composer::enableVSyncInjections(enable);
+ sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+ return sf->enableVSyncInjections(enable);
}
status_t SurfaceComposerClient::injectVSync(nsecs_t when) {
- return Composer::injectVSync(when);
+ sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+ return sf->injectVSync(when);
}
-// ----------------------------------------------------------------------------
-
-status_t SurfaceComposerClient::setCrop(const sp<IBinder>& id, const Rect& crop) {
- return getComposer().setCrop(this, id, crop);
-}
-
-status_t SurfaceComposerClient::setFinalCrop(const sp<IBinder>& id,
- const Rect& crop) {
- return getComposer().setFinalCrop(this, id, crop);
-}
-
-status_t SurfaceComposerClient::setPosition(const sp<IBinder>& id, float x, float y) {
- return getComposer().setPosition(this, id, x, y);
-}
-
-status_t SurfaceComposerClient::setSize(const sp<IBinder>& id, uint32_t w, uint32_t h) {
- return getComposer().setSize(this, id, w, h);
-}
-
-status_t SurfaceComposerClient::setLayer(const sp<IBinder>& id, int32_t z) {
- return getComposer().setLayer(this, id, z);
-}
-
-status_t SurfaceComposerClient::setRelativeLayer(const sp<IBinder>& id,
- const sp<IBinder>& relativeTo, int32_t z) {
- return getComposer().setRelativeLayer(this, id, relativeTo, z);
-}
-
-status_t SurfaceComposerClient::hide(const sp<IBinder>& id) {
- return getComposer().setFlags(this, id,
- layer_state_t::eLayerHidden,
- layer_state_t::eLayerHidden);
-}
-
-status_t SurfaceComposerClient::show(const sp<IBinder>& id) {
- return getComposer().setFlags(this, id,
- 0,
- layer_state_t::eLayerHidden);
-}
-
-status_t SurfaceComposerClient::setFlags(const sp<IBinder>& id, uint32_t flags,
- uint32_t mask) {
- return getComposer().setFlags(this, id, flags, mask);
-}
-
-status_t SurfaceComposerClient::setTransparentRegionHint(const sp<IBinder>& id,
- const Region& transparentRegion) {
- return getComposer().setTransparentRegionHint(this, id, transparentRegion);
-}
-
-status_t SurfaceComposerClient::setAlpha(const sp<IBinder>& id, float alpha) {
- return getComposer().setAlpha(this, id, alpha);
-}
-
-status_t SurfaceComposerClient::setLayerStack(const sp<IBinder>& id, uint32_t layerStack) {
- return getComposer().setLayerStack(this, id, layerStack);
-}
-
-status_t SurfaceComposerClient::setMatrix(const sp<IBinder>& id, float dsdx, float dtdx,
- float dtdy, float dsdy) {
- return getComposer().setMatrix(this, id, dsdx, dtdx, dtdy, dsdy);
-}
-
-status_t SurfaceComposerClient::deferTransactionUntil(const sp<IBinder>& id,
- const sp<IBinder>& handle, uint64_t frameNumber) {
- return getComposer().deferTransactionUntil(this, id, handle, frameNumber);
-}
-
-status_t SurfaceComposerClient::deferTransactionUntil(const sp<IBinder>& id,
- const sp<Surface>& barrierSurface, uint64_t frameNumber) {
- return getComposer().deferTransactionUntil(this, id, barrierSurface, frameNumber);
-}
-
-status_t SurfaceComposerClient::reparentChildren(const sp<IBinder>& id,
- const sp<IBinder>& newParentHandle) {
- return getComposer().reparentChildren(this, id, newParentHandle);
-}
-
-status_t SurfaceComposerClient::detachChildren(const sp<IBinder>& id) {
- return getComposer().detachChildren(this, id);
-}
-
-status_t SurfaceComposerClient::setOverrideScalingMode(
- const sp<IBinder>& id, int32_t overrideScalingMode) {
- return getComposer().setOverrideScalingMode(
- this, id, overrideScalingMode);
-}
-
-status_t SurfaceComposerClient::setGeometryAppliesWithResize(
- const sp<IBinder>& id) {
- return getComposer().setGeometryAppliesWithResize(this, id);
-}
-
-// ----------------------------------------------------------------------------
-
-status_t SurfaceComposerClient::setDisplaySurface(const sp<IBinder>& token,
- sp<IGraphicBufferProducer> bufferProducer) {
- return Composer::getInstance().setDisplaySurface(token, bufferProducer);
-}
-
-void SurfaceComposerClient::setDisplayLayerStack(const sp<IBinder>& token,
- uint32_t layerStack) {
- Composer::getInstance().setDisplayLayerStack(token, layerStack);
-}
-
-void SurfaceComposerClient::setDisplayProjection(const sp<IBinder>& token,
- uint32_t orientation,
- const Rect& layerStackRect,
- const Rect& displayRect) {
- Composer::getInstance().setDisplayProjection(token, orientation,
- layerStackRect, displayRect);
-}
-
-void SurfaceComposerClient::setDisplaySize(const sp<IBinder>& token,
- uint32_t width, uint32_t height) {
- Composer::getInstance().setDisplaySize(token, width, height);
-}
-
-// ----------------------------------------------------------------------------
-
status_t SurfaceComposerClient::getDisplayConfigs(
const sp<IBinder>& display, Vector<DisplayInfo>* configs)
{
@@ -978,6 +755,15 @@
return ret;
}
+status_t ScreenshotClient::captureLayers(const sp<IBinder>& layerHandle,
+ const sp<IGraphicBufferProducer>& producer,
+ uint32_t rotation) {
+ sp<ISurfaceComposer> s(ComposerService::getComposerService());
+ if (s == NULL) return NO_INIT;
+ return s->captureLayers(layerHandle, producer,
+ static_cast<ISurfaceComposer::Rotation>(rotation));
+}
+
ScreenshotClient::ScreenshotClient()
: mHaveBuffer(false) {
memset(&mBuffer, 0, sizeof(mBuffer));
@@ -1080,5 +866,9 @@
return mBuffer.stride * mBuffer.height * bytesPerPixel(mBuffer.format);
}
+android_dataspace ScreenshotClient::getDataSpace() const {
+ return mBuffer.dataSpace;
+}
+
// ----------------------------------------------------------------------------
}; // namespace android
diff --git a/libs/gui/SurfaceControl.cpp b/libs/gui/SurfaceControl.cpp
index bf8a815..f6a2b8f 100644
--- a/libs/gui/SurfaceControl.cpp
+++ b/libs/gui/SurfaceControl.cpp
@@ -97,112 +97,6 @@
return lhs->mHandle == rhs->mHandle;
}
-status_t SurfaceControl::setLayerStack(uint32_t layerStack) {
- status_t err = validate();
- if (err < 0) return err;
- return mClient->setLayerStack(mHandle, layerStack);
-}
-
-status_t SurfaceControl::setLayer(int32_t layer) {
- status_t err = validate();
- if (err < 0) return err;
- return mClient->setLayer(mHandle, layer);
-}
-
-status_t SurfaceControl::setRelativeLayer(const sp<IBinder>& relativeTo, int32_t layer) {
- status_t err = validate();
- if (err < 0) return err;
- return mClient->setRelativeLayer(mHandle, relativeTo, layer);
-}
-
-status_t SurfaceControl::setPosition(float x, float y) {
- status_t err = validate();
- if (err < 0) return err;
- return mClient->setPosition(mHandle, x, y);
-}
-status_t SurfaceControl::setGeometryAppliesWithResize() {
- status_t err = validate();
- if (err < 0) return err;
- return mClient->setGeometryAppliesWithResize(mHandle);
-}
-status_t SurfaceControl::setSize(uint32_t w, uint32_t h) {
- status_t err = validate();
- if (err < 0) return err;
- return mClient->setSize(mHandle, w, h);
-}
-status_t SurfaceControl::hide() {
- status_t err = validate();
- if (err < 0) return err;
- return mClient->hide(mHandle);
-}
-status_t SurfaceControl::show() {
- status_t err = validate();
- if (err < 0) return err;
- return mClient->show(mHandle);
-}
-status_t SurfaceControl::setFlags(uint32_t flags, uint32_t mask) {
- status_t err = validate();
- if (err < 0) return err;
- return mClient->setFlags(mHandle, flags, mask);
-}
-status_t SurfaceControl::setTransparentRegionHint(const Region& transparent) {
- status_t err = validate();
- if (err < 0) return err;
- return mClient->setTransparentRegionHint(mHandle, transparent);
-}
-status_t SurfaceControl::setAlpha(float alpha) {
- status_t err = validate();
- if (err < 0) return err;
- return mClient->setAlpha(mHandle, alpha);
-}
-status_t SurfaceControl::setMatrix(float dsdx, float dtdx, float dtdy, float dsdy) {
- status_t err = validate();
- if (err < 0) return err;
- return mClient->setMatrix(mHandle, dsdx, dtdx, dtdy, dsdy);
-}
-status_t SurfaceControl::setCrop(const Rect& crop) {
- status_t err = validate();
- if (err < 0) return err;
- return mClient->setCrop(mHandle, crop);
-}
-status_t SurfaceControl::setFinalCrop(const Rect& crop) {
- status_t err = validate();
- if (err < 0) return err;
- return mClient->setFinalCrop(mHandle, crop);
-}
-
-status_t SurfaceControl::deferTransactionUntil(const sp<IBinder>& handle,
- uint64_t frameNumber) {
- status_t err = validate();
- if (err < 0) return err;
- return mClient->deferTransactionUntil(mHandle, handle, frameNumber);
-}
-
-status_t SurfaceControl::deferTransactionUntil(const sp<Surface>& handle,
- uint64_t frameNumber) {
- status_t err = validate();
- if (err < 0) return err;
- return mClient->deferTransactionUntil(mHandle, handle, frameNumber);
-}
-
-status_t SurfaceControl::reparentChildren(const sp<IBinder>& newParentHandle) {
- status_t err = validate();
- if (err < 0) return err;
- return mClient->reparentChildren(mHandle, newParentHandle);
-}
-
-status_t SurfaceControl::detachChildren() {
- status_t err = validate();
- if (err < 0) return err;
- return mClient->detachChildren(mHandle);
-}
-
-status_t SurfaceControl::setOverrideScalingMode(int32_t overrideScalingMode) {
- status_t err = validate();
- if (err < 0) return err;
- return mClient->setOverrideScalingMode(mHandle, overrideScalingMode);
-}
-
status_t SurfaceControl::clearLayerFrameStats() const {
status_t err = validate();
if (err < 0) return err;
@@ -237,22 +131,40 @@
return parcel->writeStrongBinder(IInterface::asBinder(bp));
}
+sp<Surface> SurfaceControl::generateSurfaceLocked() const
+{
+ // This surface is always consumed by SurfaceFlinger, so the
+ // producerControlledByApp value doesn't matter; using false.
+ mSurfaceData = new Surface(mGraphicBufferProducer, false);
+
+ return mSurfaceData;
+}
+
sp<Surface> SurfaceControl::getSurface() const
{
Mutex::Autolock _l(mLock);
if (mSurfaceData == 0) {
- // This surface is always consumed by SurfaceFlinger, so the
- // producerControlledByApp value doesn't matter; using false.
- mSurfaceData = new Surface(mGraphicBufferProducer, false);
+ return generateSurfaceLocked();
}
return mSurfaceData;
}
+sp<Surface> SurfaceControl::createSurface() const
+{
+ Mutex::Autolock _l(mLock);
+ return generateSurfaceLocked();
+}
+
sp<IBinder> SurfaceControl::getHandle() const
{
Mutex::Autolock lock(mLock);
return mHandle;
}
+sp<SurfaceComposerClient> SurfaceControl::getClient() const
+{
+ return mClient;
+}
+
// ----------------------------------------------------------------------------
}; // namespace android
diff --git a/libs/gui/SyncFeatures.cpp b/libs/gui/SyncFeatures.cpp
index 187b211..afa15c5 100644
--- a/libs/gui/SyncFeatures.cpp
+++ b/libs/gui/SyncFeatures.cpp
@@ -27,7 +27,7 @@
#include <private/gui/SyncFeatures.h>
-EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name);
+extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name);
namespace android {
diff --git a/libs/gui/bufferqueue/1.0/H2BGraphicBufferProducer.cpp b/libs/gui/bufferqueue/1.0/H2BGraphicBufferProducer.cpp
index fda5b94..3b89291 100644
--- a/libs/gui/bufferqueue/1.0/H2BGraphicBufferProducer.cpp
+++ b/libs/gui/bufferqueue/1.0/H2BGraphicBufferProducer.cpp
@@ -21,6 +21,8 @@
#include <gui/bufferqueue/1.0/H2BGraphicBufferProducer.h>
#include <gui/bufferqueue/1.0/B2HProducerListener.h>
+#include <system/window.h>
+
namespace android {
namespace hardware {
namespace graphics {
@@ -125,7 +127,7 @@
t->attr.stride = l.getStride();
t->attr.format = static_cast<PixelFormat>(l.getPixelFormat());
t->attr.layerCount = l.getLayerCount();
- t->attr.usage = l.getUsage();
+ t->attr.usage = uint32_t(l.getUsage()); // FIXME: need 64-bits usage version
t->attr.id = l.getId();
t->attr.generationNumber = l.getGenerationNumber();
t->nativeHandle = hidl_handle(l.handle);
@@ -988,14 +990,15 @@
return toStatusT(mBase->setAsyncMode(async));
}
-status_t H2BGraphicBufferProducer::dequeueBuffer(
- int* slot, sp<Fence>* fence,
- uint32_t w, uint32_t h, ::android::PixelFormat format,
- uint32_t usage, FrameEventHistoryDelta* outTimestamps) {
+// FIXME: usage bits truncated -- needs a 64-bits usage version
+status_t H2BGraphicBufferProducer::dequeueBuffer(int* slot, sp<Fence>* fence, uint32_t w,
+ uint32_t h, ::android::PixelFormat format,
+ uint64_t usage, uint64_t* outBufferAge,
+ FrameEventHistoryDelta* outTimestamps) {
*fence = new Fence();
status_t fnStatus;
status_t transStatus = toStatusT(mBase->dequeueBuffer(
- w, h, static_cast<PixelFormat>(format), usage,
+ w, h, static_cast<PixelFormat>(format), uint32_t(usage),
outTimestamps != nullptr,
[&fnStatus, slot, fence, outTimestamps] (
Status status,
@@ -1015,6 +1018,10 @@
fnStatus = fnStatus == NO_ERROR ? BAD_VALUE : fnStatus;
}
}));
+ if (outBufferAge) {
+ // Since the HAL version doesn't return the buffer age, set it to 0:
+ *outBufferAge = 0;
+ }
return transStatus == NO_ERROR ? fnStatus : transStatus;
}
@@ -1144,10 +1151,11 @@
return toStatusT(mBase->setSidebandStream(stream == nullptr ? nullptr : stream->handle()));
}
+// FIXME: usage bits truncated -- needs a 64-bits usage version
void H2BGraphicBufferProducer::allocateBuffers(uint32_t width, uint32_t height,
- ::android::PixelFormat format, uint32_t usage) {
+ ::android::PixelFormat format, uint64_t usage) {
mBase->allocateBuffers(
- width, height, static_cast<PixelFormat>(format), usage);
+ width, height, static_cast<PixelFormat>(format), uint32_t(usage));
}
status_t H2BGraphicBufferProducer::allowAllocation(bool allow) {
@@ -1226,6 +1234,18 @@
return transStatus == NO_ERROR ? fnStatus : transStatus;
}
+status_t H2BGraphicBufferProducer::getConsumerUsage(uint64_t* outUsage) const {
+ ALOGW("getConsumerUsage is not fully supported");
+ int result;
+ status_t transStatus = toStatusT(mBase->query(
+ NATIVE_WINDOW_CONSUMER_USAGE_BITS,
+ [&result, outUsage] (int32_t tResult, int32_t tValue) {
+ result = static_cast<int>(tResult);
+ *outUsage = static_cast<uint64_t>(tValue);
+ }));
+ return transStatus == NO_ERROR ? result : static_cast<int>(transStatus);
+}
+
} // namespace utils
} // namespace V1_0
} // namespace bufferqueue
diff --git a/include/gui/BufferItem.h b/libs/gui/include/gui/BufferItem.h
similarity index 100%
rename from include/gui/BufferItem.h
rename to libs/gui/include/gui/BufferItem.h
diff --git a/include/gui/BufferItemConsumer.h b/libs/gui/include/gui/BufferItemConsumer.h
similarity index 98%
rename from include/gui/BufferItemConsumer.h
rename to libs/gui/include/gui/BufferItemConsumer.h
index 217fe6a..d9c5775 100644
--- a/include/gui/BufferItemConsumer.h
+++ b/libs/gui/include/gui/BufferItemConsumer.h
@@ -52,7 +52,7 @@
// controlledByApp tells whether this consumer is controlled by the
// application.
BufferItemConsumer(const sp<IGraphicBufferConsumer>& consumer,
- uint32_t consumerUsage, int bufferCount = DEFAULT_MAX_BUFFERS,
+ uint64_t consumerUsage, int bufferCount = DEFAULT_MAX_BUFFERS,
bool controlledByApp = false);
~BufferItemConsumer() override;
diff --git a/include/gui/BufferQueue.h b/libs/gui/include/gui/BufferQueue.h
similarity index 100%
rename from include/gui/BufferQueue.h
rename to libs/gui/include/gui/BufferQueue.h
diff --git a/include/gui/BufferQueueConsumer.h b/libs/gui/include/gui/BufferQueueConsumer.h
similarity index 97%
rename from include/gui/BufferQueueConsumer.h
rename to libs/gui/include/gui/BufferQueueConsumer.h
index f194bdf..d108120 100644
--- a/include/gui/BufferQueueConsumer.h
+++ b/libs/gui/include/gui/BufferQueueConsumer.h
@@ -121,13 +121,12 @@
// GraphicBuffers of a defaultDataSpace if no data space is specified
// in queueBuffer.
// The initial default is HAL_DATASPACE_UNKNOWN
- virtual status_t setDefaultBufferDataSpace(
- android_dataspace defaultDataSpace);
+ virtual status_t setDefaultBufferDataSpace(android_dataspace defaultDataSpace);
// setConsumerUsageBits will turn on additional usage bits for dequeueBuffer.
// These are merged with the bits passed to dequeueBuffer. The values are
// enumerated in gralloc.h, e.g. GRALLOC_USAGE_HW_RENDER; the default is 0.
- virtual status_t setConsumerUsageBits(uint32_t usage);
+ virtual status_t setConsumerUsageBits(uint64_t usage) override;
// setConsumerIsProtected will turn on an internal bit that indicates whether
// the consumer can handle protected gralloc buffers (i.e. with
diff --git a/include/gui/BufferQueueCore.h b/libs/gui/include/gui/BufferQueueCore.h
similarity index 99%
rename from include/gui/BufferQueueCore.h
rename to libs/gui/include/gui/BufferQueueCore.h
index dd8b992..537c957 100644
--- a/include/gui/BufferQueueCore.h
+++ b/libs/gui/include/gui/BufferQueueCore.h
@@ -170,7 +170,7 @@
// mConsumerUsageBits contains flags that the consumer wants for
// GraphicBuffers.
- uint32_t mConsumerUsageBits;
+ uint64_t mConsumerUsageBits;
// mConsumerIsProtected indicates the consumer is ready to handle protected
// buffer.
diff --git a/include/gui/BufferQueueDefs.h b/libs/gui/include/gui/BufferQueueDefs.h
similarity index 100%
rename from include/gui/BufferQueueDefs.h
rename to libs/gui/include/gui/BufferQueueDefs.h
diff --git a/include/gui/BufferQueueProducer.h b/libs/gui/include/gui/BufferQueueProducer.h
similarity index 95%
rename from include/gui/BufferQueueProducer.h
rename to libs/gui/include/gui/BufferQueueProducer.h
index 87bc800..5c7ffb4 100644
--- a/include/gui/BufferQueueProducer.h
+++ b/libs/gui/include/gui/BufferQueueProducer.h
@@ -80,9 +80,10 @@
//
// In both cases, the producer will need to call requestBuffer to get a
// GraphicBuffer handle for the returned slot.
- status_t dequeueBuffer(int *outSlot, sp<Fence>* outFence,
- uint32_t width, uint32_t height, PixelFormat format,
- uint32_t usage, FrameEventHistoryDelta* outTimestamps) override;
+ virtual status_t dequeueBuffer(int* outSlot, sp<Fence>* outFence, uint32_t width,
+ uint32_t height, PixelFormat format, uint64_t usage,
+ uint64_t* outBufferAge,
+ FrameEventHistoryDelta* outTimestamps) override;
// See IGraphicBufferProducer::detachBuffer
virtual status_t detachBuffer(int slot);
@@ -152,7 +153,7 @@
// See IGraphicBufferProducer::allocateBuffers
virtual void allocateBuffers(uint32_t width, uint32_t height,
- PixelFormat format, uint32_t usage);
+ PixelFormat format, uint64_t usage) override;
// See IGraphicBufferProducer::allowAllocation
virtual status_t allowAllocation(bool allow);
@@ -182,6 +183,9 @@
// See IGraphicBufferProducer::getUniqueId
virtual status_t getUniqueId(uint64_t* outId) const override;
+ // See IGraphicBufferProducer::getConsumerUsage
+ virtual status_t getConsumerUsage(uint64_t* outUsage) const override;
+
private:
// This is required by the IBinder::DeathRecipient interface
virtual void binderDied(const wp<IBinder>& who);
diff --git a/include/gui/BufferSlot.h b/libs/gui/include/gui/BufferSlot.h
similarity index 100%
rename from include/gui/BufferSlot.h
rename to libs/gui/include/gui/BufferSlot.h
diff --git a/include/gui/ConsumerBase.h b/libs/gui/include/gui/ConsumerBase.h
similarity index 98%
rename from include/gui/ConsumerBase.h
rename to libs/gui/include/gui/ConsumerBase.h
index d1a9b04..e9fc8fd 100644
--- a/include/gui/ConsumerBase.h
+++ b/libs/gui/include/gui/ConsumerBase.h
@@ -241,7 +241,9 @@
// mFrameAvailableListener is the listener object that will be called when a
// new frame becomes available. If it is not NULL it will be called from
- // queueBuffer.
+ // queueBuffer. The listener object is protected by mFrameAvailableMutex
+ // (not mMutex).
+ Mutex mFrameAvailableMutex;
wp<FrameAvailableListener> mFrameAvailableListener;
// The ConsumerBase has-a BufferQueue and is responsible for creating this object
diff --git a/include/gui/CpuConsumer.h b/libs/gui/include/gui/CpuConsumer.h
similarity index 100%
rename from include/gui/CpuConsumer.h
rename to libs/gui/include/gui/CpuConsumer.h
diff --git a/include/gui/DisplayEventReceiver.h b/libs/gui/include/gui/DisplayEventReceiver.h
similarity index 96%
rename from include/gui/DisplayEventReceiver.h
rename to libs/gui/include/gui/DisplayEventReceiver.h
index 9557b4f..32ce59a 100644
--- a/include/gui/DisplayEventReceiver.h
+++ b/libs/gui/include/gui/DisplayEventReceiver.h
@@ -25,6 +25,7 @@
#include <utils/Timers.h>
#include <binder/IInterface.h>
+#include <gui/ISurfaceComposer.h>
// ----------------------------------------------------------------------------
@@ -83,7 +84,8 @@
* or requestNextVsync to receive them.
* Other events start being delivered immediately.
*/
- DisplayEventReceiver();
+ DisplayEventReceiver(
+ ISurfaceComposer::VsyncSource vsyncSource = ISurfaceComposer::eVsyncSourceApp);
/*
* ~DisplayEventReceiver severs the connection with SurfaceFlinger, new events
diff --git a/include/gui/FrameTimestamps.h b/libs/gui/include/gui/FrameTimestamps.h
similarity index 100%
rename from include/gui/FrameTimestamps.h
rename to libs/gui/include/gui/FrameTimestamps.h
diff --git a/include/gui/GLConsumer.h b/libs/gui/include/gui/GLConsumer.h
similarity index 99%
rename from include/gui/GLConsumer.h
rename to libs/gui/include/gui/GLConsumer.h
index 2cf6162..75f2cca 100644
--- a/include/gui/GLConsumer.h
+++ b/libs/gui/include/gui/GLConsumer.h
@@ -210,7 +210,7 @@
// so the refactoring can proceed smoothly
status_t setDefaultBufferFormat(PixelFormat defaultFormat);
status_t setDefaultBufferDataSpace(android_dataspace defaultDataSpace);
- status_t setConsumerUsageBits(uint32_t usage);
+ status_t setConsumerUsageBits(uint64_t usage);
status_t setTransformHint(uint32_t hint);
status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers);
@@ -386,7 +386,7 @@
// BufferQueue instance; these will be OR:d with any additional flags passed
// from the GLConsumer user. In particular, GLConsumer will always
// consume buffers as hardware textures.
- static const uint32_t DEFAULT_USAGE_FLAGS = GraphicBuffer::USAGE_HW_TEXTURE;
+ static const uint64_t DEFAULT_USAGE_FLAGS = GraphicBuffer::USAGE_HW_TEXTURE;
// mCurrentTextureImage is the EglImage/buffer of the current texture. It's
// possible that this buffer is not associated with any buffer slot, so we
diff --git a/include/gui/GuiConfig.h b/libs/gui/include/gui/GuiConfig.h
similarity index 100%
rename from include/gui/GuiConfig.h
rename to libs/gui/include/gui/GuiConfig.h
diff --git a/include/gui/IConsumerListener.h b/libs/gui/include/gui/IConsumerListener.h
similarity index 100%
rename from include/gui/IConsumerListener.h
rename to libs/gui/include/gui/IConsumerListener.h
diff --git a/include/gui/IDisplayEventConnection.h b/libs/gui/include/gui/IDisplayEventConnection.h
similarity index 100%
rename from include/gui/IDisplayEventConnection.h
rename to libs/gui/include/gui/IDisplayEventConnection.h
diff --git a/include/gui/IGraphicBufferConsumer.h b/libs/gui/include/gui/IGraphicBufferConsumer.h
similarity index 98%
rename from include/gui/IGraphicBufferConsumer.h
rename to libs/gui/include/gui/IGraphicBufferConsumer.h
index 57cce16..9fb7580 100644
--- a/include/gui/IGraphicBufferConsumer.h
+++ b/libs/gui/include/gui/IGraphicBufferConsumer.h
@@ -241,7 +241,7 @@
// e.g. GRALLOC_USAGE_HW_RENDER; the default is 0.
//
// Return of a value other than NO_ERROR means an unknown error has occurred.
- virtual status_t setConsumerUsageBits(uint32_t usage) = 0;
+ virtual status_t setConsumerUsageBits(uint64_t usage) = 0;
// setConsumerIsProtected will turn on an internal bit that indicates whether
// the consumer can handle protected gralloc buffers (i.e. with
@@ -267,6 +267,8 @@
// discardFreeBuffers releases all currently-free buffers held by the BufferQueue, in order to
// reduce the memory consumption of the BufferQueue to the minimum possible without
// discarding data.
+ // The consumer invoking this method is responsible for calling getReleasedBuffers() after this
+ // call to free up any of its locally cached buffers.
virtual status_t discardFreeBuffers() = 0;
// dump state into a string
diff --git a/include/gui/IGraphicBufferProducer.h b/libs/gui/include/gui/IGraphicBufferProducer.h
similarity index 97%
rename from include/gui/IGraphicBufferProducer.h
rename to libs/gui/include/gui/IGraphicBufferProducer.h
index 9250806..039dc0d 100644
--- a/include/gui/IGraphicBufferProducer.h
+++ b/libs/gui/include/gui/IGraphicBufferProducer.h
@@ -194,9 +194,9 @@
//
// All other negative values are an unknown error returned downstream
// from the graphics allocator (typically errno).
- virtual status_t dequeueBuffer(int* slot, sp<Fence>* fence, uint32_t w,
- uint32_t h, PixelFormat format, uint32_t usage,
- FrameEventHistoryDelta* outTimestamps) = 0;
+ virtual status_t dequeueBuffer(int* slot, sp<Fence>* fence, uint32_t w, uint32_t h,
+ PixelFormat format, uint64_t usage, uint64_t* outBufferAge,
+ FrameEventHistoryDelta* outTimestamps) = 0;
// detachBuffer attempts to remove all ownership of the buffer in the given
// slot from the buffer queue. If this call succeeds, the slot will be
@@ -517,7 +517,7 @@
// dequeueBuffer. If there are already the maximum number of buffers
// allocated, this function has no effect.
virtual void allocateBuffers(uint32_t width, uint32_t height,
- PixelFormat format, uint32_t usage) = 0;
+ PixelFormat format, uint64_t usage) = 0;
// Sets whether dequeueBuffer is allowed to allocate new buffers.
//
@@ -593,6 +593,12 @@
// Returns a unique id for this BufferQueue
virtual status_t getUniqueId(uint64_t* outId) const = 0;
+
+ // Returns the consumer usage flags for this BufferQueue. This returns the
+ // full 64-bit usage flags, rather than the truncated 32-bit usage flags
+ // returned by querying the now deprecated
+ // NATIVE_WINDOW_CONSUMER_USAGE_BITS attribute.
+ virtual status_t getConsumerUsage(uint64_t* outUsage) const = 0;
};
// ----------------------------------------------------------------------------
diff --git a/include/gui/IProducerListener.h b/libs/gui/include/gui/IProducerListener.h
similarity index 100%
rename from include/gui/IProducerListener.h
rename to libs/gui/include/gui/IProducerListener.h
diff --git a/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
similarity index 91%
rename from include/gui/ISurfaceComposer.h
rename to libs/gui/include/gui/ISurfaceComposer.h
index 1112973..13e7473 100644
--- a/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -39,6 +39,7 @@
struct DisplayState;
struct DisplayInfo;
struct DisplayStatInfo;
+class LayerDebugInfo;
class HdrCapabilities;
class IDisplayEventConnection;
class IGraphicBufferProducer;
@@ -72,6 +73,11 @@
eRotate270 = 3
};
+ enum VsyncSource {
+ eVsyncSourceApp = 0,
+ eVsyncSourceSurfaceFlinger = 1
+ };
+
/* create connection with surface flinger, requires
* ACCESS_SURFACE_FLINGER permission
*/
@@ -89,7 +95,8 @@
const sp<IGraphicBufferProducer>& parent) = 0;
/* return an IDisplayEventConnection */
- virtual sp<IDisplayEventConnection> createDisplayEventConnection() = 0;
+ virtual sp<IDisplayEventConnection> createDisplayEventConnection(
+ VsyncSource vsyncSource = eVsyncSourceApp) = 0;
/* create a virtual display
* requires ACCESS_SURFACE_FLINGER permission.
@@ -167,6 +174,10 @@
bool useIdentityTransform,
Rotation rotation = eRotateNone) = 0;
+ virtual status_t captureLayers(const sp<IBinder>& layerHandleBinder,
+ const sp<IGraphicBufferProducer>& producer,
+ Rotation rotation = eRotateNone) = 0;
+
/* Clears the frame statistics for animations.
*
* Requires the ACCESS_SURFACE_FLINGER permission.
@@ -189,6 +200,12 @@
virtual status_t enableVSyncInjections(bool enable) = 0;
virtual status_t injectVSync(nsecs_t when) = 0;
+
+ /* Gets the list of active layers in Z order for debugging purposes
+ *
+ * Requires the ACCESS_SURFACE_FLINGER permission.
+ */
+ virtual status_t getLayerDebugInfo(std::vector<LayerDebugInfo>* outLayers) const = 0;
};
// ----------------------------------------------------------------------------
@@ -213,6 +230,7 @@
SET_ACTIVE_CONFIG,
CONNECT_DISPLAY,
CAPTURE_SCREEN,
+ CAPTURE_LAYERS,
CLEAR_ANIMATION_FRAME_STATS,
GET_ANIMATION_FRAME_STATS,
SET_POWER_MODE,
@@ -223,6 +241,7 @@
SET_ACTIVE_COLOR_MODE,
ENABLE_VSYNC_INJECTIONS,
INJECT_VSYNC,
+ GET_LAYER_DEBUG_INFO,
CREATE_SCOPED_CONNECTION
};
diff --git a/include/gui/ISurfaceComposerClient.h b/libs/gui/include/gui/ISurfaceComposerClient.h
similarity index 98%
rename from include/gui/ISurfaceComposerClient.h
rename to libs/gui/include/gui/ISurfaceComposerClient.h
index 2c613ea..d5bbef2 100644
--- a/include/gui/ISurfaceComposerClient.h
+++ b/libs/gui/include/gui/ISurfaceComposerClient.h
@@ -41,7 +41,7 @@
eCursorWindow = 0x00002000,
eFXSurfaceNormal = 0x00000000,
- eFXSurfaceDim = 0x00020000,
+ eFXSurfaceColor = 0x00020000,
eFXSurfaceMask = 0x000F0000,
};
diff --git a/libs/gui/include/gui/LayerDebugInfo.h b/libs/gui/include/gui/LayerDebugInfo.h
new file mode 100644
index 0000000..92bd8c5
--- /dev/null
+++ b/libs/gui/include/gui/LayerDebugInfo.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 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 <binder/Parcelable.h>
+
+#include <ui/PixelFormat.h>
+#include <ui/Region.h>
+
+#include <string>
+#include <math/vec4.h>
+
+namespace android {
+
+/* Class for transporting debug info from SurfaceFlinger to authorized
+ * recipients. The class is intended to be a data container. There are
+ * no getters or setters.
+ */
+class LayerDebugInfo : public Parcelable {
+public:
+ LayerDebugInfo() = default;
+ LayerDebugInfo(const LayerDebugInfo&) = default;
+ virtual ~LayerDebugInfo() = default;
+
+ virtual status_t writeToParcel(Parcel* parcel) const;
+ virtual status_t readFromParcel(const Parcel* parcel);
+
+ std::string mName = std::string("NOT FILLED");
+ std::string mParentName = std::string("NOT FILLED");
+ std::string mType = std::string("NOT FILLED");
+ Region mTransparentRegion = Region::INVALID_REGION;
+ Region mVisibleRegion = Region::INVALID_REGION;
+ Region mSurfaceDamageRegion = Region::INVALID_REGION;
+ uint32_t mLayerStack = 0;
+ float mX = 0.f;
+ float mY = 0.f;
+ uint32_t mZ = 0 ;
+ int32_t mWidth = -1;
+ int32_t mHeight = -1;
+ Rect mCrop = Rect::INVALID_RECT;
+ Rect mFinalCrop = Rect::INVALID_RECT;
+ half4 mColor = half4(1.0_hf, 1.0_hf, 1.0_hf, 0.0_hf);
+ uint32_t mFlags = 0;
+ PixelFormat mPixelFormat = PIXEL_FORMAT_NONE;
+ android_dataspace mDataSpace = HAL_DATASPACE_UNKNOWN;
+ // Row-major transform matrix (SurfaceControl::setMatrix())
+ float mMatrix[2][2] = {{0.f, 0.f}, {0.f, 0.f}};
+ int32_t mActiveBufferWidth = -1;
+ int32_t mActiveBufferHeight = -1;
+ int32_t mActiveBufferStride = 0;
+ PixelFormat mActiveBufferFormat = PIXEL_FORMAT_NONE;
+ int32_t mNumQueuedFrames = -1;
+ bool mRefreshPending = false;
+ bool mIsOpaque = false;
+ bool mContentDirty = false;
+};
+
+std::string to_string(const LayerDebugInfo& info);
+
+} // namespace android
diff --git a/include/private/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
similarity index 85%
rename from include/private/gui/LayerState.h
rename to libs/gui/include/gui/LayerState.h
index 307c764..f3fb82f 100644
--- a/include/private/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -25,6 +25,7 @@
#include <ui/Region.h>
#include <ui/Rect.h>
#include <gui/IGraphicBufferProducer.h>
+#include <math/vec3.h>
namespace android {
@@ -59,7 +60,9 @@
eGeometryAppliesWithResize = 0x00001000,
eReparentChildren = 0x00002000,
eDetachChildren = 0x00004000,
- eRelativeLayerChanged = 0x00008000
+ eRelativeLayerChanged = 0x00008000,
+ eReparent = 0x00010000,
+ eColorChanged = 0x00020000
};
layer_state_t()
@@ -74,6 +77,7 @@
matrix.dsdy = matrix.dtdx = 0.0f;
}
+ void merge(const layer_state_t& other);
status_t write(Parcel& output) const;
status_t read(const Parcel& input);
@@ -107,6 +111,10 @@
sp<IBinder> relativeLayerHandle;
+ sp<IBinder> parentHandleForChild;
+
+ half3 color;
+
// non POD must be last. see write/read
Region transparentRegion;
};
@@ -137,6 +145,7 @@
};
DisplayState();
+ void merge(const DisplayState& other);
uint32_t what;
sp<IBinder> token;
@@ -150,6 +159,20 @@
status_t read(const Parcel& input);
};
+static inline
+int compare_type(const ComposerState& lhs, const ComposerState& rhs) {
+ if (lhs.client < rhs.client) return -1;
+ if (lhs.client > rhs.client) return 1;
+ if (lhs.state.surface < rhs.state.surface) return -1;
+ if (lhs.state.surface > rhs.state.surface) return 1;
+ return 0;
+}
+
+static inline
+int compare_type(const DisplayState& lhs, const DisplayState& rhs) {
+ return compare_type(lhs.token, rhs.token);
+}
+
}; // namespace android
#endif // ANDROID_SF_LAYER_STATE_H
diff --git a/include/gui/OccupancyTracker.h b/libs/gui/include/gui/OccupancyTracker.h
similarity index 100%
rename from include/gui/OccupancyTracker.h
rename to libs/gui/include/gui/OccupancyTracker.h
diff --git a/include/gui/StreamSplitter.h b/libs/gui/include/gui/StreamSplitter.h
similarity index 100%
rename from include/gui/StreamSplitter.h
rename to libs/gui/include/gui/StreamSplitter.h
diff --git a/include/gui/Surface.h b/libs/gui/include/gui/Surface.h
similarity index 96%
rename from include/gui/Surface.h
rename to libs/gui/include/gui/Surface.h
index c8c6e99..3fe29d9 100644
--- a/include/gui/Surface.h
+++ b/libs/gui/include/gui/Surface.h
@@ -159,6 +159,10 @@
status_t getHdrSupport(bool* supported);
status_t getUniqueId(uint64_t* outId) const;
+ status_t getConsumerUsage(uint64_t* outUsage) const;
+
+ // Returns the CLOCK_MONOTONIC start time of the last dequeueBuffer call
+ nsecs_t getLastDequeueStartTime() const;
protected:
virtual ~Surface();
@@ -204,8 +208,8 @@
int dispatchSetBuffersStickyTransform(va_list args);
int dispatchSetBuffersTimestamp(va_list args);
int dispatchSetCrop(va_list args);
- int dispatchSetPostTransformCrop(va_list args);
int dispatchSetUsage(va_list args);
+ int dispatchSetUsage64(va_list args);
int dispatchLock(va_list args);
int dispatchUnlockAndPost(va_list args);
int dispatchSetSidebandStream(va_list args);
@@ -220,6 +224,7 @@
int dispatchGetFrameTimestamps(va_list args);
int dispatchGetWideColorSupport(va_list args);
int dispatchGetHdrSupport(va_list args);
+ int dispatchGetConsumerUsage64(va_list args);
protected:
virtual int dequeueBuffer(ANativeWindowBuffer** buffer, int* fenceFd);
@@ -239,7 +244,7 @@
virtual int setBuffersTimestamp(int64_t timestamp);
virtual int setBuffersDataSpace(android_dataspace dataSpace);
virtual int setCrop(Rect const* rect);
- virtual int setUsage(uint32_t reqUsage);
+ virtual int setUsage(uint64_t reqUsage);
virtual void setSurfaceDamage(android_native_rect_t* rects, size_t numRects);
public:
@@ -276,6 +281,8 @@
// detachNextBuffer, or attachBuffer call.
status_t getAndFlushRemovedBuffers(std::vector<sp<GraphicBuffer>>* out);
+ android_dataspace_t getBuffersDataSpace();
+
protected:
enum { NUM_BUFFER_SLOTS = BufferQueueDefs::NUM_BUFFER_SLOTS };
enum { DEFAULT_FORMAT = PIXEL_FORMAT_RGBA_8888 };
@@ -318,7 +325,7 @@
// mReqUsage is the set of buffer usage flags that will be requested
// at the next deuque operation. It is initialized to 0.
- uint32_t mReqUsage;
+ uint64_t mReqUsage;
// mTimestamp is the timestamp that will be used for the next buffer queue
// operation. It defaults to NATIVE_WINDOW_TIMESTAMP_AUTO, which means that
@@ -400,6 +407,10 @@
// (the change since the previous frame) passed in by the producer.
Region mDirtyRegion;
+ // mBufferAge tracks the age of the contents of the most recently dequeued
+ // buffer as the number of frames that have elapsed since it was last queued
+ uint64_t mBufferAge;
+
// Stores the current generation number. See setGenerationNumber and
// IGraphicBufferProducer::setGenerationNumber for more information.
uint32_t mGenerationNumber;
@@ -421,6 +432,9 @@
nsecs_t mLastDequeueDuration = 0;
nsecs_t mLastQueueDuration = 0;
+ // Stores the time right before we call IGBP::dequeueBuffer
+ nsecs_t mLastDequeueStartTime = 0;
+
Condition mQueueBufferCondition;
uint64_t mNextFrameNumber = 1;
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
new file mode 100644
index 0000000..87fdfae
--- /dev/null
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -0,0 +1,351 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_GUI_SURFACE_COMPOSER_CLIENT_H
+#define ANDROID_GUI_SURFACE_COMPOSER_CLIENT_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <binder/IBinder.h>
+
+#include <utils/RefBase.h>
+#include <utils/Singleton.h>
+#include <utils/SortedVector.h>
+#include <utils/threads.h>
+
+#include <ui/FrameStats.h>
+#include <ui/PixelFormat.h>
+
+#include <gui/CpuConsumer.h>
+#include <gui/SurfaceControl.h>
+#include <math/vec3.h>
+#include <gui/LayerState.h>
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+struct DisplayInfo;
+class HdrCapabilities;
+class ISurfaceComposerClient;
+class IGraphicBufferProducer;
+class Region;
+
+// ---------------------------------------------------------------------------
+
+class SurfaceComposerClient : public RefBase
+{
+ friend class Composer;
+public:
+ SurfaceComposerClient();
+ SurfaceComposerClient(const sp<IGraphicBufferProducer>& parent);
+ virtual ~SurfaceComposerClient();
+
+ // Always make sure we could initialize
+ status_t initCheck() const;
+
+ // Return the connection of this client
+ sp<IBinder> connection() const;
+
+ // Forcibly remove connection before all references have gone away.
+ void dispose();
+
+ // callback when the composer is dies
+ status_t linkToComposerDeath(const sp<IBinder::DeathRecipient>& recipient,
+ void* cookie = NULL, uint32_t flags = 0);
+
+ // Get a list of supported configurations for a given display
+ static status_t getDisplayConfigs(const sp<IBinder>& display,
+ Vector<DisplayInfo>* configs);
+
+ // Get the DisplayInfo for the currently-active configuration
+ static status_t getDisplayInfo(const sp<IBinder>& display,
+ DisplayInfo* info);
+
+ // Get the index of the current active configuration (relative to the list
+ // returned by getDisplayInfo)
+ static int getActiveConfig(const sp<IBinder>& display);
+
+ // Set a new active configuration using an index relative to the list
+ // returned by getDisplayInfo
+ static status_t setActiveConfig(const sp<IBinder>& display, int id);
+
+ // Gets the list of supported color modes for the given display
+ static status_t getDisplayColorModes(const sp<IBinder>& display,
+ Vector<android_color_mode_t>* outColorModes);
+
+ // Gets the active color mode for the given display
+ static android_color_mode_t getActiveColorMode(const sp<IBinder>& display);
+
+ // Sets the active color mode for the given display
+ static status_t setActiveColorMode(const sp<IBinder>& display, android_color_mode_t colorMode);
+
+ /* Triggers screen on/off or low power mode and waits for it to complete */
+ static void setDisplayPowerMode(const sp<IBinder>& display, int mode);
+
+ // ------------------------------------------------------------------------
+ // surface creation / destruction
+
+ //! Create a surface
+ sp<SurfaceControl> createSurface(
+ const String8& name,// name of the surface
+ uint32_t w, // width in pixel
+ uint32_t h, // height in pixel
+ PixelFormat format, // pixel-format desired
+ uint32_t flags = 0, // usage flags
+ SurfaceControl* parent = nullptr, // parent
+ uint32_t windowType = 0, // from WindowManager.java (STATUS_BAR, INPUT_METHOD, etc.)
+ uint32_t ownerUid = 0 // UID of the task
+ );
+
+ //! Create a virtual display
+ static sp<IBinder> createDisplay(const String8& displayName, bool secure);
+
+ //! Destroy a virtual display
+ static void destroyDisplay(const sp<IBinder>& display);
+
+ //! Get the token for the existing default displays.
+ //! Possible values for id are eDisplayIdMain and eDisplayIdHdmi.
+ static sp<IBinder> getBuiltInDisplay(int32_t id);
+
+ static status_t enableVSyncInjections(bool enable);
+
+ static status_t injectVSync(nsecs_t when);
+
+ class Transaction {
+ SortedVector<ComposerState> mComposerStates;
+ SortedVector<DisplayState > mDisplayStates;
+ uint32_t mForceSynchronous = 0;
+ uint32_t mTransactionNestCount = 0;
+ bool mAnimation = false;
+
+ int mStatus = NO_ERROR;
+
+ layer_state_t* getLayerStateLocked(const sp<SurfaceControl>& sc);
+ DisplayState& getDisplayStateLocked(const sp<IBinder>& token);
+
+ public:
+ Transaction() = default;
+ virtual ~Transaction() = default;
+ Transaction(Transaction const& other);
+
+ status_t apply(bool synchronous = false);
+ // Merge another transaction in to this one, clearing other
+ // as if it had been applied.
+ Transaction& merge(Transaction&& other);
+ Transaction& show(const sp<SurfaceControl>& sc);
+ Transaction& hide(const sp<SurfaceControl>& sc);
+ Transaction& setPosition(const sp<SurfaceControl>& sc,
+ float x, float y);
+ Transaction& setSize(const sp<SurfaceControl>& sc,
+ uint32_t w, uint32_t h);
+ Transaction& setLayer(const sp<SurfaceControl>& sc,
+ int32_t z);
+
+ // Sets a Z order relative to the Surface specified by "relativeTo" but
+ // without becoming a full child of the relative. Z-ordering works exactly
+ // as if it were a child however.
+ //
+ // As a nod to sanity, only non-child surfaces may have a relative Z-order.
+ //
+ // This overrides any previous call and is overriden by any future calls
+ // to setLayer.
+ //
+ // If the relative is removed, the Surface will have no layer and be
+ // invisible, until the next time set(Relative)Layer is called.
+ Transaction& setRelativeLayer(const sp<SurfaceControl>& sc,
+ const sp<IBinder>& relativeTo, int32_t z);
+ Transaction& setFlags(const sp<SurfaceControl>& sc,
+ uint32_t flags, uint32_t mask);
+ Transaction& setTransparentRegionHint(const sp<SurfaceControl>& sc,
+ const Region& transparentRegion);
+ Transaction& setAlpha(const sp<SurfaceControl>& sc,
+ float alpha);
+ Transaction& setMatrix(const sp<SurfaceControl>& sc,
+ float dsdx, float dtdx, float dtdy, float dsdy);
+ Transaction& setCrop(const sp<SurfaceControl>& sc, const Rect& crop);
+ Transaction& setFinalCrop(const sp<SurfaceControl>& sc, const Rect& crop);
+ Transaction& setLayerStack(const sp<SurfaceControl>& sc, uint32_t layerStack);
+ // Defers applying any changes made in this transaction until the Layer
+ // identified by handle reaches the given frameNumber. If the Layer identified
+ // by handle is removed, then we will apply this transaction regardless of
+ // what frame number has been reached.
+ Transaction& deferTransactionUntil(const sp<SurfaceControl>& sc,
+ const sp<IBinder>& handle,
+ uint64_t frameNumber);
+ // A variant of deferTransactionUntil which identifies the Layer we wait for by
+ // Surface instead of Handle. Useful for clients which may not have the
+ // SurfaceControl for some of their Surfaces. Otherwise behaves identically.
+ Transaction& deferTransactionUntil(const sp<SurfaceControl>& sc,
+ const sp<Surface>& barrierSurface,
+ uint64_t frameNumber);
+ // Reparents all children of this layer to the new parent handle.
+ Transaction& reparentChildren(const sp<SurfaceControl>& sc,
+ const sp<IBinder>& newParentHandle);
+
+ /// Reparents the current layer to the new parent handle. The new parent must not be null.
+ // This can be used instead of reparentChildren if the caller wants to
+ // only re-parent a specific child.
+ Transaction& reparent(const sp<SurfaceControl>& sc,
+ const sp<IBinder>& newParentHandle);
+
+ Transaction& setColor(const sp<SurfaceControl>& sc, const half3& color);
+
+ // Detaches all child surfaces (and their children recursively)
+ // from their SurfaceControl.
+ // The child SurfaceControls will not throw exceptions or return errors,
+ // but transactions will have no effect.
+ // The child surfaces will continue to follow their parent surfaces,
+ // and remain eligible for rendering, but their relative state will be
+ // frozen. We use this in the WindowManager, in app shutdown/relaunch
+ // scenarios, where the app would otherwise clean up its child Surfaces.
+ // Sometimes the WindowManager needs to extend their lifetime slightly
+ // in order to perform an exit animation or prevent flicker.
+ Transaction& detachChildren(const sp<SurfaceControl>& sc);
+ // Set an override scaling mode as documented in <system/window.h>
+ // the override scaling mode will take precedence over any client
+ // specified scaling mode. -1 will clear the override scaling mode.
+ Transaction& setOverrideScalingMode(const sp<SurfaceControl>& sc,
+ int32_t overrideScalingMode);
+
+ // If the size changes in this transaction, all geometry updates specified
+ // in this transaction will not complete until a buffer of the new size
+ // arrives. As some elements normally apply immediately, this enables
+ // freezing the total geometry of a surface until a resize is completed.
+ Transaction& setGeometryAppliesWithResize(const sp<SurfaceControl>& sc);
+
+ status_t setDisplaySurface(const sp<IBinder>& token,
+ const sp<IGraphicBufferProducer>& bufferProducer);
+
+ void setDisplayLayerStack(const sp<IBinder>& token, uint32_t layerStack);
+
+ /* setDisplayProjection() defines the projection of layer stacks
+ * to a given display.
+ *
+ * - orientation defines the display's orientation.
+ * - layerStackRect defines which area of the window manager coordinate
+ * space will be used.
+ * - displayRect defines where on the display will layerStackRect be
+ * mapped to. displayRect is specified post-orientation, that is
+ * it uses the orientation seen by the end-user.
+ */
+ void setDisplayProjection(const sp<IBinder>& token,
+ uint32_t orientation,
+ const Rect& layerStackRect,
+ const Rect& displayRect);
+ void setDisplaySize(const sp<IBinder>& token, uint32_t width, uint32_t height);
+ void setAnimationTransaction();
+ };
+
+ status_t destroySurface(const sp<IBinder>& id);
+
+ status_t clearLayerFrameStats(const sp<IBinder>& token) const;
+ status_t getLayerFrameStats(const sp<IBinder>& token, FrameStats* outStats) const;
+ static status_t clearAnimationFrameStats();
+ static status_t getAnimationFrameStats(FrameStats* outStats);
+
+ static status_t getHdrCapabilities(const sp<IBinder>& display,
+ HdrCapabilities* outCapabilities);
+
+ static void setDisplayProjection(const sp<IBinder>& token,
+ uint32_t orientation,
+ const Rect& layerStackRect,
+ const Rect& displayRect);
+
+ inline sp<ISurfaceComposerClient> getClient() { return mClient; }
+
+private:
+ virtual void onFirstRef();
+
+ mutable Mutex mLock;
+ status_t mStatus;
+ sp<ISurfaceComposerClient> mClient;
+ wp<IGraphicBufferProducer> mParent;
+};
+
+// ---------------------------------------------------------------------------
+
+class ScreenshotClient
+{
+public:
+ // if cropping isn't required, callers may pass in a default Rect, e.g.:
+ // capture(display, producer, Rect(), reqWidth, ...);
+ static status_t capture(
+ const sp<IBinder>& display,
+ const sp<IGraphicBufferProducer>& producer,
+ Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
+ int32_t minLayerZ, int32_t maxLayerZ,
+ bool useIdentityTransform);
+ static status_t captureToBuffer(
+ const sp<IBinder>& display,
+ Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
+ int32_t minLayerZ, int32_t maxLayerZ,
+ bool useIdentityTransform,
+ uint32_t rotation,
+ sp<GraphicBuffer>* outbuffer);
+ static status_t captureLayers(const sp<IBinder>& layerHandle,
+ const sp<IGraphicBufferProducer>& producer, uint32_t rotation);
+
+private:
+ mutable sp<CpuConsumer> mCpuConsumer;
+ mutable sp<IGraphicBufferProducer> mProducer;
+ CpuConsumer::LockedBuffer mBuffer;
+ bool mHaveBuffer;
+
+public:
+ ScreenshotClient();
+ ~ScreenshotClient();
+
+ // frees the previous screenshot and captures a new one
+ // if cropping isn't required, callers may pass in a default Rect, e.g.:
+ // update(display, Rect(), useIdentityTransform);
+ status_t update(const sp<IBinder>& display,
+ Rect sourceCrop, bool useIdentityTransform);
+ status_t update(const sp<IBinder>& display,
+ Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
+ bool useIdentityTransform);
+ status_t update(const sp<IBinder>& display,
+ Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
+ int32_t minLayerZ, int32_t maxLayerZ,
+ bool useIdentityTransform);
+ status_t update(const sp<IBinder>& display,
+ Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
+ int32_t minLayerZ, int32_t maxLayerZ,
+ bool useIdentityTransform, uint32_t rotation);
+
+ sp<CpuConsumer> getCpuConsumer() const;
+
+ // release memory occupied by the screenshot
+ void release();
+
+ // pixels are valid until this object is freed or
+ // release() or update() is called
+ void const* getPixels() const;
+
+ uint32_t getWidth() const;
+ uint32_t getHeight() const;
+ PixelFormat getFormat() const;
+ uint32_t getStride() const;
+ // size of allocated memory in bytes
+ size_t getSize() const;
+ android_dataspace getDataSpace() const;
+};
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_GUI_SURFACE_COMPOSER_CLIENT_H
diff --git a/libs/gui/include/gui/SurfaceControl.h b/libs/gui/include/gui/SurfaceControl.h
new file mode 100644
index 0000000..384815d
--- /dev/null
+++ b/libs/gui/include/gui/SurfaceControl.h
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_GUI_SURFACE_CONTROL_H
+#define ANDROID_GUI_SURFACE_CONTROL_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/KeyedVector.h>
+#include <utils/RefBase.h>
+#include <utils/threads.h>
+
+#include <ui/FrameStats.h>
+#include <ui/PixelFormat.h>
+#include <ui/Region.h>
+
+#include <gui/ISurfaceComposerClient.h>
+#include <math/vec3.h>
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+class IGraphicBufferProducer;
+class Surface;
+class SurfaceComposerClient;
+
+// ---------------------------------------------------------------------------
+
+class SurfaceControl : public RefBase
+{
+public:
+ static bool isValid(const sp<SurfaceControl>& surface) {
+ return (surface != 0) && surface->isValid();
+ }
+
+ bool isValid() {
+ return mHandle!=0 && mClient!=0;
+ }
+
+ static bool isSameSurface(
+ const sp<SurfaceControl>& lhs, const sp<SurfaceControl>& rhs);
+
+ // release surface data from java
+ void clear();
+
+ // disconnect any api that's connected
+ void disconnect();
+
+ static status_t writeSurfaceToParcel(
+ const sp<SurfaceControl>& control, Parcel* parcel);
+
+ sp<Surface> getSurface() const;
+ sp<Surface> createSurface() const;
+ sp<IBinder> getHandle() const;
+
+ status_t clearLayerFrameStats() const;
+ status_t getLayerFrameStats(FrameStats* outStats) const;
+
+ sp<SurfaceComposerClient> getClient() const;
+
+private:
+ // can't be copied
+ SurfaceControl& operator = (SurfaceControl& rhs);
+ SurfaceControl(const SurfaceControl& rhs);
+
+ friend class SurfaceComposerClient;
+ friend class Surface;
+
+ SurfaceControl(
+ const sp<SurfaceComposerClient>& client,
+ const sp<IBinder>& handle,
+ const sp<IGraphicBufferProducer>& gbp);
+
+ ~SurfaceControl();
+
+ sp<Surface> generateSurfaceLocked() const;
+ status_t validate() const;
+ void destroy();
+
+ sp<SurfaceComposerClient> mClient;
+ sp<IBinder> mHandle;
+ sp<IGraphicBufferProducer> mGraphicBufferProducer;
+ mutable Mutex mLock;
+ mutable sp<Surface> mSurfaceData;
+};
+
+}; // namespace android
+
+#endif // ANDROID_GUI_SURFACE_CONTROL_H
diff --git a/include/gui/bufferqueue/1.0/B2HProducerListener.h b/libs/gui/include/gui/bufferqueue/1.0/B2HProducerListener.h
similarity index 100%
rename from include/gui/bufferqueue/1.0/B2HProducerListener.h
rename to libs/gui/include/gui/bufferqueue/1.0/B2HProducerListener.h
diff --git a/include/gui/bufferqueue/1.0/H2BGraphicBufferProducer.h b/libs/gui/include/gui/bufferqueue/1.0/H2BGraphicBufferProducer.h
similarity index 92%
rename from include/gui/bufferqueue/1.0/H2BGraphicBufferProducer.h
rename to libs/gui/include/gui/bufferqueue/1.0/H2BGraphicBufferProducer.h
index 93c452a..74850b4 100644
--- a/include/gui/bufferqueue/1.0/H2BGraphicBufferProducer.h
+++ b/libs/gui/include/gui/bufferqueue/1.0/H2BGraphicBufferProducer.h
@@ -64,9 +64,9 @@
status_t requestBuffer(int slot, sp<GraphicBuffer>* buf) override;
status_t setMaxDequeuedBufferCount(int maxDequeuedBuffers) override;
status_t setAsyncMode(bool async) override;
- status_t dequeueBuffer(int* slot, sp<Fence>* fence, uint32_t w,
- uint32_t h, ::android::PixelFormat format, uint32_t usage,
- FrameEventHistoryDelta* outTimestamps) override;
+ status_t dequeueBuffer(int* slot, sp<Fence>* fence, uint32_t w, uint32_t h,
+ ::android::PixelFormat format, uint64_t usage, uint64_t* outBufferAge,
+ FrameEventHistoryDelta* outTimestamps) override;
status_t detachBuffer(int slot) override;
status_t detachNextBuffer(sp<GraphicBuffer>* outBuffer, sp<Fence>* outFence)
override;
@@ -83,7 +83,7 @@
override;
status_t setSidebandStream(const sp<NativeHandle>& stream) override;
void allocateBuffers(uint32_t width, uint32_t height,
- ::android::PixelFormat format, uint32_t usage) override;
+ ::android::PixelFormat format, uint64_t usage) override;
status_t allowAllocation(bool allow) override;
status_t setGenerationNumber(uint32_t generationNumber) override;
String8 getConsumerName() const override;
@@ -94,6 +94,7 @@
sp<Fence>* outFence, float outTransformMatrix[16]) override;
void getFrameTimestamps(FrameEventHistoryDelta* outDelta) override;
status_t getUniqueId(uint64_t* outId) const override;
+ status_t getConsumerUsage(uint64_t* outUsage) const override;
};
} // namespace utils
diff --git a/include/gui/view/Surface.h b/libs/gui/include/gui/view/Surface.h
similarity index 100%
rename from include/gui/view/Surface.h
rename to libs/gui/include/gui/view/Surface.h
diff --git a/include/private/gui/ComposerService.h b/libs/gui/include/private/gui/ComposerService.h
similarity index 100%
rename from include/private/gui/ComposerService.h
rename to libs/gui/include/private/gui/ComposerService.h
diff --git a/include/private/gui/SyncFeatures.h b/libs/gui/include/private/gui/SyncFeatures.h
similarity index 100%
rename from include/private/gui/SyncFeatures.h
rename to libs/gui/include/private/gui/SyncFeatures.h
diff --git a/libs/gui/tests/Android.bp b/libs/gui/tests/Android.bp
index fa87f29a..908959c 100644
--- a/libs/gui/tests/Android.bp
+++ b/libs/gui/tests/Android.bp
@@ -7,6 +7,10 @@
test_suites: ["device-tests"],
clang: true,
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
srcs: [
"BufferItemConsumer_test.cpp",
diff --git a/libs/gui/tests/BufferItemConsumer_test.cpp b/libs/gui/tests/BufferItemConsumer_test.cpp
index d64e530..b87cbbd 100644
--- a/libs/gui/tests/BufferItemConsumer_test.cpp
+++ b/libs/gui/tests/BufferItemConsumer_test.cpp
@@ -76,8 +76,8 @@
int slot;
sp<Fence> outFence;
- status_t ret = mProducer->dequeueBuffer(&slot, &outFence, kWidth,
- kHeight, 0, 0, nullptr);
+ status_t ret = mProducer->dequeueBuffer(&slot, &outFence, kWidth, kHeight, 0, 0,
+ nullptr, nullptr);
ASSERT_GE(ret, 0);
ALOGV("dequeueBuffer: slot=%d", slot);
diff --git a/libs/gui/tests/BufferQueue_test.cpp b/libs/gui/tests/BufferQueue_test.cpp
index 4220aaf..9a20859 100644
--- a/libs/gui/tests/BufferQueue_test.cpp
+++ b/libs/gui/tests/BufferQueue_test.cpp
@@ -144,8 +144,8 @@
sp<Fence> fence;
sp<GraphicBuffer> buffer;
ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
- mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0,
- GRALLOC_USAGE_SW_WRITE_OFTEN, nullptr));
+ mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, GRALLOC_USAGE_SW_WRITE_OFTEN,
+ nullptr, nullptr));
ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buffer));
uint32_t* dataIn;
@@ -188,16 +188,16 @@
for (int i = 0; i < 2; i++) {
ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
- mProducer->dequeueBuffer(&slot, &fence, 1, 1, 0,
- GRALLOC_USAGE_SW_READ_OFTEN, nullptr));
+ mProducer->dequeueBuffer(&slot, &fence, 1, 1, 0, GRALLOC_USAGE_SW_READ_OFTEN,
+ nullptr, nullptr));
ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buf));
ASSERT_EQ(OK, mProducer->queueBuffer(slot, qbi, &qbo));
ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0));
}
ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
- mProducer->dequeueBuffer(&slot, &fence, 1, 1, 0,
- GRALLOC_USAGE_SW_READ_OFTEN, nullptr));
+ mProducer->dequeueBuffer(&slot, &fence, 1, 1, 0, GRALLOC_USAGE_SW_READ_OFTEN,
+ nullptr, nullptr));
ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buf));
ASSERT_EQ(OK, mProducer->queueBuffer(slot, qbi, &qbo));
@@ -239,8 +239,8 @@
EXPECT_EQ(OK, mConsumer->setMaxAcquiredBufferCount(3));
for (int i = 0; i < 3; i++) {
ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
- mProducer->dequeueBuffer(&slot, &fence, 1, 1, 0,
- GRALLOC_USAGE_SW_READ_OFTEN, nullptr));
+ mProducer->dequeueBuffer(&slot, &fence, 1, 1, 0, GRALLOC_USAGE_SW_READ_OFTEN,
+ nullptr, nullptr));
ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buf));
ASSERT_EQ(OK, mProducer->queueBuffer(slot, qbi, &qbo));
ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0));
@@ -275,8 +275,8 @@
BufferItem item;
ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
- mProducer->dequeueBuffer(&slot, &fence, 1, 1, 0,
- GRALLOC_USAGE_SW_READ_OFTEN, nullptr));
+ mProducer->dequeueBuffer(&slot, &fence, 1, 1, 0, GRALLOC_USAGE_SW_READ_OFTEN,
+ nullptr, nullptr));
ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buf));
ASSERT_EQ(OK, mProducer->queueBuffer(slot, qbi, &qbo));
ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0));
@@ -285,8 +285,8 @@
for (int i = 0; i < 2; i++) {
ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
- mProducer->dequeueBuffer(&slot, &fence, 1, 1, 0,
- GRALLOC_USAGE_SW_READ_OFTEN, nullptr));
+ mProducer->dequeueBuffer(&slot, &fence, 1, 1, 0, GRALLOC_USAGE_SW_READ_OFTEN,
+ nullptr, nullptr));
ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buf));
ASSERT_EQ(OK, mProducer->queueBuffer(slot, qbi, &qbo));
ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0));
@@ -335,8 +335,8 @@
sp<Fence> fence;
sp<GraphicBuffer> buffer;
ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
- mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0,
- GRALLOC_USAGE_SW_WRITE_OFTEN, nullptr));
+ mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, GRALLOC_USAGE_SW_WRITE_OFTEN,
+ nullptr, nullptr));
ASSERT_EQ(BAD_VALUE, mProducer->detachBuffer(slot)); // Not requested
ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buffer));
ASSERT_EQ(OK, mProducer->detachBuffer(slot));
@@ -384,8 +384,8 @@
sp<Fence> fence;
sp<GraphicBuffer> buffer;
ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
- mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0,
- GRALLOC_USAGE_SW_WRITE_OFTEN, nullptr));
+ mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, GRALLOC_USAGE_SW_WRITE_OFTEN,
+ nullptr, nullptr));
ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buffer));
IGraphicBufferProducer::QueueBufferInput input(0, false,
HAL_DATASPACE_UNKNOWN, Rect(0, 0, 1, 1),
@@ -420,8 +420,8 @@
EGL_NO_SYNC_KHR, Fence::NO_FENCE));
ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
- mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0,
- GRALLOC_USAGE_SW_WRITE_OFTEN, nullptr));
+ mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, GRALLOC_USAGE_SW_WRITE_OFTEN,
+ nullptr, nullptr));
ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buffer));
uint32_t* dataOut;
@@ -443,8 +443,8 @@
sp<Fence> fence;
sp<GraphicBuffer> buffer;
ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
- mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0,
- GRALLOC_USAGE_SW_WRITE_OFTEN, nullptr));
+ mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, GRALLOC_USAGE_SW_WRITE_OFTEN,
+ nullptr, nullptr));
ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buffer));
uint32_t* dataIn;
@@ -492,22 +492,24 @@
sp<GraphicBuffer> buffer;
// This should return an error since it would require an allocation
ASSERT_EQ(OK, mProducer->allowAllocation(false));
- ASSERT_EQ(WOULD_BLOCK, mProducer->dequeueBuffer(&slot, &fence, 0, 0,
- 0, GRALLOC_USAGE_SW_WRITE_OFTEN, nullptr));
+ ASSERT_EQ(WOULD_BLOCK,
+ mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, GRALLOC_USAGE_SW_WRITE_OFTEN,
+ nullptr, nullptr));
// This should succeed, now that we've lifted the prohibition
ASSERT_EQ(OK, mProducer->allowAllocation(true));
ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
- mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0,
- GRALLOC_USAGE_SW_WRITE_OFTEN, nullptr));
+ mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, GRALLOC_USAGE_SW_WRITE_OFTEN,
+ nullptr, nullptr));
// Release the previous buffer back to the BufferQueue
mProducer->cancelBuffer(slot, fence);
// This should fail since we're requesting a different size
ASSERT_EQ(OK, mProducer->allowAllocation(false));
- ASSERT_EQ(WOULD_BLOCK, mProducer->dequeueBuffer(&slot, &fence,
- WIDTH * 2, HEIGHT * 2, 0, GRALLOC_USAGE_SW_WRITE_OFTEN, nullptr));
+ ASSERT_EQ(WOULD_BLOCK,
+ mProducer->dequeueBuffer(&slot, &fence, WIDTH * 2, HEIGHT * 2, 0,
+ GRALLOC_USAGE_SW_WRITE_OFTEN, nullptr, nullptr));
}
TEST_F(BufferQueueTest, TestGenerationNumbers) {
@@ -524,7 +526,7 @@
int slot;
sp<Fence> fence;
ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
- mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr));
+ mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr, nullptr));
sp<GraphicBuffer> buffer;
ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buffer));
@@ -567,7 +569,7 @@
sp<Fence> fence;
sp<GraphicBuffer> buffer;
ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
- mProducer->dequeueBuffer(&sharedSlot, &fence, 0, 0, 0, 0, nullptr));
+ mProducer->dequeueBuffer(&sharedSlot, &fence, 0, 0, 0, 0, nullptr, nullptr));
ASSERT_EQ(OK, mProducer->requestBuffer(sharedSlot, &buffer));
// Queue the buffer
@@ -581,8 +583,7 @@
// always the same one and because async mode gets enabled.
int slot;
for (int i = 0; i < 5; i++) {
- ASSERT_EQ(OK, mProducer->dequeueBuffer(
- &slot, &fence, 0, 0, 0, 0, nullptr));
+ ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr, nullptr));
ASSERT_EQ(sharedSlot, slot);
ASSERT_EQ(OK, mProducer->queueBuffer(sharedSlot, input, &output));
}
@@ -619,7 +620,7 @@
sp<Fence> fence;
sp<GraphicBuffer> buffer;
ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
- mProducer->dequeueBuffer(&sharedSlot, &fence, 0, 0, 0, 0, nullptr));
+ mProducer->dequeueBuffer(&sharedSlot, &fence, 0, 0, 0, 0, nullptr, nullptr));
ASSERT_EQ(OK, mProducer->requestBuffer(sharedSlot, &buffer));
// Queue the buffer
@@ -646,8 +647,7 @@
// always return the same one.
int slot;
for (int i = 0; i < 5; i++) {
- ASSERT_EQ(OK, mProducer->dequeueBuffer(
- &slot, &fence, 0, 0, 0, 0, nullptr));
+ ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr, nullptr));
ASSERT_EQ(sharedSlot, slot);
ASSERT_EQ(OK, mProducer->queueBuffer(sharedSlot, input, &output));
}
@@ -686,7 +686,7 @@
sp<Fence> fence;
sp<GraphicBuffer> buffer;
ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
- mProducer->dequeueBuffer(&sharedSlot, &fence, 0, 0, 0, 0, nullptr));
+ mProducer->dequeueBuffer(&sharedSlot, &fence, 0, 0, 0, 0, nullptr, nullptr));
ASSERT_EQ(OK, mProducer->requestBuffer(sharedSlot, &buffer));
// Enable shared buffer mode
@@ -703,8 +703,7 @@
// always the same one and because async mode gets enabled.
int slot;
for (int i = 0; i < 5; i++) {
- ASSERT_EQ(OK, mProducer->dequeueBuffer(
- &slot, &fence, 0, 0, 0, 0, nullptr));
+ ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr, nullptr));
ASSERT_EQ(sharedSlot, slot);
ASSERT_EQ(OK, mProducer->queueBuffer(sharedSlot, input, &output));
}
@@ -739,8 +738,7 @@
for (int i = 0; i < 5; ++i) {
int slot = BufferQueue::INVALID_BUFFER_SLOT;
sp<Fence> fence = Fence::NO_FENCE;
- auto result = mProducer->dequeueBuffer(
- &slot, &fence, 0, 0, 0, 0, nullptr);
+ auto result = mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr, nullptr);
if (i < 2) {
ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
result);
@@ -767,8 +765,7 @@
for (int i = 0; i < 2; ++i) {
int slot = BufferQueue::INVALID_BUFFER_SLOT;
sp<Fence> fence = Fence::NO_FENCE;
- ASSERT_EQ(OK, mProducer->dequeueBuffer(
- &slot, &fence, 0, 0, 0, 0, nullptr));
+ ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr, nullptr));
ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buffer));
IGraphicBufferProducer::QueueBufferInput input(0ull, true,
HAL_DATASPACE_UNKNOWN, Rect::INVALID_RECT,
@@ -779,8 +776,7 @@
int slot = BufferQueue::INVALID_BUFFER_SLOT;
sp<Fence> fence = Fence::NO_FENCE;
auto startTime = systemTime();
- ASSERT_EQ(TIMED_OUT, mProducer->dequeueBuffer(
- &slot, &fence, 0, 0, 0, 0, nullptr));
+ ASSERT_EQ(TIMED_OUT, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr, nullptr));
ASSERT_GE(systemTime() - startTime, TIMEOUT);
// We're technically attaching the same buffer multiple times (since we
@@ -801,7 +797,7 @@
int slot = BufferQueue::INVALID_BUFFER_SLOT;
sp<Fence> sourceFence;
ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
- mProducer->dequeueBuffer(&slot, &sourceFence, 0, 0, 0, 0, nullptr));
+ mProducer->dequeueBuffer(&slot, &sourceFence, 0, 0, 0, 0, nullptr, nullptr));
sp<GraphicBuffer> buffer;
ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buffer));
ASSERT_EQ(OK, mProducer->detachBuffer(slot));
@@ -824,7 +820,7 @@
int slot = BufferQueue::INVALID_BUFFER_SLOT;
sp<Fence> fence;
ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
- mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr));
+ mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr, nullptr));
sp<GraphicBuffer> firstBuffer;
ASSERT_EQ(OK, mProducer->requestBuffer(slot, &firstBuffer));
@@ -836,7 +832,7 @@
// Dequeue a second buffer
slot = BufferQueue::INVALID_BUFFER_SLOT;
ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
- mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr));
+ mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr, nullptr));
sp<GraphicBuffer> secondBuffer;
ASSERT_EQ(OK, mProducer->requestBuffer(slot, &secondBuffer));
@@ -887,8 +883,8 @@
int slots[3] = {};
mProducer->setMaxDequeuedBufferCount(3);
for (size_t i = 0; i < 3; ++i) {
- status_t result = mProducer->dequeueBuffer(&slots[i], &fence,
- 0, 0, 0, 0, nullptr);
+ status_t result =
+ mProducer->dequeueBuffer(&slots[i], &fence, 0, 0, 0, 0, nullptr, nullptr);
ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, result);
ASSERT_EQ(OK, mProducer->requestBuffer(slots[i], &buffer));
}
@@ -901,8 +897,7 @@
// The first segment is a two-buffer segment, so we only put one buffer into
// the queue at a time
for (size_t i = 0; i < 5; ++i) {
- ASSERT_EQ(OK, mProducer->dequeueBuffer(
- &slot, &fence, 0, 0, 0, 0, nullptr));
+ ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr, nullptr));
ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output));
ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0));
ASSERT_EQ(OK, mConsumer->releaseBuffer(item.mSlot, item.mFrameNumber,
@@ -917,17 +912,16 @@
// two-buffer segment, but then at the end, we put two buffers in the queue
// at the same time before draining it.
for (size_t i = 0; i < 5; ++i) {
- ASSERT_EQ(OK, mProducer->dequeueBuffer(
- &slot, &fence, 0, 0, 0, 0, nullptr));
+ ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr, nullptr));
ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output));
ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0));
ASSERT_EQ(OK, mConsumer->releaseBuffer(item.mSlot, item.mFrameNumber,
EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE));
std::this_thread::sleep_for(16ms);
}
- ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr));
+ ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr, nullptr));
ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output));
- ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr));
+ ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr, nullptr));
ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output));
ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0));
ASSERT_EQ(OK, mConsumer->releaseBuffer(item.mSlot, item.mFrameNumber,
@@ -942,11 +936,10 @@
// The third segment is a triple-buffer segment, so the queue is switching
// between one buffer and two buffers deep.
- ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr));
+ ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr, nullptr));
ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output));
for (size_t i = 0; i < 5; ++i) {
- ASSERT_EQ(OK, mProducer->dequeueBuffer(
- &slot, &fence, 0, 0, 0, 0, nullptr));
+ ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr, nullptr));
ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output));
ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0));
ASSERT_EQ(OK, mConsumer->releaseBuffer(item.mSlot, item.mFrameNumber,
@@ -1026,8 +1019,8 @@
int slots[4] = {};
mProducer->setMaxDequeuedBufferCount(4);
for (size_t i = 0; i < 4; ++i) {
- status_t result = mProducer->dequeueBuffer(&slots[i], &fence,
- 0, 0, 0, 0, nullptr);
+ status_t result =
+ mProducer->dequeueBuffer(&slots[i], &fence, 0, 0, 0, 0, nullptr, nullptr);
ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, result);
ASSERT_EQ(OK, mProducer->requestBuffer(slots[i], &buffer));
}
@@ -1038,14 +1031,14 @@
// Get buffers in all states: dequeued, filled, acquired, free
// Fill 3 buffers
- ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr));
+ ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr, nullptr));
ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output));
- ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr));
+ ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr, nullptr));
ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output));
- ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr));
+ ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr, nullptr));
ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output));
// Dequeue 1 buffer
- ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr));
+ ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr, nullptr));
// Acquire and free 1 buffer
ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0));
@@ -1104,8 +1097,8 @@
int slots[2] = {};
ASSERT_EQ(OK, mProducer->setMaxDequeuedBufferCount(2));
for (size_t i = 0; i < 2; ++i) {
- status_t result = mProducer->dequeueBuffer(&slots[i], &fence,
- 0, 0, 0, 0, nullptr);
+ status_t result =
+ mProducer->dequeueBuffer(&slots[i], &fence, 0, 0, 0, 0, nullptr, nullptr);
ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, result);
ASSERT_EQ(OK, mProducer->requestBuffer(slots[i], &buffer));
}
@@ -1115,10 +1108,10 @@
// Fill 2 buffers without consumer consuming them. Verify that all
// queued buffer returns proper bufferReplaced flag
- ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr));
+ ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr, nullptr));
ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output));
ASSERT_EQ(false, output.bufferReplaced);
- ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr));
+ ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr, nullptr));
ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output));
ASSERT_EQ(true, output.bufferReplaced);
}
@@ -1140,8 +1133,7 @@
NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, Fence::NO_FENCE);
// Dequeue, request, and queue one buffer
- status_t result = mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0,
- nullptr);
+ status_t result = mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr, nullptr);
ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, result);
ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buffer));
ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output));
@@ -1156,7 +1148,7 @@
EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE));
// Dequeue and queue the buffer again
- ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr));
+ ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr, nullptr));
ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output));
// Acquire and release the buffer again. Upon acquiring, the buffer handle
@@ -1168,7 +1160,7 @@
EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE));
// Dequeue and queue the buffer again
- ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr));
+ ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr, nullptr));
ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output));
// Disconnect the producer end. This should clear all of the slots and mark
diff --git a/libs/gui/tests/CpuConsumer_test.cpp b/libs/gui/tests/CpuConsumer_test.cpp
index 5848c74..588e541 100644
--- a/libs/gui/tests/CpuConsumer_test.cpp
+++ b/libs/gui/tests/CpuConsumer_test.cpp
@@ -33,6 +33,7 @@
#include <utils/Mutex.h>
#include <utils/Condition.h>
+#include <vector>
#define CPU_CONSUMER_TEST_FORMAT_RAW 0
#define CPU_CONSUMER_TEST_FORMAT_Y8 0
#define CPU_CONSUMER_TEST_FORMAT_Y16 0
@@ -309,8 +310,6 @@
uint32_t h = buf.height;
const int blockWidth = w > 16 ? w / 16 : 1;
const int blockHeight = h > 16 ? h / 16 : 1;
- const int blockRows = h / blockHeight;
- const int blockCols = w / blockWidth;
// Top-left square is bright
checkPixel(buf, 0, 0, 191);
@@ -348,8 +347,6 @@
uint32_t h = buf.height;
const int blockWidth = w > 16 ? w / 16 : 1;
const int blockHeight = h > 16 ? h / 16 : 1;
- const int blockRows = h / blockHeight;
- const int blockCols = w / blockWidth;
// Top-left square is bright red
checkPixel(buf, 0, 0, 191, 63, 63);
@@ -391,8 +388,6 @@
uint32_t h = buf.height;
const int blockWidth = (w > 16 ? w / 8 : 2) & ~0x1;
const int blockHeight = (h > 16 ? h / 8 : 2) & ~0x1;
- const int blockRows = h / blockHeight;
- const int blockCols = w / blockWidth;
// Top-left square is red
checkPixel(buf, 0, 0, 1000, 200, 200);
@@ -635,7 +630,7 @@
// Consume
- CpuConsumer::LockedBuffer *b = new CpuConsumer::LockedBuffer[params.maxLockedBuffers];
+ std::vector<CpuConsumer::LockedBuffer> b(params.maxLockedBuffers);
for (int i = 0; i < params.maxLockedBuffers; i++) {
ALOGV("Locking frame %d", i);
err = mCC->lockNextBuffer(&b[i]);
@@ -684,9 +679,6 @@
for (int i = 1; i < params.maxLockedBuffers; i++) {
mCC->unlockBuffer(b[i]);
}
-
- delete[] b;
-
}
CpuConsumerTestParams y8TestSets[] = {
diff --git a/libs/gui/tests/GLTest.cpp b/libs/gui/tests/GLTest.cpp
index 1739d9c..a91552f 100644
--- a/libs/gui/tests/GLTest.cpp
+++ b/libs/gui/tests/GLTest.cpp
@@ -22,6 +22,8 @@
namespace android {
+using Transaction = SurfaceComposerClient::Transaction;
+
static int abs(int value) {
return value > 0 ? value : -value;
}
@@ -68,10 +70,10 @@
ASSERT_TRUE(mSurfaceControl != NULL);
ASSERT_TRUE(mSurfaceControl->isValid());
- SurfaceComposerClient::openGlobalTransaction();
- ASSERT_EQ(NO_ERROR, mSurfaceControl->setLayer(0x7FFFFFFF));
- ASSERT_EQ(NO_ERROR, mSurfaceControl->show());
- SurfaceComposerClient::closeGlobalTransaction();
+ Transaction t;
+ ASSERT_EQ(NO_ERROR, t.setLayer(mSurfaceControl, 0x7FFFFFFF)
+ .show(mSurfaceControl)
+ .apply());
sp<ANativeWindow> window = mSurfaceControl->getSurface();
mEglSurface = createWindowSurface(mEglDisplay, mGlConfig, window);
diff --git a/libs/gui/tests/IGraphicBufferProducer_test.cpp b/libs/gui/tests/IGraphicBufferProducer_test.cpp
index bcfc91c..dd23bd4 100644
--- a/libs/gui/tests/IGraphicBufferProducer_test.cpp
+++ b/libs/gui/tests/IGraphicBufferProducer_test.cpp
@@ -194,7 +194,8 @@
};
status_t dequeueBuffer(uint32_t w, uint32_t h, uint32_t format, uint32_t usage, DequeueBufferResult* result) {
- return mProducer->dequeueBuffer(&result->slot, &result->fence, w, h, format, usage, nullptr);
+ return mProducer->dequeueBuffer(&result->slot, &result->fence, w, h, format, usage,
+ nullptr, nullptr);
}
void setupDequeueRequestBuffer(int *slot, sp<Fence> *fence,
@@ -206,9 +207,12 @@
ASSERT_NO_FATAL_FAILURE(ConnectProducer());
- ASSERT_EQ(OK, ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION &
- (mProducer->dequeueBuffer(slot, fence, DEFAULT_WIDTH,
- DEFAULT_HEIGHT, DEFAULT_FORMAT, TEST_PRODUCER_USAGE_BITS, nullptr)));
+
+ ASSERT_EQ(OK,
+ ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION &
+ (mProducer->dequeueBuffer(slot, fence, DEFAULT_WIDTH, DEFAULT_HEIGHT,
+ DEFAULT_FORMAT, TEST_PRODUCER_USAGE_BITS,
+ nullptr, nullptr)));
EXPECT_LE(0, *slot);
EXPECT_GT(BufferQueue::NUM_BUFFER_SLOTS, *slot);
@@ -343,11 +347,11 @@
int dequeuedSlot = -1;
sp<Fence> dequeuedFence;
-
- ASSERT_EQ(OK, ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION &
- (mProducer->dequeueBuffer(&dequeuedSlot, &dequeuedFence,
- DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_FORMAT,
- TEST_PRODUCER_USAGE_BITS, nullptr)));
+ ASSERT_EQ(OK,
+ ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION &
+ (mProducer->dequeueBuffer(&dequeuedSlot, &dequeuedFence, DEFAULT_WIDTH,
+ DEFAULT_HEIGHT, DEFAULT_FORMAT,
+ TEST_PRODUCER_USAGE_BITS, nullptr, nullptr)));
EXPECT_LE(0, dequeuedSlot);
EXPECT_GT(BufferQueue::NUM_BUFFER_SLOTS, dequeuedSlot);
@@ -403,10 +407,11 @@
int dequeuedSlot = -1;
sp<Fence> dequeuedFence;
- ASSERT_EQ(OK, ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION &
- (mProducer->dequeueBuffer(&dequeuedSlot, &dequeuedFence,
- DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_FORMAT,
- TEST_PRODUCER_USAGE_BITS, nullptr)));
+ ASSERT_EQ(OK,
+ ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION &
+ (mProducer->dequeueBuffer(&dequeuedSlot, &dequeuedFence, DEFAULT_WIDTH,
+ DEFAULT_HEIGHT, DEFAULT_FORMAT,
+ TEST_PRODUCER_USAGE_BITS, nullptr, nullptr)));
// Slot was enqueued without requesting a buffer
{
@@ -472,10 +477,11 @@
int dequeuedSlot = -1;
sp<Fence> dequeuedFence;
- ASSERT_EQ(OK, ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION &
- (mProducer->dequeueBuffer(&dequeuedSlot, &dequeuedFence,
- DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_FORMAT,
- TEST_PRODUCER_USAGE_BITS, nullptr)));
+ ASSERT_EQ(OK,
+ ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION &
+ (mProducer->dequeueBuffer(&dequeuedSlot, &dequeuedFence, DEFAULT_WIDTH,
+ DEFAULT_HEIGHT, DEFAULT_FORMAT,
+ TEST_PRODUCER_USAGE_BITS, nullptr, nullptr)));
// No return code, but at least test that it doesn't blow up...
// TODO: add a return code
@@ -519,12 +525,11 @@
int dequeuedSlot = -1;
sp<Fence> dequeuedFence;
for (int i = 0; i < maxBuffers; ++i) {
-
- EXPECT_EQ(OK, ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION &
- (mProducer->dequeueBuffer(&dequeuedSlot, &dequeuedFence,
- DEFAULT_WIDTH, DEFAULT_HEIGHT,
- DEFAULT_FORMAT,
- TEST_PRODUCER_USAGE_BITS, nullptr)))
+ EXPECT_EQ(OK,
+ ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION &
+ (mProducer->dequeueBuffer(&dequeuedSlot, &dequeuedFence, DEFAULT_WIDTH,
+ DEFAULT_HEIGHT, DEFAULT_FORMAT,
+ TEST_PRODUCER_USAGE_BITS, nullptr, nullptr)))
<< "iteration: " << i << ", slot: " << dequeuedSlot;
}
@@ -557,11 +562,11 @@
int dequeuedSlot = -1;
sp<Fence> dequeuedFence;
for (int i = 0; i < 2; i++) {
- ASSERT_EQ(OK, ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION &
- (mProducer->dequeueBuffer(&dequeuedSlot, &dequeuedFence,
- DEFAULT_WIDTH, DEFAULT_HEIGHT,
- DEFAULT_FORMAT,
- TEST_PRODUCER_USAGE_BITS, nullptr)))
+ ASSERT_EQ(OK,
+ ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION &
+ (mProducer->dequeueBuffer(&dequeuedSlot, &dequeuedFence, DEFAULT_WIDTH,
+ DEFAULT_HEIGHT, DEFAULT_FORMAT,
+ TEST_PRODUCER_USAGE_BITS, nullptr, nullptr)))
<< "slot: " << dequeuedSlot;
}
@@ -593,10 +598,11 @@
// Should now be able to queue/dequeue as many buffers as we want without
// blocking
for (int i = 0; i < 5; ++i) {
- ASSERT_EQ(OK, ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION &
- (mProducer->dequeueBuffer(&dequeuedSlot, &dequeuedFence,
- DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_FORMAT,
- TEST_PRODUCER_USAGE_BITS, nullptr)))
+ ASSERT_EQ(OK,
+ ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION &
+ (mProducer->dequeueBuffer(&dequeuedSlot, &dequeuedFence, DEFAULT_WIDTH,
+ DEFAULT_HEIGHT, DEFAULT_FORMAT,
+ TEST_PRODUCER_USAGE_BITS, nullptr, nullptr)))
<< "slot : " << dequeuedSlot;
ASSERT_OK(mProducer->requestBuffer(dequeuedSlot, &dequeuedBuffer));
ASSERT_OK(mProducer->queueBuffer(dequeuedSlot, input, &output));
@@ -610,10 +616,11 @@
int dequeuedSlot = -1;
sp<Fence> dequeuedFence;
- ASSERT_EQ(OK, ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION &
- (mProducer->dequeueBuffer(&dequeuedSlot, &dequeuedFence,
- DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_FORMAT,
- TEST_PRODUCER_USAGE_BITS, nullptr)))
+ ASSERT_EQ(OK,
+ ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION &
+ (mProducer->dequeueBuffer(&dequeuedSlot, &dequeuedFence, DEFAULT_WIDTH,
+ DEFAULT_HEIGHT, DEFAULT_FORMAT,
+ TEST_PRODUCER_USAGE_BITS, nullptr, nullptr)))
<< "slot: " << dequeuedSlot;
}
@@ -630,8 +637,9 @@
int slot = -1;
sp<Fence> fence;
- ASSERT_EQ(NO_INIT, mProducer->dequeueBuffer(&slot, &fence, DEFAULT_WIDTH,
- DEFAULT_HEIGHT, DEFAULT_FORMAT, TEST_PRODUCER_USAGE_BITS, nullptr));
+ ASSERT_EQ(NO_INIT,
+ mProducer->dequeueBuffer(&slot, &fence, DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_FORMAT,
+ TEST_PRODUCER_USAGE_BITS, nullptr, nullptr));
}
TEST_F(IGraphicBufferProducerTest,
@@ -649,10 +657,11 @@
int slot = -1;
sp<Fence> fence;
- ASSERT_EQ(OK, ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION &
- (mProducer->dequeueBuffer(&slot, &fence, DEFAULT_WIDTH,
- DEFAULT_HEIGHT, DEFAULT_FORMAT, TEST_PRODUCER_USAGE_BITS,
- nullptr)));
+ ASSERT_EQ(OK,
+ ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION &
+ (mProducer->dequeueBuffer(&slot, &fence, DEFAULT_WIDTH, DEFAULT_HEIGHT,
+ DEFAULT_FORMAT, TEST_PRODUCER_USAGE_BITS,
+ nullptr, nullptr)));
EXPECT_LE(0, slot);
EXPECT_GT(BufferQueue::NUM_BUFFER_SLOTS, slot);
diff --git a/libs/gui/tests/Malicious.cpp b/libs/gui/tests/Malicious.cpp
index 7ecf08c..bb6b8a5 100644
--- a/libs/gui/tests/Malicious.cpp
+++ b/libs/gui/tests/Malicious.cpp
@@ -38,8 +38,10 @@
}
status_t setAsyncMode(bool async) override { return mProducer->setAsyncMode(async); }
status_t dequeueBuffer(int* slot, sp<Fence>* fence, uint32_t w, uint32_t h, PixelFormat format,
- uint32_t usage, FrameEventHistoryDelta* outTimestamps) override {
- return mProducer->dequeueBuffer(slot, fence, w, h, format, usage, outTimestamps);
+ uint64_t usage, uint64_t* outBufferAge,
+ FrameEventHistoryDelta* outTimestamps) override {
+ return mProducer->dequeueBuffer(slot, fence, w, h, format, usage, outBufferAge,
+ outTimestamps);
}
status_t detachBuffer(int slot) override { return mProducer->detachBuffer(slot); }
status_t detachNextBuffer(sp<GraphicBuffer>* outBuffer, sp<Fence>* outFence) override {
@@ -67,7 +69,7 @@
return mProducer->setSidebandStream(stream);
}
void allocateBuffers(uint32_t width, uint32_t height, PixelFormat format,
- uint32_t usage) override {
+ uint64_t usage) override {
mProducer->allocateBuffers(width, height, format, usage);
}
status_t allowAllocation(bool allow) override { return mProducer->allowAllocation(allow); }
@@ -90,6 +92,9 @@
}
void getFrameTimestamps(FrameEventHistoryDelta*) override {}
status_t getUniqueId(uint64_t* outId) const override { return mProducer->getUniqueId(outId); }
+ status_t getConsumerUsage(uint64_t* outUsage) const override {
+ return mProducer->getConsumerUsage(outUsage);
+ }
protected:
sp<IGraphicBufferProducer> mProducer;
@@ -105,10 +110,10 @@
// Override dequeueBuffer, optionally corrupting the returned slot number
status_t dequeueBuffer(int* buf, sp<Fence>* fence, uint32_t width, uint32_t height,
- PixelFormat format, uint32_t usage,
+ PixelFormat format, uint64_t usage, uint64_t* outBufferAge,
FrameEventHistoryDelta* outTimestamps) override {
EXPECT_EQ(BUFFER_NEEDS_REALLOCATION,
- mProducer->dequeueBuffer(buf, fence, width, height, format, usage,
+ mProducer->dequeueBuffer(buf, fence, width, height, format, usage, outBufferAge,
outTimestamps));
EXPECT_EQ(mExpectedSlot, *buf);
if (mMaliciousValue != 0) {
diff --git a/libs/gui/tests/StreamSplitter_test.cpp b/libs/gui/tests/StreamSplitter_test.cpp
index e2f4948..ad6e051 100644
--- a/libs/gui/tests/StreamSplitter_test.cpp
+++ b/libs/gui/tests/StreamSplitter_test.cpp
@@ -82,8 +82,8 @@
sp<Fence> fence;
sp<GraphicBuffer> buffer;
ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
- inputProducer->dequeueBuffer(&slot, &fence, 0, 0, 0,
- GRALLOC_USAGE_SW_WRITE_OFTEN, nullptr));
+ inputProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, GRALLOC_USAGE_SW_WRITE_OFTEN,
+ nullptr, nullptr));
ASSERT_EQ(OK, inputProducer->requestBuffer(slot, &buffer));
uint32_t* dataIn;
@@ -116,8 +116,8 @@
// This should succeed even with allocation disabled since it will have
// received the buffer back from the output BufferQueue
ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
- inputProducer->dequeueBuffer(&slot, &fence, 0, 0, 0,
- GRALLOC_USAGE_SW_WRITE_OFTEN, nullptr));
+ inputProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, GRALLOC_USAGE_SW_WRITE_OFTEN,
+ nullptr, nullptr));
}
TEST_F(StreamSplitterTest, OneInputMultipleOutputs) {
@@ -154,8 +154,8 @@
sp<Fence> fence;
sp<GraphicBuffer> buffer;
ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
- inputProducer->dequeueBuffer(&slot, &fence, 0, 0, 0,
- GRALLOC_USAGE_SW_WRITE_OFTEN, nullptr));
+ inputProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, GRALLOC_USAGE_SW_WRITE_OFTEN,
+ nullptr, nullptr));
ASSERT_EQ(OK, inputProducer->requestBuffer(slot, &buffer));
uint32_t* dataIn;
@@ -191,8 +191,8 @@
// This should succeed even with allocation disabled since it will have
// received the buffer back from the output BufferQueues
ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
- inputProducer->dequeueBuffer(&slot, &fence, 0, 0, 0,
- GRALLOC_USAGE_SW_WRITE_OFTEN, nullptr));
+ inputProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, GRALLOC_USAGE_SW_WRITE_OFTEN,
+ nullptr, nullptr));
}
TEST_F(StreamSplitterTest, OutputAbandonment) {
@@ -218,8 +218,8 @@
sp<Fence> fence;
sp<GraphicBuffer> buffer;
ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
- inputProducer->dequeueBuffer(&slot, &fence, 0, 0, 0,
- GRALLOC_USAGE_SW_WRITE_OFTEN, nullptr));
+ inputProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, GRALLOC_USAGE_SW_WRITE_OFTEN,
+ nullptr, nullptr));
ASSERT_EQ(OK, inputProducer->requestBuffer(slot, &buffer));
// Abandon the output
@@ -231,8 +231,9 @@
ASSERT_EQ(OK, inputProducer->queueBuffer(slot, qbInput, &qbOutput));
// Input should be abandoned
- ASSERT_EQ(NO_INIT, inputProducer->dequeueBuffer(&slot, &fence, 0, 0, 0,
- GRALLOC_USAGE_SW_WRITE_OFTEN, nullptr));
+ ASSERT_EQ(NO_INIT,
+ inputProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, GRALLOC_USAGE_SW_WRITE_OFTEN,
+ nullptr, nullptr));
}
} // namespace android
diff --git a/libs/gui/tests/SurfaceTextureClient_test.cpp b/libs/gui/tests/SurfaceTextureClient_test.cpp
index bd598e4..d5b2f00 100644
--- a/libs/gui/tests/SurfaceTextureClient_test.cpp
+++ b/libs/gui/tests/SurfaceTextureClient_test.cpp
@@ -28,7 +28,7 @@
#include <utils/Log.h>
#include <utils/Thread.h>
-EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name);
+extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name);
#define CROP_EXT_STR "EGL_ANDROID_image_crop"
namespace android {
diff --git a/libs/gui/tests/SurfaceTextureGL_test.cpp b/libs/gui/tests/SurfaceTextureGL_test.cpp
index c6745d0..5639286 100644
--- a/libs/gui/tests/SurfaceTextureGL_test.cpp
+++ b/libs/gui/tests/SurfaceTextureGL_test.cpp
@@ -323,7 +323,6 @@
for (int j = 0; j < numTestPixels; j++) {
int x = testPixels[j].x;
int y = testPixels[j].y;
- uint8_t value = 0;
if (j == (i % numTestPixels)) {
// We must y-invert the texture coords
EXPECT_TRUE(checkPixel(x, texHeight-y-1, 255, 255, 255, 255));
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index fcaa23a..660680b 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -42,6 +42,8 @@
using namespace android::hardware::configstore;
using namespace android::hardware::configstore::V1_0;
+using Transaction = SurfaceComposerClient::Transaction;
+
static bool hasWideColorDisplay =
getBool<ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::hasWideColorDisplay>(false);
@@ -69,10 +71,10 @@
ASSERT_TRUE(mSurfaceControl != NULL);
ASSERT_TRUE(mSurfaceControl->isValid());
- SurfaceComposerClient::openGlobalTransaction();
- ASSERT_EQ(NO_ERROR, mSurfaceControl->setLayer(0x7fffffff));
- ASSERT_EQ(NO_ERROR, mSurfaceControl->show());
- SurfaceComposerClient::closeGlobalTransaction();
+ Transaction t;
+ ASSERT_EQ(NO_ERROR, t.setLayer(mSurfaceControl, 0x7fffffff)
+ .show(mSurfaceControl)
+ .apply());
mSurface = mSurfaceControl->getSurface();
ASSERT_TRUE(mSurface != NULL);
@@ -393,6 +395,22 @@
ASSERT_LE(removedBuffers.size(), 1u);
}
+TEST_F(SurfaceTest, TestGetLastDequeueStartTime) {
+ sp<ANativeWindow> anw(mSurface);
+ ASSERT_EQ(NO_ERROR, native_window_api_connect(anw.get(), NATIVE_WINDOW_API_CPU));
+
+ ANativeWindowBuffer* buffer = nullptr;
+ int32_t fenceFd = -1;
+
+ nsecs_t before = systemTime(CLOCK_MONOTONIC);
+ anw->dequeueBuffer(anw.get(), &buffer, &fenceFd);
+ nsecs_t after = systemTime(CLOCK_MONOTONIC);
+
+ nsecs_t lastDequeueTime = mSurface->getLastDequeueStartTime();
+ ASSERT_LE(before, lastDequeueTime);
+ ASSERT_GE(after, lastDequeueTime);
+}
+
class FakeConsumer : public BnConsumerListener {
public:
void onFrameAvailable(const BufferItem& /*item*/) override {}
@@ -449,7 +467,8 @@
const sp<IGraphicBufferProducer>& /* parent */) override {
return nullptr;
}
- sp<IDisplayEventConnection> createDisplayEventConnection() override {
+ sp<IDisplayEventConnection> createDisplayEventConnection(ISurfaceComposer::VsyncSource)
+ override {
return nullptr;
}
sp<IBinder> createDisplay(const String8& /*displayName*/,
@@ -510,6 +529,11 @@
int32_t /*minLayerZ*/, int32_t /*maxLayerZ*/,
bool /*useIdentityTransform*/,
Rotation /*rotation*/) override { return NO_ERROR; }
+ virtual status_t captureLayers(const sp<IBinder>& /*parentHandle*/,
+ const sp<IGraphicBufferProducer>& /*producer*/,
+ ISurfaceComposer::Rotation /*rotation*/) override {
+ return NO_ERROR;
+ }
status_t clearAnimationFrameStats() override { return NO_ERROR; }
status_t getAnimationFrameStats(FrameStats* /*outStats*/) const override {
return NO_ERROR;
@@ -522,6 +546,9 @@
return NO_ERROR;
}
status_t injectVSync(nsecs_t /*when*/) override { return NO_ERROR; }
+ status_t getLayerDebugInfo(std::vector<LayerDebugInfo>* /*layers*/) const override {
+ return NO_ERROR;
+ }
protected:
IBinder* onAsBinder() override { return nullptr; }
@@ -1058,7 +1085,6 @@
EXPECT_EQ(initialCompositorTiming.presentLatency,
compositeToPresentLatency);
- const uint64_t fId1 = getNextFrameId();
dequeueAndQueue(0);
addFrameEvents(true, NO_FRAME_INDEX, 0);
@@ -1072,7 +1098,6 @@
EXPECT_EQ(initialCompositorTiming.presentLatency,
compositeToPresentLatency);
- const uint64_t fId2 = getNextFrameId();
dequeueAndQueue(1);
addFrameEvents(true, 0, 1);
@@ -1145,7 +1170,6 @@
nsecs_t expectedDeadline = initialCompositorTiming.deadline;
EXPECT_EQ(expectedDeadline, compositeDeadline);
- const uint64_t fId1 = getNextFrameId();
dequeueAndQueue(0);
addFrameEvents(true, NO_FRAME_INDEX, 0);
@@ -1158,7 +1182,6 @@
initialCompositorTiming.deadline +initialCompositorTiming.interval;
EXPECT_EQ(expectedDeadline, compositeDeadline);
- const uint64_t fId2 = getNextFrameId();
dequeueAndQueue(1);
addFrameEvents(true, 0, 1);
@@ -1568,4 +1591,4 @@
EXPECT_EQ(-1, outDisplayPresentTime);
}
-}
+} // namespace android
diff --git a/libs/hwc2on1adapter/Android.bp b/libs/hwc2on1adapter/Android.bp
index ec9cbf8..420a1f6 100644
--- a/libs/hwc2on1adapter/Android.bp
+++ b/libs/hwc2on1adapter/Android.bp
@@ -17,9 +17,13 @@
vendor: true,
clang: true,
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wno-user-defined-warnings",
+ ],
cppflags: [
"-Weverything",
- "-Wall",
"-Wunused",
"-Wunreachable-code",
diff --git a/libs/hwc2on1adapter/HWC2On1Adapter.cpp b/libs/hwc2on1adapter/HWC2On1Adapter.cpp
index 8c6ef69..77f06bb 100644
--- a/libs/hwc2on1adapter/HWC2On1Adapter.cpp
+++ b/libs/hwc2on1adapter/HWC2On1Adapter.cpp
@@ -426,7 +426,13 @@
std::unique_lock<std::recursive_timed_mutex> lock(mStateMutex);
- mCallbacks[descriptor] = {callbackData, pointer};
+ if (pointer != nullptr) {
+ mCallbacks[descriptor] = {callbackData, pointer};
+ } else {
+ ALOGI("unregisterCallback(%s)", to_string(descriptor).c_str());
+ mCallbacks.erase(descriptor);
+ return Error::None;
+ }
bool hasPendingInvalidate = false;
std::vector<hwc2_display_t> displayIds;
@@ -2005,10 +2011,21 @@
return Error::None;
}
+static bool compareRects(const hwc_rect_t& rect1, const hwc_rect_t& rect2) {
+ return rect1.left == rect2.left &&
+ rect1.right == rect2.right &&
+ rect1.top == rect2.top &&
+ rect1.bottom == rect2.bottom;
+}
+
Error HWC2On1Adapter::Layer::setVisibleRegion(hwc_region_t visible) {
- mVisibleRegion.resize(visible.numRects);
- std::copy_n(visible.rects, visible.numRects, mVisibleRegion.begin());
- mDisplay.markGeometryChanged();
+ if ((getNumVisibleRegions() != visible.numRects) ||
+ !std::equal(mVisibleRegion.begin(), mVisibleRegion.end(), visible.rects,
+ compareRects)) {
+ mVisibleRegion.resize(visible.numRects);
+ std::copy_n(visible.rects, visible.numRects, mVisibleRegion.begin());
+ mDisplay.markGeometryChanged();
+ }
return Error::None;
}
diff --git a/libs/hwc2onfbadapter/Android.bp b/libs/hwc2onfbadapter/Android.bp
new file mode 100644
index 0000000..73a41f7
--- /dev/null
+++ b/libs/hwc2onfbadapter/Android.bp
@@ -0,0 +1,33 @@
+// Copyright 2010 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.
+
+cc_library_shared {
+ name: "libhwc2onfbadapter",
+ vendor: true,
+
+ clang: true,
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+ ],
+
+ srcs: [
+ "HWC2OnFbAdapter.cpp",
+ ],
+
+ header_libs: ["libhardware_headers"],
+ shared_libs: ["liblog", "libsync"],
+ export_include_dirs: ["include"],
+}
diff --git a/libs/hwc2onfbadapter/HWC2OnFbAdapter.cpp b/libs/hwc2onfbadapter/HWC2OnFbAdapter.cpp
new file mode 100644
index 0000000..7c9e651
--- /dev/null
+++ b/libs/hwc2onfbadapter/HWC2OnFbAdapter.cpp
@@ -0,0 +1,887 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "HWC2OnFbAdapter"
+
+//#define LOG_NDEBUG 0
+
+#include "hwc2onfbadapter/HWC2OnFbAdapter.h"
+
+#include <algorithm>
+#include <type_traits>
+
+#include <inttypes.h>
+#include <time.h>
+#include <sys/prctl.h>
+#include <unistd.h> // for close
+
+#include <hardware/fb.h>
+#include <log/log.h>
+#include <sync/sync.h>
+
+namespace android {
+
+namespace {
+
+void dumpHook(hwc2_device_t* device, uint32_t* outSize, char* outBuffer) {
+ auto& adapter = HWC2OnFbAdapter::cast(device);
+ if (outBuffer) {
+ *outSize = adapter.getDebugString().copy(outBuffer, *outSize);
+ } else {
+ adapter.updateDebugString();
+ *outSize = adapter.getDebugString().size();
+ }
+}
+
+int32_t registerCallbackHook(hwc2_device_t* device, int32_t descriptor,
+ hwc2_callback_data_t callbackData, hwc2_function_pointer_t pointer) {
+ auto& adapter = HWC2OnFbAdapter::cast(device);
+ switch (descriptor) {
+ case HWC2_CALLBACK_HOTPLUG:
+ if (pointer) {
+ reinterpret_cast<HWC2_PFN_HOTPLUG>(pointer)(callbackData, adapter.getDisplayId(),
+ HWC2_CONNECTION_CONNECTED);
+ }
+ break;
+ case HWC2_CALLBACK_REFRESH:
+ break;
+ case HWC2_CALLBACK_VSYNC:
+ adapter.setVsyncCallback(reinterpret_cast<HWC2_PFN_VSYNC>(pointer), callbackData);
+ break;
+ default:
+ return HWC2_ERROR_BAD_PARAMETER;
+ }
+
+ return HWC2_ERROR_NONE;
+}
+
+uint32_t getMaxVirtualDisplayCountHook(hwc2_device_t* /*device*/) {
+ return 0;
+}
+
+int32_t createVirtualDisplayHook(hwc2_device_t* /*device*/, uint32_t /*width*/, uint32_t /*height*/,
+ int32_t* /*format*/, hwc2_display_t* /*outDisplay*/) {
+ return HWC2_ERROR_NO_RESOURCES;
+}
+
+int32_t destroyVirtualDisplayHook(hwc2_device_t* /*device*/, hwc2_display_t /*display*/) {
+ return HWC2_ERROR_BAD_DISPLAY;
+}
+
+int32_t setOutputBufferHook(hwc2_device_t* /*device*/, hwc2_display_t /*display*/,
+ buffer_handle_t /*buffer*/, int32_t /*releaseFence*/) {
+ return HWC2_ERROR_BAD_DISPLAY;
+}
+
+int32_t getDisplayNameHook(hwc2_device_t* device, hwc2_display_t display, uint32_t* outSize,
+ char* outName) {
+ auto& adapter = HWC2OnFbAdapter::cast(device);
+ if (adapter.getDisplayId() != display) {
+ return HWC2_ERROR_BAD_DISPLAY;
+ }
+
+ const auto& info = adapter.getInfo();
+ if (outName) {
+ *outSize = info.name.copy(outName, *outSize);
+ } else {
+ *outSize = info.name.size();
+ }
+
+ return HWC2_ERROR_NONE;
+}
+
+int32_t getDisplayTypeHook(hwc2_device_t* device, hwc2_display_t display, int32_t* outType) {
+ auto& adapter = HWC2OnFbAdapter::cast(device);
+ if (adapter.getDisplayId() != display) {
+ return HWC2_ERROR_BAD_DISPLAY;
+ }
+
+ *outType = HWC2_DISPLAY_TYPE_PHYSICAL;
+ return HWC2_ERROR_NONE;
+}
+
+int32_t getDozeSupportHook(hwc2_device_t* device, hwc2_display_t display, int32_t* outSupport) {
+ auto& adapter = HWC2OnFbAdapter::cast(device);
+ if (adapter.getDisplayId() != display) {
+ return HWC2_ERROR_BAD_DISPLAY;
+ }
+
+ *outSupport = 0;
+ return HWC2_ERROR_NONE;
+}
+
+int32_t getHdrCapabilitiesHook(hwc2_device_t* device, hwc2_display_t display, uint32_t* outNumTypes,
+ int32_t* /*outTypes*/, float* /*outMaxLuminance*/,
+ float* /*outMaxAverageLuminance*/, float* /*outMinLuminance*/) {
+ auto& adapter = HWC2OnFbAdapter::cast(device);
+ if (adapter.getDisplayId() != display) {
+ return HWC2_ERROR_BAD_DISPLAY;
+ }
+
+ *outNumTypes = 0;
+ return HWC2_ERROR_NONE;
+}
+
+int32_t setPowerModeHook(hwc2_device_t* device, hwc2_display_t display, int32_t /*mode*/) {
+ auto& adapter = HWC2OnFbAdapter::cast(device);
+ if (adapter.getDisplayId() != display) {
+ return HWC2_ERROR_BAD_DISPLAY;
+ }
+
+ // pretend that it works
+ return HWC2_ERROR_NONE;
+}
+
+int32_t setVsyncEnabledHook(hwc2_device_t* device, hwc2_display_t display, int32_t enabled) {
+ auto& adapter = HWC2OnFbAdapter::cast(device);
+ if (adapter.getDisplayId() != display) {
+ return HWC2_ERROR_BAD_DISPLAY;
+ }
+
+ adapter.enableVsync(enabled == HWC2_VSYNC_ENABLE);
+ return HWC2_ERROR_NONE;
+}
+
+int32_t getColorModesHook(hwc2_device_t* device, hwc2_display_t display, uint32_t* outNumModes,
+ int32_t* outModes) {
+ auto& adapter = HWC2OnFbAdapter::cast(device);
+ if (adapter.getDisplayId() != display) {
+ return HWC2_ERROR_BAD_DISPLAY;
+ }
+
+ if (outModes) {
+ if (*outNumModes > 0) {
+ outModes[0] = HAL_COLOR_MODE_NATIVE;
+ *outNumModes = 1;
+ }
+ } else {
+ *outNumModes = 1;
+ }
+
+ return HWC2_ERROR_NONE;
+}
+
+int32_t setColorModeHook(hwc2_device_t* device, hwc2_display_t display, int32_t mode) {
+ auto& adapter = HWC2OnFbAdapter::cast(device);
+ if (adapter.getDisplayId() != display) {
+ return HWC2_ERROR_BAD_DISPLAY;
+ }
+ if (mode != HAL_COLOR_MODE_NATIVE) {
+ return HWC2_ERROR_BAD_PARAMETER;
+ }
+
+ return HWC2_ERROR_NONE;
+}
+
+int32_t setColorTransformHook(hwc2_device_t* device, hwc2_display_t display,
+ const float* /*matrix*/, int32_t /*hint*/) {
+ auto& adapter = HWC2OnFbAdapter::cast(device);
+ if (adapter.getDisplayId() != display) {
+ return HWC2_ERROR_BAD_DISPLAY;
+ }
+
+ // we always force client composition
+ adapter.setState(HWC2OnFbAdapter::State::MODIFIED);
+ return HWC2_ERROR_NONE;
+}
+
+int32_t getClientTargetSupportHook(hwc2_device_t* device, hwc2_display_t display, uint32_t width,
+ uint32_t height, int32_t format, int32_t dataspace) {
+ auto& adapter = HWC2OnFbAdapter::cast(device);
+ if (adapter.getDisplayId() != display) {
+ return HWC2_ERROR_BAD_DISPLAY;
+ }
+ if (dataspace != HAL_DATASPACE_UNKNOWN) {
+ return HWC2_ERROR_UNSUPPORTED;
+ }
+
+ const auto& info = adapter.getInfo();
+ return (info.width == width && info.height == height && info.format == format)
+ ? HWC2_ERROR_NONE
+ : HWC2_ERROR_UNSUPPORTED;
+}
+
+int32_t setClientTargetHook(hwc2_device_t* device, hwc2_display_t display, buffer_handle_t target,
+ int32_t acquireFence, int32_t dataspace, hwc_region_t /*damage*/) {
+ if (acquireFence >= 0) {
+ sync_wait(acquireFence, -1);
+ close(acquireFence);
+ }
+
+ auto& adapter = HWC2OnFbAdapter::cast(device);
+ if (adapter.getDisplayId() != display) {
+ return HWC2_ERROR_BAD_DISPLAY;
+ }
+ if (dataspace != HAL_DATASPACE_UNKNOWN) {
+ return HWC2_ERROR_BAD_PARAMETER;
+ }
+
+ // no state change
+ adapter.setBuffer(target);
+ return HWC2_ERROR_NONE;
+}
+
+int32_t getDisplayConfigsHook(hwc2_device_t* device, hwc2_display_t display,
+ uint32_t* outNumConfigs, hwc2_config_t* outConfigs) {
+ auto& adapter = HWC2OnFbAdapter::cast(device);
+ if (adapter.getDisplayId() != display) {
+ return HWC2_ERROR_BAD_DISPLAY;
+ }
+
+ if (outConfigs) {
+ if (*outNumConfigs > 0) {
+ outConfigs[0] = adapter.getConfigId();
+ *outNumConfigs = 1;
+ }
+ } else {
+ *outNumConfigs = 1;
+ }
+
+ return HWC2_ERROR_NONE;
+}
+
+int32_t getDisplayAttributeHook(hwc2_device_t* device, hwc2_display_t display, hwc2_config_t config,
+ int32_t attribute, int32_t* outValue) {
+ auto& adapter = HWC2OnFbAdapter::cast(device);
+ if (adapter.getDisplayId() != display) {
+ return HWC2_ERROR_BAD_DISPLAY;
+ }
+ if (adapter.getConfigId() != config) {
+ return HWC2_ERROR_BAD_CONFIG;
+ }
+
+ const auto& info = adapter.getInfo();
+ switch (attribute) {
+ case HWC2_ATTRIBUTE_WIDTH:
+ *outValue = int32_t(info.width);
+ break;
+ case HWC2_ATTRIBUTE_HEIGHT:
+ *outValue = int32_t(info.height);
+ break;
+ case HWC2_ATTRIBUTE_VSYNC_PERIOD:
+ *outValue = int32_t(info.vsync_period_ns);
+ break;
+ case HWC2_ATTRIBUTE_DPI_X:
+ *outValue = int32_t(info.xdpi_scaled);
+ break;
+ case HWC2_ATTRIBUTE_DPI_Y:
+ *outValue = int32_t(info.ydpi_scaled);
+ break;
+ default:
+ return HWC2_ERROR_BAD_PARAMETER;
+ }
+
+ return HWC2_ERROR_NONE;
+}
+
+int32_t getActiveConfigHook(hwc2_device_t* device, hwc2_display_t display,
+ hwc2_config_t* outConfig) {
+ auto& adapter = HWC2OnFbAdapter::cast(device);
+ if (adapter.getDisplayId() != display) {
+ return HWC2_ERROR_BAD_DISPLAY;
+ }
+
+ *outConfig = adapter.getConfigId();
+ return HWC2_ERROR_NONE;
+}
+
+int32_t setActiveConfigHook(hwc2_device_t* device, hwc2_display_t display, hwc2_config_t config) {
+ auto& adapter = HWC2OnFbAdapter::cast(device);
+ if (adapter.getDisplayId() != display) {
+ return HWC2_ERROR_BAD_DISPLAY;
+ }
+ if (adapter.getConfigId() != config) {
+ return HWC2_ERROR_BAD_CONFIG;
+ }
+
+ return HWC2_ERROR_NONE;
+}
+
+int32_t validateDisplayHook(hwc2_device_t* device, hwc2_display_t display, uint32_t* outNumTypes,
+ uint32_t* outNumRequests) {
+ auto& adapter = HWC2OnFbAdapter::cast(device);
+ if (adapter.getDisplayId() != display) {
+ return HWC2_ERROR_BAD_DISPLAY;
+ }
+
+ const auto& dirtyLayers = adapter.getDirtyLayers();
+ *outNumTypes = dirtyLayers.size();
+ *outNumRequests = 0;
+
+ if (*outNumTypes > 0) {
+ adapter.setState(HWC2OnFbAdapter::State::VALIDATED_WITH_CHANGES);
+ return HWC2_ERROR_HAS_CHANGES;
+ } else {
+ adapter.setState(HWC2OnFbAdapter::State::VALIDATED);
+ return HWC2_ERROR_NONE;
+ }
+}
+
+int32_t getChangedCompositionTypesHook(hwc2_device_t* device, hwc2_display_t display,
+ uint32_t* outNumElements, hwc2_layer_t* outLayers,
+ int32_t* outTypes) {
+ auto& adapter = HWC2OnFbAdapter::cast(device);
+ if (adapter.getDisplayId() != display) {
+ return HWC2_ERROR_BAD_DISPLAY;
+ }
+ if (adapter.getState() == HWC2OnFbAdapter::State::MODIFIED) {
+ return HWC2_ERROR_NOT_VALIDATED;
+ }
+
+ // request client composition for all layers
+ const auto& dirtyLayers = adapter.getDirtyLayers();
+ if (outLayers && outTypes) {
+ *outNumElements = std::min(*outNumElements, uint32_t(dirtyLayers.size()));
+ auto iter = dirtyLayers.cbegin();
+ for (uint32_t i = 0; i < *outNumElements; i++) {
+ outLayers[i] = *iter++;
+ outTypes[i] = HWC2_COMPOSITION_CLIENT;
+ }
+ } else {
+ *outNumElements = dirtyLayers.size();
+ }
+
+ return HWC2_ERROR_NONE;
+}
+
+int32_t getDisplayRequestsHook(hwc2_device_t* device, hwc2_display_t display,
+ int32_t* outDisplayRequests, uint32_t* outNumElements,
+ hwc2_layer_t* /*outLayers*/, int32_t* /*outLayerRequests*/) {
+ auto& adapter = HWC2OnFbAdapter::cast(device);
+ if (adapter.getDisplayId() != display) {
+ return HWC2_ERROR_BAD_DISPLAY;
+ }
+ if (adapter.getState() == HWC2OnFbAdapter::State::MODIFIED) {
+ return HWC2_ERROR_NOT_VALIDATED;
+ }
+
+ *outDisplayRequests = 0;
+ *outNumElements = 0;
+ return HWC2_ERROR_NONE;
+}
+
+int32_t acceptDisplayChangesHook(hwc2_device_t* device, hwc2_display_t display) {
+ auto& adapter = HWC2OnFbAdapter::cast(device);
+ if (adapter.getDisplayId() != display) {
+ return HWC2_ERROR_BAD_DISPLAY;
+ }
+ if (adapter.getState() == HWC2OnFbAdapter::State::MODIFIED) {
+ return HWC2_ERROR_NOT_VALIDATED;
+ }
+
+ adapter.clearDirtyLayers();
+ adapter.setState(HWC2OnFbAdapter::State::VALIDATED);
+ return HWC2_ERROR_NONE;
+}
+
+int32_t presentDisplayHook(hwc2_device_t* device, hwc2_display_t display,
+ int32_t* outPresentFence) {
+ auto& adapter = HWC2OnFbAdapter::cast(device);
+ if (adapter.getDisplayId() != display) {
+ return HWC2_ERROR_BAD_DISPLAY;
+ }
+ if (adapter.getState() != HWC2OnFbAdapter::State::VALIDATED) {
+ return HWC2_ERROR_NOT_VALIDATED;
+ }
+
+ adapter.postBuffer();
+ *outPresentFence = -1;
+
+ return HWC2_ERROR_NONE;
+}
+
+int32_t getReleaseFencesHook(hwc2_device_t* device, hwc2_display_t display,
+ uint32_t* outNumElements, hwc2_layer_t* /*outLayers*/,
+ int32_t* /*outFences*/) {
+ auto& adapter = HWC2OnFbAdapter::cast(device);
+ if (adapter.getDisplayId() != display) {
+ return HWC2_ERROR_BAD_DISPLAY;
+ }
+
+ *outNumElements = 0;
+ return HWC2_ERROR_NONE;
+}
+
+int32_t createLayerHook(hwc2_device_t* device, hwc2_display_t display, hwc2_layer_t* outLayer) {
+ auto& adapter = HWC2OnFbAdapter::cast(device);
+ if (adapter.getDisplayId() != display) {
+ return HWC2_ERROR_BAD_DISPLAY;
+ }
+
+ *outLayer = adapter.addLayer();
+ adapter.setState(HWC2OnFbAdapter::State::MODIFIED);
+ return HWC2_ERROR_NONE;
+}
+
+int32_t destroyLayerHook(hwc2_device_t* device, hwc2_display_t display, hwc2_layer_t layer) {
+ auto& adapter = HWC2OnFbAdapter::cast(device);
+ if (adapter.getDisplayId() != display) {
+ return HWC2_ERROR_BAD_DISPLAY;
+ }
+
+ if (adapter.removeLayer(layer)) {
+ adapter.setState(HWC2OnFbAdapter::State::MODIFIED);
+ return HWC2_ERROR_NONE;
+ } else {
+ return HWC2_ERROR_BAD_LAYER;
+ }
+}
+
+int32_t setCursorPositionHook(hwc2_device_t* device, hwc2_display_t display, hwc2_layer_t /*layer*/,
+ int32_t /*x*/, int32_t /*y*/) {
+ auto& adapter = HWC2OnFbAdapter::cast(device);
+ if (adapter.getDisplayId() != display) {
+ return HWC2_ERROR_BAD_DISPLAY;
+ }
+
+ // always an error
+ return HWC2_ERROR_BAD_LAYER;
+}
+
+int32_t setLayerBufferHook(hwc2_device_t* device, hwc2_display_t display, hwc2_layer_t layer,
+ buffer_handle_t /*buffer*/, int32_t acquireFence) {
+ if (acquireFence >= 0) {
+ sync_wait(acquireFence, -1);
+ close(acquireFence);
+ }
+
+ auto& adapter = HWC2OnFbAdapter::cast(device);
+ if (adapter.getDisplayId() != display) {
+ return HWC2_ERROR_BAD_DISPLAY;
+ }
+ if (!adapter.hasLayer(layer)) {
+ return HWC2_ERROR_BAD_LAYER;
+ }
+
+ // no state change
+ return HWC2_ERROR_NONE;
+}
+
+int32_t setLayerSurfaceDamageHook(hwc2_device_t* device, hwc2_display_t display, hwc2_layer_t layer,
+ hwc_region_t /*damage*/) {
+ auto& adapter = HWC2OnFbAdapter::cast(device);
+ if (adapter.getDisplayId() != display) {
+ return HWC2_ERROR_BAD_DISPLAY;
+ }
+ if (!adapter.hasLayer(layer)) {
+ return HWC2_ERROR_BAD_LAYER;
+ }
+
+ // no state change
+ return HWC2_ERROR_NONE;
+}
+
+int32_t setLayerCompositionTypeHook(hwc2_device_t* device, hwc2_display_t display,
+ hwc2_layer_t layer, int32_t type) {
+ auto& adapter = HWC2OnFbAdapter::cast(device);
+ if (adapter.getDisplayId() != display) {
+ return HWC2_ERROR_BAD_DISPLAY;
+ }
+ if (!adapter.markLayerDirty(layer, type != HWC2_COMPOSITION_CLIENT)) {
+ return HWC2_ERROR_BAD_LAYER;
+ }
+
+ adapter.setState(HWC2OnFbAdapter::State::MODIFIED);
+ return HWC2_ERROR_NONE;
+}
+
+template <typename... Args>
+int32_t setLayerStateHook(hwc2_device_t* device, hwc2_display_t display, hwc2_layer_t layer,
+ Args... /*args*/) {
+ auto& adapter = HWC2OnFbAdapter::cast(device);
+ if (adapter.getDisplayId() != display) {
+ return HWC2_ERROR_BAD_DISPLAY;
+ }
+ if (!adapter.hasLayer(layer)) {
+ return HWC2_ERROR_BAD_LAYER;
+ }
+
+ adapter.setState(HWC2OnFbAdapter::State::MODIFIED);
+ return HWC2_ERROR_NONE;
+}
+
+template <typename PFN, typename T>
+static hwc2_function_pointer_t asFP(T function) {
+ static_assert(std::is_same<PFN, T>::value, "Incompatible function pointer");
+ return reinterpret_cast<hwc2_function_pointer_t>(function);
+}
+
+hwc2_function_pointer_t getFunctionHook(hwc2_device_t* /*device*/, int32_t descriptor) {
+ switch (descriptor) {
+ // global functions
+ case HWC2_FUNCTION_DUMP:
+ return asFP<HWC2_PFN_DUMP>(dumpHook);
+ case HWC2_FUNCTION_REGISTER_CALLBACK:
+ return asFP<HWC2_PFN_REGISTER_CALLBACK>(registerCallbackHook);
+
+ // virtual display functions
+ case HWC2_FUNCTION_GET_MAX_VIRTUAL_DISPLAY_COUNT:
+ return asFP<HWC2_PFN_GET_MAX_VIRTUAL_DISPLAY_COUNT>(getMaxVirtualDisplayCountHook);
+ case HWC2_FUNCTION_CREATE_VIRTUAL_DISPLAY:
+ return asFP<HWC2_PFN_CREATE_VIRTUAL_DISPLAY>(createVirtualDisplayHook);
+ case HWC2_FUNCTION_DESTROY_VIRTUAL_DISPLAY:
+ return asFP<HWC2_PFN_DESTROY_VIRTUAL_DISPLAY>(destroyVirtualDisplayHook);
+ case HWC2_FUNCTION_SET_OUTPUT_BUFFER:
+ return asFP<HWC2_PFN_SET_OUTPUT_BUFFER>(setOutputBufferHook);
+
+ // display functions
+ case HWC2_FUNCTION_GET_DISPLAY_NAME:
+ return asFP<HWC2_PFN_GET_DISPLAY_NAME>(getDisplayNameHook);
+ case HWC2_FUNCTION_GET_DISPLAY_TYPE:
+ return asFP<HWC2_PFN_GET_DISPLAY_TYPE>(getDisplayTypeHook);
+ case HWC2_FUNCTION_GET_DOZE_SUPPORT:
+ return asFP<HWC2_PFN_GET_DOZE_SUPPORT>(getDozeSupportHook);
+ case HWC2_FUNCTION_GET_HDR_CAPABILITIES:
+ return asFP<HWC2_PFN_GET_HDR_CAPABILITIES>(getHdrCapabilitiesHook);
+ case HWC2_FUNCTION_SET_POWER_MODE:
+ return asFP<HWC2_PFN_SET_POWER_MODE>(setPowerModeHook);
+ case HWC2_FUNCTION_SET_VSYNC_ENABLED:
+ return asFP<HWC2_PFN_SET_VSYNC_ENABLED>(setVsyncEnabledHook);
+ case HWC2_FUNCTION_GET_COLOR_MODES:
+ return asFP<HWC2_PFN_GET_COLOR_MODES>(getColorModesHook);
+ case HWC2_FUNCTION_SET_COLOR_MODE:
+ return asFP<HWC2_PFN_SET_COLOR_MODE>(setColorModeHook);
+ case HWC2_FUNCTION_SET_COLOR_TRANSFORM:
+ return asFP<HWC2_PFN_SET_COLOR_TRANSFORM>(setColorTransformHook);
+ case HWC2_FUNCTION_GET_CLIENT_TARGET_SUPPORT:
+ return asFP<HWC2_PFN_GET_CLIENT_TARGET_SUPPORT>(getClientTargetSupportHook);
+ case HWC2_FUNCTION_SET_CLIENT_TARGET:
+ return asFP<HWC2_PFN_SET_CLIENT_TARGET>(setClientTargetHook);
+
+ // config functions
+ case HWC2_FUNCTION_GET_DISPLAY_CONFIGS:
+ return asFP<HWC2_PFN_GET_DISPLAY_CONFIGS>(getDisplayConfigsHook);
+ case HWC2_FUNCTION_GET_DISPLAY_ATTRIBUTE:
+ return asFP<HWC2_PFN_GET_DISPLAY_ATTRIBUTE>(getDisplayAttributeHook);
+ case HWC2_FUNCTION_GET_ACTIVE_CONFIG:
+ return asFP<HWC2_PFN_GET_ACTIVE_CONFIG>(getActiveConfigHook);
+ case HWC2_FUNCTION_SET_ACTIVE_CONFIG:
+ return asFP<HWC2_PFN_SET_ACTIVE_CONFIG>(setActiveConfigHook);
+
+ // validate/present functions
+ case HWC2_FUNCTION_VALIDATE_DISPLAY:
+ return asFP<HWC2_PFN_VALIDATE_DISPLAY>(validateDisplayHook);
+ case HWC2_FUNCTION_GET_CHANGED_COMPOSITION_TYPES:
+ return asFP<HWC2_PFN_GET_CHANGED_COMPOSITION_TYPES>(getChangedCompositionTypesHook);
+ case HWC2_FUNCTION_GET_DISPLAY_REQUESTS:
+ return asFP<HWC2_PFN_GET_DISPLAY_REQUESTS>(getDisplayRequestsHook);
+ case HWC2_FUNCTION_ACCEPT_DISPLAY_CHANGES:
+ return asFP<HWC2_PFN_ACCEPT_DISPLAY_CHANGES>(acceptDisplayChangesHook);
+ case HWC2_FUNCTION_PRESENT_DISPLAY:
+ return asFP<HWC2_PFN_PRESENT_DISPLAY>(presentDisplayHook);
+ case HWC2_FUNCTION_GET_RELEASE_FENCES:
+ return asFP<HWC2_PFN_GET_RELEASE_FENCES>(getReleaseFencesHook);
+
+ // layer create/destroy
+ case HWC2_FUNCTION_CREATE_LAYER:
+ return asFP<HWC2_PFN_CREATE_LAYER>(createLayerHook);
+ case HWC2_FUNCTION_DESTROY_LAYER:
+ return asFP<HWC2_PFN_DESTROY_LAYER>(destroyLayerHook);
+
+ // layer functions; validateDisplay not required
+ case HWC2_FUNCTION_SET_CURSOR_POSITION:
+ return asFP<HWC2_PFN_SET_CURSOR_POSITION>(setCursorPositionHook);
+ case HWC2_FUNCTION_SET_LAYER_BUFFER:
+ return asFP<HWC2_PFN_SET_LAYER_BUFFER>(setLayerBufferHook);
+ case HWC2_FUNCTION_SET_LAYER_SURFACE_DAMAGE:
+ return asFP<HWC2_PFN_SET_LAYER_SURFACE_DAMAGE>(setLayerSurfaceDamageHook);
+
+ // layer state functions; validateDisplay required
+ case HWC2_FUNCTION_SET_LAYER_COMPOSITION_TYPE:
+ return asFP<HWC2_PFN_SET_LAYER_COMPOSITION_TYPE>(setLayerCompositionTypeHook);
+ case HWC2_FUNCTION_SET_LAYER_BLEND_MODE:
+ return asFP<HWC2_PFN_SET_LAYER_BLEND_MODE>(setLayerStateHook<int32_t>);
+ case HWC2_FUNCTION_SET_LAYER_COLOR:
+ return asFP<HWC2_PFN_SET_LAYER_COLOR>(setLayerStateHook<hwc_color_t>);
+ case HWC2_FUNCTION_SET_LAYER_DATASPACE:
+ return asFP<HWC2_PFN_SET_LAYER_DATASPACE>(setLayerStateHook<int32_t>);
+ case HWC2_FUNCTION_SET_LAYER_DISPLAY_FRAME:
+ return asFP<HWC2_PFN_SET_LAYER_DISPLAY_FRAME>(setLayerStateHook<hwc_rect_t>);
+ case HWC2_FUNCTION_SET_LAYER_PLANE_ALPHA:
+ return asFP<HWC2_PFN_SET_LAYER_PLANE_ALPHA>(setLayerStateHook<float>);
+ case HWC2_FUNCTION_SET_LAYER_SIDEBAND_STREAM:
+ return asFP<HWC2_PFN_SET_LAYER_SIDEBAND_STREAM>(setLayerStateHook<buffer_handle_t>);
+ case HWC2_FUNCTION_SET_LAYER_SOURCE_CROP:
+ return asFP<HWC2_PFN_SET_LAYER_SOURCE_CROP>(setLayerStateHook<hwc_frect_t>);
+ case HWC2_FUNCTION_SET_LAYER_TRANSFORM:
+ return asFP<HWC2_PFN_SET_LAYER_TRANSFORM>(setLayerStateHook<int32_t>);
+ case HWC2_FUNCTION_SET_LAYER_VISIBLE_REGION:
+ return asFP<HWC2_PFN_SET_LAYER_VISIBLE_REGION>(setLayerStateHook<hwc_region_t>);
+ case HWC2_FUNCTION_SET_LAYER_Z_ORDER:
+ return asFP<HWC2_PFN_SET_LAYER_Z_ORDER>(setLayerStateHook<uint32_t>);
+
+ default:
+ ALOGE("unknown function descriptor %d", descriptor);
+ return nullptr;
+ }
+}
+
+void getCapabilitiesHook(hwc2_device_t* /*device*/, uint32_t* outCount,
+ int32_t* /*outCapabilities*/) {
+ *outCount = 0;
+}
+
+int closeHook(hw_device_t* device) {
+ auto& adapter = HWC2OnFbAdapter::cast(device);
+ adapter.close();
+ return 0;
+}
+
+} // anonymous namespace
+
+HWC2OnFbAdapter::HWC2OnFbAdapter(framebuffer_device_t* fbDevice)
+ : hwc2_device_t(), mFbDevice(fbDevice) {
+ common.close = closeHook;
+ hwc2_device::getCapabilities = getCapabilitiesHook;
+ hwc2_device::getFunction = getFunctionHook;
+
+ mFbInfo.name = "fbdev";
+ mFbInfo.width = mFbDevice->width;
+ mFbInfo.height = mFbDevice->height;
+ mFbInfo.format = mFbDevice->format;
+ mFbInfo.vsync_period_ns = int(1e9 / mFbDevice->fps);
+ mFbInfo.xdpi_scaled = int(mFbDevice->xdpi * 1000.0f);
+ mFbInfo.ydpi_scaled = int(mFbDevice->ydpi * 1000.0f);
+
+ mVsyncThread.start(0, mFbInfo.vsync_period_ns);
+}
+
+HWC2OnFbAdapter& HWC2OnFbAdapter::cast(hw_device_t* device) {
+ return *reinterpret_cast<HWC2OnFbAdapter*>(device);
+}
+
+HWC2OnFbAdapter& HWC2OnFbAdapter::cast(hwc2_device_t* device) {
+ return *reinterpret_cast<HWC2OnFbAdapter*>(device);
+}
+
+hwc2_display_t HWC2OnFbAdapter::getDisplayId() {
+ return 0;
+}
+
+hwc2_config_t HWC2OnFbAdapter::getConfigId() {
+ return 0;
+}
+
+void HWC2OnFbAdapter::close() {
+ mVsyncThread.stop();
+ framebuffer_close(mFbDevice);
+}
+
+const HWC2OnFbAdapter::Info& HWC2OnFbAdapter::getInfo() const {
+ return mFbInfo;
+}
+
+void HWC2OnFbAdapter::updateDebugString() {
+ if (mFbDevice->common.version >= 1 && mFbDevice->dump) {
+ char buffer[4096];
+ mFbDevice->dump(mFbDevice, buffer, sizeof(buffer));
+ buffer[sizeof(buffer) - 1] = '\0';
+
+ mDebugString = buffer;
+ }
+}
+
+const std::string& HWC2OnFbAdapter::getDebugString() const {
+ return mDebugString;
+}
+
+void HWC2OnFbAdapter::setState(State state) {
+ mState = state;
+}
+
+HWC2OnFbAdapter::State HWC2OnFbAdapter::getState() const {
+ return mState;
+}
+
+hwc2_layer_t HWC2OnFbAdapter::addLayer() {
+ hwc2_layer_t id = ++mNextLayerId;
+
+ mLayers.insert(id);
+ mDirtyLayers.insert(id);
+
+ return id;
+}
+
+bool HWC2OnFbAdapter::removeLayer(hwc2_layer_t layer) {
+ mDirtyLayers.erase(layer);
+ return mLayers.erase(layer);
+}
+
+bool HWC2OnFbAdapter::hasLayer(hwc2_layer_t layer) const {
+ return mLayers.count(layer) > 0;
+}
+
+bool HWC2OnFbAdapter::markLayerDirty(hwc2_layer_t layer, bool dirty) {
+ if (mLayers.count(layer) == 0) {
+ return false;
+ }
+
+ if (dirty) {
+ mDirtyLayers.insert(layer);
+ } else {
+ mDirtyLayers.erase(layer);
+ }
+
+ return true;
+}
+
+const std::unordered_set<hwc2_layer_t>& HWC2OnFbAdapter::getDirtyLayers() const {
+ return mDirtyLayers;
+}
+
+void HWC2OnFbAdapter::clearDirtyLayers() {
+ mDirtyLayers.clear();
+}
+
+/*
+ * For each frame, SurfaceFlinger
+ *
+ * - peforms GLES composition
+ * - calls eglSwapBuffers
+ * - calls setClientTarget, which maps to setBuffer below
+ * - calls presentDisplay, which maps to postBuffer below
+ *
+ * setBuffer should be a good place to call compositionComplete.
+ *
+ * As for post, it
+ *
+ * - schedules the buffer for presentation on the next vsync
+ * - locks the buffer and blocks all other users trying to lock it
+ *
+ * It does not give us a way to return a present fence, and we need to live
+ * with that. The implication is that, when we are double-buffered,
+ * SurfaceFlinger assumes the front buffer is available for rendering again
+ * immediately after the back buffer is posted. The locking semantics
+ * hopefully are strong enough that the rendering will be blocked.
+ */
+void HWC2OnFbAdapter::setBuffer(buffer_handle_t buffer) {
+ if (mFbDevice->compositionComplete) {
+ mFbDevice->compositionComplete(mFbDevice);
+ }
+ mBuffer = buffer;
+}
+
+bool HWC2OnFbAdapter::postBuffer() {
+ int error = 0;
+ if (mBuffer) {
+ error = mFbDevice->post(mFbDevice, mBuffer);
+ }
+
+ return error == 0;
+}
+
+void HWC2OnFbAdapter::setVsyncCallback(HWC2_PFN_VSYNC callback, hwc2_callback_data_t data) {
+ mVsyncThread.setCallback(callback, data);
+}
+
+void HWC2OnFbAdapter::enableVsync(bool enable) {
+ mVsyncThread.enableCallback(enable);
+}
+
+int64_t HWC2OnFbAdapter::VsyncThread::now() {
+ struct timespec ts;
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+
+ return int64_t(ts.tv_sec) * 1'000'000'000 + ts.tv_nsec;
+}
+
+bool HWC2OnFbAdapter::VsyncThread::sleepUntil(int64_t t) {
+ struct timespec ts;
+ ts.tv_sec = t / 1'000'000'000;
+ ts.tv_nsec = t % 1'000'000'000;
+
+ while (true) {
+ int error = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &ts, nullptr);
+ if (error) {
+ if (error == EINTR) {
+ continue;
+ }
+ return false;
+ } else {
+ return true;
+ }
+ }
+}
+
+void HWC2OnFbAdapter::VsyncThread::start(int64_t firstVsync, int64_t period) {
+ mNextVsync = firstVsync;
+ mPeriod = period;
+ mStarted = true;
+ mThread = std::thread(&VsyncThread::vsyncLoop, this);
+}
+
+void HWC2OnFbAdapter::VsyncThread::stop() {
+ {
+ std::lock_guard<std::mutex> lock(mMutex);
+ mStarted = false;
+ }
+ mCondition.notify_all();
+ mThread.join();
+}
+
+void HWC2OnFbAdapter::VsyncThread::setCallback(HWC2_PFN_VSYNC callback, hwc2_callback_data_t data) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ mCallback = callback;
+ mCallbackData = data;
+}
+
+void HWC2OnFbAdapter::VsyncThread::enableCallback(bool enable) {
+ {
+ std::lock_guard<std::mutex> lock(mMutex);
+ mCallbackEnabled = enable;
+ }
+ mCondition.notify_all();
+}
+
+void HWC2OnFbAdapter::VsyncThread::vsyncLoop() {
+ prctl(PR_SET_NAME, "VsyncThread", 0, 0, 0);
+
+ std::unique_lock<std::mutex> lock(mMutex);
+ if (!mStarted) {
+ return;
+ }
+
+ while (true) {
+ if (!mCallbackEnabled) {
+ mCondition.wait(lock, [this] { return mCallbackEnabled || !mStarted; });
+ if (!mStarted) {
+ break;
+ }
+ }
+
+ lock.unlock();
+
+ // adjust mNextVsync if necessary
+ int64_t t = now();
+ if (mNextVsync < t) {
+ int64_t n = (t - mNextVsync + mPeriod - 1) / mPeriod;
+ mNextVsync += mPeriod * n;
+ }
+ bool fire = sleepUntil(mNextVsync);
+
+ lock.lock();
+
+ if (fire) {
+ ALOGV("VsyncThread(%" PRId64 ")", mNextVsync);
+ if (mCallback) {
+ mCallback(mCallbackData, getDisplayId(), mNextVsync);
+ }
+ mNextVsync += mPeriod;
+ }
+ }
+}
+
+} // namespace android
diff --git a/libs/hwc2onfbadapter/include/hwc2onfbadapter/HWC2OnFbAdapter.h b/libs/hwc2onfbadapter/include/hwc2onfbadapter/HWC2OnFbAdapter.h
new file mode 100644
index 0000000..d6272fd
--- /dev/null
+++ b/libs/hwc2onfbadapter/include/hwc2onfbadapter/HWC2OnFbAdapter.h
@@ -0,0 +1,123 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_SF_HWC2_ON_FB_ADAPTER_H
+#define ANDROID_SF_HWC2_ON_FB_ADAPTER_H
+
+#include <condition_variable>
+#include <mutex>
+#include <string>
+#include <thread>
+#include <unordered_set>
+
+#include <hardware/hwcomposer2.h>
+
+struct framebuffer_device_t;
+
+namespace android {
+
+class HWC2OnFbAdapter : public hwc2_device_t {
+public:
+ HWC2OnFbAdapter(framebuffer_device_t* fbDevice);
+
+ static HWC2OnFbAdapter& cast(hw_device_t* device);
+ static HWC2OnFbAdapter& cast(hwc2_device_t* device);
+
+ static hwc2_display_t getDisplayId();
+ static hwc2_config_t getConfigId();
+
+ void close();
+
+ struct Info {
+ std::string name;
+ uint32_t width;
+ uint32_t height;
+ int format;
+ int vsync_period_ns;
+ int xdpi_scaled;
+ int ydpi_scaled;
+ };
+ const Info& getInfo() const;
+
+ void updateDebugString();
+ const std::string& getDebugString() const;
+
+ enum class State {
+ MODIFIED,
+ VALIDATED_WITH_CHANGES,
+ VALIDATED,
+ };
+ void setState(State state);
+ State getState() const;
+
+ hwc2_layer_t addLayer();
+ bool removeLayer(hwc2_layer_t layer);
+ bool hasLayer(hwc2_layer_t layer) const;
+ bool markLayerDirty(hwc2_layer_t layer, bool dirty);
+ const std::unordered_set<hwc2_layer_t>& getDirtyLayers() const;
+ void clearDirtyLayers();
+
+ void setBuffer(buffer_handle_t buffer);
+ bool postBuffer();
+
+ void setVsyncCallback(HWC2_PFN_VSYNC callback, hwc2_callback_data_t data);
+ void enableVsync(bool enable);
+
+private:
+ framebuffer_device_t* mFbDevice{nullptr};
+ Info mFbInfo{};
+
+ std::string mDebugString;
+
+ State mState{State::MODIFIED};
+
+ uint64_t mNextLayerId{0};
+ std::unordered_set<hwc2_layer_t> mLayers;
+ std::unordered_set<hwc2_layer_t> mDirtyLayers;
+
+ buffer_handle_t mBuffer{nullptr};
+
+ class VsyncThread {
+ public:
+ static int64_t now();
+ static bool sleepUntil(int64_t t);
+
+ void start(int64_t first, int64_t period);
+ void stop();
+ void setCallback(HWC2_PFN_VSYNC callback, hwc2_callback_data_t data);
+ void enableCallback(bool enable);
+
+ private:
+ void vsyncLoop();
+ bool waitUntilNextVsync();
+
+ std::thread mThread;
+ int64_t mNextVsync{0};
+ int64_t mPeriod{0};
+
+ std::mutex mMutex;
+ std::condition_variable mCondition;
+ bool mStarted{false};
+ HWC2_PFN_VSYNC mCallback{nullptr};
+ hwc2_callback_data_t mCallbackData{nullptr};
+ bool mCallbackEnabled{false};
+ };
+ VsyncThread mVsyncThread;
+};
+
+} // namespace android
+
+#endif // ANDROID_SF_HWC2_ON_FB_ADAPTER_H
diff --git a/libs/input/Android.bp b/libs/input/Android.bp
index 9294419..2f39976 100644
--- a/libs/input/Android.bp
+++ b/libs/input/Android.bp
@@ -34,6 +34,7 @@
clang: true,
shared_libs: [
+ "libbase",
"liblog",
"libcutils",
],
diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp
index 293bc25..b8901bd 100644
--- a/libs/input/InputTransport.cpp
+++ b/libs/input/InputTransport.cpp
@@ -254,7 +254,7 @@
#if DEBUG_TRANSPORT_ACTIONS
ALOGD("channel '%s' publisher ~ publishKeyEvent: seq=%u, deviceId=%d, source=0x%x, "
"action=0x%x, flags=0x%x, keyCode=%d, scanCode=%d, metaState=0x%x, repeatCount=%d,"
- "downTime=%lld, eventTime=%lld",
+ "downTime=%" PRId64 ", eventTime=%" PRId64,
mChannel->getName().string(), seq,
deviceId, source, action, flags, keyCode, scanCode, metaState, repeatCount,
downTime, eventTime);
@@ -285,6 +285,7 @@
uint32_t seq,
int32_t deviceId,
int32_t source,
+ int32_t displayId,
int32_t action,
int32_t actionButton,
int32_t flags,
@@ -304,7 +305,7 @@
ALOGD("channel '%s' publisher ~ publishMotionEvent: seq=%u, deviceId=%d, source=0x%x, "
"action=0x%x, actionButton=0x%08x, flags=0x%x, edgeFlags=0x%x, "
"metaState=0x%x, buttonState=0x%x, xOffset=%f, yOffset=%f, "
- "xPrecision=%f, yPrecision=%f, downTime=%lld, eventTime=%lld, "
+ "xPrecision=%f, yPrecision=%f, downTime=%" PRId64 ", eventTime=%" PRId64 ", "
"pointerCount=%" PRIu32,
mChannel->getName().string(), seq,
deviceId, source, action, actionButton, flags, edgeFlags, metaState, buttonState,
@@ -327,6 +328,7 @@
msg.body.motion.seq = seq;
msg.body.motion.deviceId = deviceId;
msg.body.motion.source = source;
+ msg.body.motion.displayId = displayId;
msg.body.motion.action = action;
msg.body.motion.actionButton = actionButton;
msg.body.motion.flags = flags;
@@ -396,14 +398,16 @@
}
status_t InputConsumer::consume(InputEventFactoryInterface* factory,
- bool consumeBatches, nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent) {
+ bool consumeBatches, nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent,
+ int32_t* displayId) {
#if DEBUG_TRANSPORT_ACTIONS
- ALOGD("channel '%s' consumer ~ consume: consumeBatches=%s, frameTime=%lld",
+ ALOGD("channel '%s' consumer ~ consume: consumeBatches=%s, frameTime=%" PRId64,
mChannel->getName().string(), consumeBatches ? "true" : "false", frameTime);
#endif
*outSeq = 0;
*outEvent = NULL;
+ *displayId = -1; // Invalid display.
// Fetch the next input message.
// Loop until an event can be returned or no additional events are received.
@@ -418,7 +422,7 @@
if (result) {
// Consume the next batched event unless batches are being held for later.
if (consumeBatches || result != WOULD_BLOCK) {
- result = consumeBatch(factory, frameTime, outSeq, outEvent);
+ result = consumeBatch(factory, frameTime, outSeq, outEvent, displayId);
if (*outEvent) {
#if DEBUG_TRANSPORT_ACTIONS
ALOGD("channel '%s' consumer ~ consumed batch event, seq=%u",
@@ -446,7 +450,7 @@
break;
}
- case AINPUT_EVENT_TYPE_MOTION: {
+ case InputMessage::TYPE_MOTION: {
ssize_t batchIndex = findBatch(mMsg.body.motion.deviceId, mMsg.body.motion.source);
if (batchIndex >= 0) {
Batch& batch = mBatches.editItemAt(batchIndex);
@@ -462,7 +466,7 @@
// the previous batch right now and defer the new message until later.
mMsgDeferred = true;
status_t result = consumeSamples(factory,
- batch, batch.samples.size(), outSeq, outEvent);
+ batch, batch.samples.size(), outSeq, outEvent, displayId);
mBatches.removeAt(batchIndex);
if (result) {
return result;
@@ -492,10 +496,11 @@
MotionEvent* motionEvent = factory->createMotionEvent();
if (! motionEvent) return NO_MEMORY;
- updateTouchState(&mMsg);
+ updateTouchState(mMsg);
initializeMotionEvent(motionEvent, &mMsg);
*outSeq = mMsg.body.motion.seq;
*outEvent = motionEvent;
+ *displayId = mMsg.body.motion.displayId;
#if DEBUG_TRANSPORT_ACTIONS
ALOGD("channel '%s' consumer ~ consumed motion event, seq=%u",
mChannel->getName().string(), *outSeq);
@@ -513,14 +518,14 @@
}
status_t InputConsumer::consumeBatch(InputEventFactoryInterface* factory,
- nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent) {
+ nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent, int32_t* displayId) {
status_t result;
for (size_t i = mBatches.size(); i > 0; ) {
i--;
Batch& batch = mBatches.editItemAt(i);
if (frameTime < 0) {
result = consumeSamples(factory, batch, batch.samples.size(),
- outSeq, outEvent);
+ outSeq, outEvent, displayId);
mBatches.removeAt(i);
return result;
}
@@ -534,7 +539,7 @@
continue;
}
- result = consumeSamples(factory, batch, split + 1, outSeq, outEvent);
+ result = consumeSamples(factory, batch, split + 1, outSeq, outEvent, displayId);
const InputMessage* next;
if (batch.samples.isEmpty()) {
mBatches.removeAt(i);
@@ -552,14 +557,14 @@
}
status_t InputConsumer::consumeSamples(InputEventFactoryInterface* factory,
- Batch& batch, size_t count, uint32_t* outSeq, InputEvent** outEvent) {
+ Batch& batch, size_t count, uint32_t* outSeq, InputEvent** outEvent, int32_t* displayId) {
MotionEvent* motionEvent = factory->createMotionEvent();
if (! motionEvent) return NO_MEMORY;
uint32_t chain = 0;
for (size_t i = 0; i < count; i++) {
InputMessage& msg = batch.samples.editItemAt(i);
- updateTouchState(&msg);
+ updateTouchState(msg);
if (i) {
SeqChain seqChain;
seqChain.seq = msg.body.motion.seq;
@@ -567,6 +572,7 @@
mSeqChains.push(seqChain);
addSample(motionEvent, &msg);
} else {
+ *displayId = msg.body.motion.displayId;
initializeMotionEvent(motionEvent, &msg);
}
chain = msg.body.motion.seq;
@@ -578,20 +584,19 @@
return OK;
}
-void InputConsumer::updateTouchState(InputMessage* msg) {
+void InputConsumer::updateTouchState(InputMessage& msg) {
if (!mResampleTouch ||
- !(msg->body.motion.source & AINPUT_SOURCE_CLASS_POINTER)) {
+ !(msg.body.motion.source & AINPUT_SOURCE_CLASS_POINTER)) {
return;
}
- int32_t deviceId = msg->body.motion.deviceId;
- int32_t source = msg->body.motion.source;
- nsecs_t eventTime = msg->body.motion.eventTime;
+ int32_t deviceId = msg.body.motion.deviceId;
+ int32_t source = msg.body.motion.source;
// Update the touch state history to incorporate the new input message.
// If the message is in the past relative to the most recently produced resampled
// touch, then use the resampled time and coordinates instead.
- switch (msg->body.motion.action & AMOTION_EVENT_ACTION_MASK) {
+ switch (msg.body.motion.action & AMOTION_EVENT_ACTION_MASK) {
case AMOTION_EVENT_ACTION_DOWN: {
ssize_t index = findTouchState(deviceId, source);
if (index < 0) {
@@ -609,9 +614,8 @@
if (index >= 0) {
TouchState& touchState = mTouchStates.editItemAt(index);
touchState.addHistory(msg);
- if (eventTime < touchState.lastResample.eventTime) {
- rewriteMessage(touchState, msg);
- } else {
+ bool messageRewritten = rewriteMessage(touchState, msg);
+ if (!messageRewritten) {
touchState.lastResample.idBits.clear();
}
}
@@ -622,7 +626,7 @@
ssize_t index = findTouchState(deviceId, source);
if (index >= 0) {
TouchState& touchState = mTouchStates.editItemAt(index);
- touchState.lastResample.idBits.clearBit(msg->body.motion.getActionId());
+ touchState.lastResample.idBits.clearBit(msg.body.motion.getActionId());
rewriteMessage(touchState, msg);
}
break;
@@ -633,7 +637,7 @@
if (index >= 0) {
TouchState& touchState = mTouchStates.editItemAt(index);
rewriteMessage(touchState, msg);
- touchState.lastResample.idBits.clearBit(msg->body.motion.getActionId());
+ touchState.lastResample.idBits.clearBit(msg.body.motion.getActionId());
}
break;
}
@@ -660,23 +664,28 @@
}
}
-void InputConsumer::rewriteMessage(const TouchState& state, InputMessage* msg) {
- for (uint32_t i = 0; i < msg->body.motion.pointerCount; i++) {
- uint32_t id = msg->body.motion.pointers[i].properties.id;
+bool InputConsumer::rewriteMessage(const TouchState& state, InputMessage& msg) {
+ bool messageRewritten = false;
+ nsecs_t eventTime = msg.body.motion.eventTime;
+ for (uint32_t i = 0; i < msg.body.motion.pointerCount; i++) {
+ uint32_t id = msg.body.motion.pointers[i].properties.id;
if (state.lastResample.idBits.hasBit(id)) {
- PointerCoords& msgCoords = msg->body.motion.pointers[i].coords;
+ PointerCoords& msgCoords = msg.body.motion.pointers[i].coords;
const PointerCoords& resampleCoords = state.lastResample.getPointerById(id);
+ if (eventTime < state.lastResample.eventTime ||
+ state.recentCoordinatesAreIdentical(id)) {
+ msgCoords.setAxisValue(AMOTION_EVENT_AXIS_X, resampleCoords.getX());
+ msgCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, resampleCoords.getY());
#if DEBUG_RESAMPLING
- ALOGD("[%d] - rewrite (%0.3f, %0.3f), old (%0.3f, %0.3f)", id,
- resampleCoords.getAxisValue(AMOTION_EVENT_AXIS_X),
- resampleCoords.getAxisValue(AMOTION_EVENT_AXIS_Y),
- msgCoords.getAxisValue(AMOTION_EVENT_AXIS_X),
- msgCoords.getAxisValue(AMOTION_EVENT_AXIS_Y));
+ ALOGD("[%d] - rewrite (%0.3f, %0.3f), old (%0.3f, %0.3f)", id,
+ resampleCoords.getX(), resampleCoords.getY(),
+ msgCoords.getX(), msgCoords.getY());
#endif
- msgCoords.setAxisValue(AMOTION_EVENT_AXIS_X, resampleCoords.getX());
- msgCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, resampleCoords.getY());
+ messageRewritten = true;
+ }
}
}
+ return messageRewritten;
}
void InputConsumer::resampleTouchState(nsecs_t sampleTime, MotionEvent* event,
@@ -704,6 +713,7 @@
}
// Ensure that the current sample has all of the pointers that need to be reported.
+ // Also ensure that the past two "real" touch events do not contain duplicate coordinates
const History* current = touchState.getHistory(0);
size_t pointerCount = event->getPointerCount();
for (size_t i = 0; i < pointerCount; i++) {
@@ -714,6 +724,12 @@
#endif
return;
}
+ if (touchState.recentCoordinatesAreIdentical(id)) {
+#if DEBUG_RESAMPLING
+ ALOGD("Not resampled, past two historical events have duplicate coordinates");
+#endif
+ return;
+ }
}
// Find the data to use for resampling.
@@ -723,12 +739,12 @@
if (next) {
// Interpolate between current sample and future sample.
// So current->eventTime <= sampleTime <= future.eventTime.
- future.initializeFrom(next);
+ future.initializeFrom(*next);
other = &future;
nsecs_t delta = future.eventTime - current->eventTime;
if (delta < RESAMPLE_MIN_DELTA) {
#if DEBUG_RESAMPLING
- ALOGD("Not resampled, delta time is too small: %lld ns.", delta);
+ ALOGD("Not resampled, delta time is too small: %" PRId64 " ns.", delta);
#endif
return;
}
@@ -740,12 +756,12 @@
nsecs_t delta = current->eventTime - other->eventTime;
if (delta < RESAMPLE_MIN_DELTA) {
#if DEBUG_RESAMPLING
- ALOGD("Not resampled, delta time is too small: %lld ns.", delta);
+ ALOGD("Not resampled, delta time is too small: %" PRId64 " ns.", delta);
#endif
return;
} else if (delta > RESAMPLE_MAX_DELTA) {
#if DEBUG_RESAMPLING
- ALOGD("Not resampled, delta time is too large: %lld ns.", delta);
+ ALOGD("Not resampled, delta time is too large: %" PRId64 " ns.", delta);
#endif
return;
}
@@ -753,7 +769,7 @@
if (sampleTime > maxPredict) {
#if DEBUG_RESAMPLING
ALOGD("Sample time is too far in the future, adjusting prediction "
- "from %lld to %lld ns.",
+ "from %" PRId64 " to %" PRId64 " ns.",
sampleTime - current->eventTime, maxPredict - current->eventTime);
#endif
sampleTime = maxPredict;
diff --git a/libs/input/VelocityTracker.cpp b/libs/input/VelocityTracker.cpp
index 7f6b157..e54f147 100644
--- a/libs/input/VelocityTracker.cpp
+++ b/libs/input/VelocityTracker.cpp
@@ -23,13 +23,14 @@
// Log debug messages about the progress of the algorithm itself.
#define DEBUG_STRATEGY 0
-#include <math.h>
+#include <inttypes.h>
#include <limits.h>
+#include <math.h>
+#include <android-base/stringprintf.h>
#include <cutils/properties.h>
#include <input/VelocityTracker.h>
#include <utils/BitSet.h>
-#include <utils/String8.h>
#include <utils/Timers.h>
namespace android {
@@ -46,8 +47,7 @@
static float vectorDot(const float* a, const float* b, uint32_t m) {
float r = 0;
- while (m) {
- m--;
+ for (size_t i = 0; i < m; i++) {
r += *(a++) * *(b++);
}
return r;
@@ -55,8 +55,7 @@
static float vectorNorm(const float* a, uint32_t m) {
float r = 0;
- while (m) {
- m--;
+ for (size_t i = 0; i < m; i++) {
float t = *(a++);
r += t * t;
}
@@ -64,36 +63,38 @@
}
#if DEBUG_STRATEGY || DEBUG_VELOCITY
-static String8 vectorToString(const float* a, uint32_t m) {
- String8 str;
- str.append("[");
- while (m--) {
- str.appendFormat(" %f", *(a++));
- if (m) {
- str.append(",");
- }
- }
- str.append(" ]");
- return str;
-}
-
-static String8 matrixToString(const float* a, uint32_t m, uint32_t n, bool rowMajor) {
- String8 str;
- str.append("[");
+static std::string vectorToString(const float* a, uint32_t m) {
+ std::string str;
+ str += "[";
for (size_t i = 0; i < m; i++) {
if (i) {
- str.append(",");
+ str += ",";
}
- str.append(" [");
+ str += android::base::StringPrintf(" %f", *(a++));
+ }
+ str += " ]";
+ return str;
+}
+#endif
+
+#if DEBUG_STRATEGY
+static std::string matrixToString(const float* a, uint32_t m, uint32_t n, bool rowMajor) {
+ std::string str;
+ str = "[";
+ for (size_t i = 0; i < m; i++) {
+ if (i) {
+ str += ",";
+ }
+ str += " [";
for (size_t j = 0; j < n; j++) {
if (j) {
- str.append(",");
+ str += ",";
}
- str.appendFormat(" %f", a[rowMajor ? i * n + j : j * m + i]);
+ str += android::base::StringPrintf(" %f", a[rowMajor ? i * n + j : j * m + i]);
}
- str.append(" ]");
+ str += " ]";
}
- str.append(" ]");
+ str += " ]";
return str;
}
#endif
@@ -142,6 +143,11 @@
}
VelocityTrackerStrategy* VelocityTracker::createStrategy(const char* strategy) {
+ if (!strcmp("impulse", strategy)) {
+ // Physical model of pushing an object. Quality: VERY GOOD.
+ // Works with duplicate coordinates, unclean finger liftoff.
+ return new ImpulseVelocityTrackerStrategy();
+ }
if (!strcmp("lsq1", strategy)) {
// 1st order least squares. Quality: POOR.
// Frequently underfits the touch data especially when the finger accelerates
@@ -244,7 +250,7 @@
mStrategy->addMovement(eventTime, idBits, positions);
#if DEBUG_VELOCITY
- ALOGD("VelocityTracker: addMovement eventTime=%lld, idBits=0x%08x, activePointerId=%d",
+ ALOGD("VelocityTracker: addMovement eventTime=%" PRId64 ", idBits=0x%08x, activePointerId=%d",
eventTime, idBits.value, mActivePointerId);
for (BitSet32 iterBits(idBits); !iterBits.isEmpty(); ) {
uint32_t id = iterBits.firstMarkedBit();
@@ -256,8 +262,8 @@
"estimator (degree=%d, xCoeff=%s, yCoeff=%s, confidence=%f)",
id, positions[index].x, positions[index].y,
int(estimator.degree),
- vectorToString(estimator.xCoeff, estimator.degree + 1).string(),
- vectorToString(estimator.yCoeff, estimator.degree + 1).string(),
+ vectorToString(estimator.xCoeff, estimator.degree + 1).c_str(),
+ vectorToString(estimator.yCoeff, estimator.degree + 1).c_str(),
estimator.confidence);
}
#endif
@@ -353,9 +359,6 @@
// --- LeastSquaresVelocityTrackerStrategy ---
-const nsecs_t LeastSquaresVelocityTrackerStrategy::HORIZON;
-const uint32_t LeastSquaresVelocityTrackerStrategy::HISTORY_SIZE;
-
LeastSquaresVelocityTrackerStrategy::LeastSquaresVelocityTrackerStrategy(
uint32_t degree, Weighting weighting) :
mDegree(degree), mWeighting(weighting) {
@@ -443,8 +446,8 @@
const float* w, uint32_t m, uint32_t n, float* outB, float* outDet) {
#if DEBUG_STRATEGY
ALOGD("solveLeastSquares: m=%d, n=%d, x=%s, y=%s, w=%s", int(m), int(n),
- vectorToString(x, m).string(), vectorToString(y, m).string(),
- vectorToString(w, m).string());
+ vectorToString(x, m).c_str(), vectorToString(y, m).c_str(),
+ vectorToString(w, m).c_str());
#endif
// Expand the X vector to a matrix A, pre-multiplied by the weights.
@@ -456,7 +459,7 @@
}
}
#if DEBUG_STRATEGY
- ALOGD(" - a=%s", matrixToString(&a[0][0], m, n, false /*rowMajor*/).string());
+ ALOGD(" - a=%s", matrixToString(&a[0][0], m, n, false /*rowMajor*/).c_str());
#endif
// Apply the Gram-Schmidt process to A to obtain its QR decomposition.
@@ -491,8 +494,8 @@
}
}
#if DEBUG_STRATEGY
- ALOGD(" - q=%s", matrixToString(&q[0][0], m, n, false /*rowMajor*/).string());
- ALOGD(" - r=%s", matrixToString(&r[0][0], n, n, true /*rowMajor*/).string());
+ ALOGD(" - q=%s", matrixToString(&q[0][0], m, n, false /*rowMajor*/).c_str());
+ ALOGD(" - r=%s", matrixToString(&r[0][0], n, n, true /*rowMajor*/).c_str());
// calculate QR, if we factored A correctly then QR should equal A
float qr[n][m];
@@ -504,7 +507,7 @@
}
}
}
- ALOGD(" - qr=%s", matrixToString(&qr[0][0], m, n, false /*rowMajor*/).string());
+ ALOGD(" - qr=%s", matrixToString(&qr[0][0], m, n, false /*rowMajor*/).c_str());
#endif
// Solve R B = Qt W Y to find B. This is easy because R is upper triangular.
@@ -522,7 +525,7 @@
outB[i] /= r[i][i];
}
#if DEBUG_STRATEGY
- ALOGD(" - b=%s", vectorToString(outB, n).string());
+ ALOGD(" - b=%s", vectorToString(outB, n).c_str());
#endif
// Calculate the coefficient of determination as 1 - (SSerr / SStot) where
@@ -557,6 +560,46 @@
return true;
}
+/*
+ * Optimized unweighted second-order least squares fit. About 2x speed improvement compared to
+ * the default implementation
+ */
+static float solveUnweightedLeastSquaresDeg2(const float* x, const float* y, size_t count) {
+ float sxi = 0, sxiyi = 0, syi = 0, sxi2 = 0, sxi3 = 0, sxi2yi = 0, sxi4 = 0;
+
+ for (size_t i = 0; i < count; i++) {
+ float xi = x[i];
+ float yi = y[i];
+ float xi2 = xi*xi;
+ float xi3 = xi2*xi;
+ float xi4 = xi3*xi;
+ float xi2yi = xi2*yi;
+ float xiyi = xi*yi;
+
+ sxi += xi;
+ sxi2 += xi2;
+ sxiyi += xiyi;
+ sxi2yi += xi2yi;
+ syi += yi;
+ sxi3 += xi3;
+ sxi4 += xi4;
+ }
+
+ float Sxx = sxi2 - sxi*sxi / count;
+ float Sxy = sxiyi - sxi*syi / count;
+ float Sxx2 = sxi3 - sxi*sxi2 / count;
+ float Sx2y = sxi2yi - sxi2*syi / count;
+ float Sx2x2 = sxi4 - sxi2*sxi2 / count;
+
+ float numerator = Sxy*Sx2x2 - Sx2y*Sxx2;
+ float denominator = Sxx*Sx2x2 - Sxx2*Sxx2;
+ if (denominator == 0) {
+ ALOGW("division by 0 when computing velocity, Sxx=%f, Sx2x2=%f, Sxx2=%f", Sxx, Sx2x2, Sxx2);
+ return 0;
+ }
+ return numerator/denominator;
+}
+
bool LeastSquaresVelocityTrackerStrategy::getEstimator(uint32_t id,
VelocityTracker::Estimator* outEstimator) const {
outEstimator->clear();
@@ -598,6 +641,19 @@
degree = m - 1;
}
if (degree >= 1) {
+ if (degree == 2 && mWeighting == WEIGHTING_NONE) { // optimize unweighted, degree=2 fit
+ outEstimator->time = newestMovement.eventTime;
+ outEstimator->degree = 2;
+ outEstimator->confidence = 1;
+ outEstimator->xCoeff[0] = 0; // only slope is calculated, set rest of coefficients = 0
+ outEstimator->yCoeff[0] = 0;
+ outEstimator->xCoeff[1] = solveUnweightedLeastSquaresDeg2(time, x, m);
+ outEstimator->yCoeff[1] = solveUnweightedLeastSquaresDeg2(time, y, m);
+ outEstimator->xCoeff[2] = 0;
+ outEstimator->yCoeff[2] = 0;
+ return true;
+ }
+
float xdet, ydet;
uint32_t n = degree + 1;
if (solveLeastSquares(time, x, w, m, n, outEstimator->xCoeff, &xdet)
@@ -608,8 +664,8 @@
#if DEBUG_STRATEGY
ALOGD("estimate: degree=%d, xCoeff=%s, yCoeff=%s, confidence=%f",
int(outEstimator->degree),
- vectorToString(outEstimator->xCoeff, n).string(),
- vectorToString(outEstimator->yCoeff, n).string(),
+ vectorToString(outEstimator->xCoeff, n).c_str(),
+ vectorToString(outEstimator->yCoeff, n).c_str(),
outEstimator->confidence);
#endif
return true;
@@ -811,10 +867,6 @@
// --- LegacyVelocityTrackerStrategy ---
-const nsecs_t LegacyVelocityTrackerStrategy::HORIZON;
-const uint32_t LegacyVelocityTrackerStrategy::HISTORY_SIZE;
-const nsecs_t LegacyVelocityTrackerStrategy::MIN_DURATION;
-
LegacyVelocityTrackerStrategy::LegacyVelocityTrackerStrategy() {
clear();
}
@@ -927,4 +979,194 @@
return true;
}
+// --- ImpulseVelocityTrackerStrategy ---
+
+ImpulseVelocityTrackerStrategy::ImpulseVelocityTrackerStrategy() {
+ clear();
+}
+
+ImpulseVelocityTrackerStrategy::~ImpulseVelocityTrackerStrategy() {
+}
+
+void ImpulseVelocityTrackerStrategy::clear() {
+ mIndex = 0;
+ mMovements[0].idBits.clear();
+}
+
+void ImpulseVelocityTrackerStrategy::clearPointers(BitSet32 idBits) {
+ BitSet32 remainingIdBits(mMovements[mIndex].idBits.value & ~idBits.value);
+ mMovements[mIndex].idBits = remainingIdBits;
+}
+
+void ImpulseVelocityTrackerStrategy::addMovement(nsecs_t eventTime, BitSet32 idBits,
+ const VelocityTracker::Position* positions) {
+ if (++mIndex == HISTORY_SIZE) {
+ mIndex = 0;
+ }
+
+ Movement& movement = mMovements[mIndex];
+ movement.eventTime = eventTime;
+ movement.idBits = idBits;
+ uint32_t count = idBits.count();
+ for (uint32_t i = 0; i < count; i++) {
+ movement.positions[i] = positions[i];
+ }
+}
+
+/**
+ * Calculate the total impulse provided to the screen and the resulting velocity.
+ *
+ * The touchscreen is modeled as a physical object.
+ * Initial condition is discussed below, but for now suppose that v(t=0) = 0
+ *
+ * The kinetic energy of the object at the release is E=0.5*m*v^2
+ * Then vfinal = sqrt(2E/m). The goal is to calculate E.
+ *
+ * The kinetic energy at the release is equal to the total work done on the object by the finger.
+ * The total work W is the sum of all dW along the path.
+ *
+ * dW = F*dx, where dx is the piece of path traveled.
+ * Force is change of momentum over time, F = dp/dt = m dv/dt.
+ * Then substituting:
+ * dW = m (dv/dt) * dx = m * v * dv
+ *
+ * Summing along the path, we get:
+ * W = sum(dW) = sum(m * v * dv) = m * sum(v * dv)
+ * Since the mass stays constant, the equation for final velocity is:
+ * vfinal = sqrt(2*sum(v * dv))
+ *
+ * Here,
+ * dv : change of velocity = (v[i+1]-v[i])
+ * dx : change of distance = (x[i+1]-x[i])
+ * dt : change of time = (t[i+1]-t[i])
+ * v : instantaneous velocity = dx/dt
+ *
+ * The final formula is:
+ * vfinal = sqrt(2) * sqrt(sum((v[i]-v[i-1])*|v[i]|)) for all i
+ * The absolute value is needed to properly account for the sign. If the velocity over a
+ * particular segment descreases, then this indicates braking, which means that negative
+ * work was done. So for two positive, but decreasing, velocities, this contribution would be
+ * negative and will cause a smaller final velocity.
+ *
+ * Initial condition
+ * There are two ways to deal with initial condition:
+ * 1) Assume that v(0) = 0, which would mean that the screen is initially at rest.
+ * This is not entirely accurate. We are only taking the past X ms of touch data, where X is
+ * currently equal to 100. However, a touch event that created a fling probably lasted for longer
+ * than that, which would mean that the user has already been interacting with the touchscreen
+ * and it has probably already been moving.
+ * 2) Assume that the touchscreen has already been moving at a certain velocity, calculate this
+ * initial velocity and the equivalent energy, and start with this initial energy.
+ * Consider an example where we have the following data, consisting of 3 points:
+ * time: t0, t1, t2
+ * x : x0, x1, x2
+ * v : 0 , v1, v2
+ * Here is what will happen in each of these scenarios:
+ * 1) By directly applying the formula above with the v(0) = 0 boundary condition, we will get
+ * vfinal = sqrt(2*(|v1|*(v1-v0) + |v2|*(v2-v1))). This can be simplified since v0=0
+ * vfinal = sqrt(2*(|v1|*v1 + |v2|*(v2-v1))) = sqrt(2*(v1^2 + |v2|*(v2 - v1)))
+ * since velocity is a real number
+ * 2) If we treat the screen as already moving, then it must already have an energy (per mass)
+ * equal to 1/2*v1^2. Then the initial energy should be 1/2*v1*2, and only the second segment
+ * will contribute to the total kinetic energy (since we can effectively consider that v0=v1).
+ * This will give the following expression for the final velocity:
+ * vfinal = sqrt(2*(1/2*v1^2 + |v2|*(v2-v1)))
+ * This analysis can be generalized to an arbitrary number of samples.
+ *
+ *
+ * Comparing the two equations above, we see that the only mathematical difference
+ * is the factor of 1/2 in front of the first velocity term.
+ * This boundary condition would allow for the "proper" calculation of the case when all of the
+ * samples are equally spaced in time and distance, which should suggest a constant velocity.
+ *
+ * Note that approach 2) is sensitive to the proper ordering of the data in time, since
+ * the boundary condition must be applied to the oldest sample to be accurate.
+ */
+static float kineticEnergyToVelocity(float work) {
+ static constexpr float sqrt2 = 1.41421356237;
+ return (work < 0 ? -1.0 : 1.0) * sqrtf(fabsf(work)) * sqrt2;
+}
+
+static float calculateImpulseVelocity(const nsecs_t* t, const float* x, size_t count) {
+ // The input should be in reversed time order (most recent sample at index i=0)
+ // t[i] is in nanoseconds, but due to FP arithmetic, convert to seconds inside this function
+ static constexpr float NANOS_PER_SECOND = 1E-9;
+
+ if (count < 2) {
+ return 0; // if 0 or 1 points, velocity is zero
+ }
+ if (t[1] > t[0]) { // Algorithm will still work, but not perfectly
+ ALOGE("Samples provided to calculateImpulseVelocity in the wrong order");
+ }
+ if (count == 2) { // if 2 points, basic linear calculation
+ if (t[1] == t[0]) {
+ ALOGE("Events have identical time stamps t=%" PRId64 ", setting velocity = 0", t[0]);
+ return 0;
+ }
+ return (x[1] - x[0]) / (NANOS_PER_SECOND * (t[1] - t[0]));
+ }
+ // Guaranteed to have at least 3 points here
+ float work = 0;
+ for (size_t i = count - 1; i > 0 ; i--) { // start with the oldest sample and go forward in time
+ if (t[i] == t[i-1]) {
+ ALOGE("Events have identical time stamps t=%" PRId64 ", skipping sample", t[i]);
+ continue;
+ }
+ float vprev = kineticEnergyToVelocity(work); // v[i-1]
+ float vcurr = (x[i] - x[i-1]) / (NANOS_PER_SECOND * (t[i] - t[i-1])); // v[i]
+ work += (vcurr - vprev) * fabsf(vcurr);
+ if (i == count - 1) {
+ work *= 0.5; // initial condition, case 2) above
+ }
+ }
+ return kineticEnergyToVelocity(work);
+}
+
+bool ImpulseVelocityTrackerStrategy::getEstimator(uint32_t id,
+ VelocityTracker::Estimator* outEstimator) const {
+ outEstimator->clear();
+
+ // Iterate over movement samples in reverse time order and collect samples.
+ float x[HISTORY_SIZE];
+ float y[HISTORY_SIZE];
+ nsecs_t time[HISTORY_SIZE];
+ size_t m = 0; // number of points that will be used for fitting
+ size_t index = mIndex;
+ const Movement& newestMovement = mMovements[mIndex];
+ do {
+ const Movement& movement = mMovements[index];
+ if (!movement.idBits.hasBit(id)) {
+ break;
+ }
+
+ nsecs_t age = newestMovement.eventTime - movement.eventTime;
+ if (age > HORIZON) {
+ break;
+ }
+
+ const VelocityTracker::Position& position = movement.getPosition(id);
+ x[m] = position.x;
+ y[m] = position.y;
+ time[m] = movement.eventTime;
+ index = (index == 0 ? HISTORY_SIZE : index) - 1;
+ } while (++m < HISTORY_SIZE);
+
+ if (m == 0) {
+ return false; // no data
+ }
+ outEstimator->xCoeff[0] = 0;
+ outEstimator->yCoeff[0] = 0;
+ outEstimator->xCoeff[1] = calculateImpulseVelocity(time, x, m);
+ outEstimator->yCoeff[1] = calculateImpulseVelocity(time, y, m);
+ outEstimator->xCoeff[2] = 0;
+ outEstimator->yCoeff[2] = 0;
+ outEstimator->time = newestMovement.eventTime;
+ outEstimator->degree = 2; // similar results to 2nd degree fit
+ outEstimator->confidence = 1;
+#if DEBUG_STRATEGY
+ ALOGD("velocity: (%f, %f)", outEstimator->xCoeff[1], outEstimator->yCoeff[1]);
+#endif
+ return true;
+}
+
} // namespace android
diff --git a/libs/input/tests/Android.bp b/libs/input/tests/Android.bp
index 029a420..aca9521 100644
--- a/libs/input/tests/Android.bp
+++ b/libs/input/tests/Android.bp
@@ -6,6 +6,13 @@
"InputChannel_test.cpp",
"InputEvent_test.cpp",
"InputPublisherAndConsumer_test.cpp",
+ "VelocityTracker_test.cpp",
+ ],
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+ "-Wno-unused-variable",
],
shared_libs: [
"libinput",
@@ -13,6 +20,7 @@
"libutils",
"libbinder",
"libui",
+ "libbase",
]
}
@@ -24,5 +32,7 @@
srcs: ["StructLayout_test.cpp"],
cflags: [
"-O0",
+ "-Wall",
+ "-Werror",
],
}
diff --git a/libs/input/tests/InputEvent_test.cpp b/libs/input/tests/InputEvent_test.cpp
index 3fb1c6d..fd3b7c8 100644
--- a/libs/input/tests/InputEvent_test.cpp
+++ b/libs/input/tests/InputEvent_test.cpp
@@ -184,7 +184,7 @@
ASSERT_EQ(AINPUT_EVENT_TYPE_KEY, event.getType());
ASSERT_EQ(2, event.getDeviceId());
- ASSERT_EQ(AINPUT_SOURCE_GAMEPAD, event.getSource());
+ ASSERT_EQ(static_cast<int>(AINPUT_SOURCE_GAMEPAD), event.getSource());
ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, event.getAction());
ASSERT_EQ(AKEY_EVENT_FLAG_FROM_SYSTEM, event.getFlags());
ASSERT_EQ(AKEYCODE_BUTTON_X, event.getKeyCode());
@@ -196,7 +196,7 @@
// Set source.
event.setSource(AINPUT_SOURCE_JOYSTICK);
- ASSERT_EQ(AINPUT_SOURCE_JOYSTICK, event.getSource());
+ ASSERT_EQ(static_cast<int>(AINPUT_SOURCE_JOYSTICK), event.getSource());
}
@@ -300,7 +300,7 @@
// Check properties.
ASSERT_EQ(AINPUT_EVENT_TYPE_MOTION, event->getType());
ASSERT_EQ(2, event->getDeviceId());
- ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, event->getSource());
+ ASSERT_EQ(static_cast<int>(AINPUT_SOURCE_TOUCHSCREEN), event->getSource());
ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, event->getAction());
ASSERT_EQ(AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED, event->getFlags());
ASSERT_EQ(AMOTION_EVENT_EDGE_FLAG_TOP, event->getEdgeFlags());
@@ -432,7 +432,7 @@
// Set source.
event.setSource(AINPUT_SOURCE_JOYSTICK);
- ASSERT_EQ(AINPUT_SOURCE_JOYSTICK, event.getSource());
+ ASSERT_EQ(static_cast<int>(AINPUT_SOURCE_JOYSTICK), event.getSource());
// Set action.
event.setAction(AMOTION_EVENT_ACTION_CANCEL);
diff --git a/libs/input/tests/InputPublisherAndConsumer_test.cpp b/libs/input/tests/InputPublisherAndConsumer_test.cpp
index 8e69c9c..34c52d0 100644
--- a/libs/input/tests/InputPublisherAndConsumer_test.cpp
+++ b/libs/input/tests/InputPublisherAndConsumer_test.cpp
@@ -89,7 +89,9 @@
uint32_t consumeSeq;
InputEvent* event;
- status = mConsumer->consume(&mEventFactory, true /*consumeBatches*/, -1, &consumeSeq, &event);
+ int32_t displayId;
+ status = mConsumer->consume(&mEventFactory, true /*consumeBatches*/, -1, &consumeSeq, &event,
+ &displayId);
ASSERT_EQ(OK, status)
<< "consumer consume should return OK";
@@ -132,6 +134,7 @@
const uint32_t seq = 15;
const int32_t deviceId = 1;
const int32_t source = AINPUT_SOURCE_TOUCHSCREEN;
+ int32_t displayId = 0;
const int32_t action = AMOTION_EVENT_ACTION_MOVE;
const int32_t actionButton = 0;
const int32_t flags = AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED;
@@ -164,7 +167,7 @@
pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 3.5 * i);
}
- status = mPublisher->publishMotionEvent(seq, deviceId, source, action, actionButton,
+ status = mPublisher->publishMotionEvent(seq, deviceId, source, displayId, action, actionButton,
flags, edgeFlags, metaState, buttonState, xOffset, yOffset, xPrecision, yPrecision,
downTime, eventTime, pointerCount,
pointerProperties, pointerCoords);
@@ -173,7 +176,8 @@
uint32_t consumeSeq;
InputEvent* event;
- status = mConsumer->consume(&mEventFactory, true /*consumeBatches*/, -1, &consumeSeq, &event);
+ status = mConsumer->consume(&mEventFactory, true /*consumeBatches*/, -1, &consumeSeq, &event,
+ &displayId);
ASSERT_EQ(OK, status)
<< "consumer consume should return OK";
@@ -256,7 +260,7 @@
PointerProperties pointerProperties[pointerCount];
PointerCoords pointerCoords[pointerCount];
- status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
pointerCount, pointerProperties, pointerCoords);
ASSERT_EQ(BAD_VALUE, status)
<< "publisher publishMotionEvent should return BAD_VALUE";
@@ -272,7 +276,7 @@
pointerCoords[i].clear();
}
- status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
pointerCount, pointerProperties, pointerCoords);
ASSERT_EQ(BAD_VALUE, status)
<< "publisher publishMotionEvent should return BAD_VALUE";
diff --git a/libs/input/tests/StructLayout_test.cpp b/libs/input/tests/StructLayout_test.cpp
index 81b9953..d19f3b8 100644
--- a/libs/input/tests/StructLayout_test.cpp
+++ b/libs/input/tests/StructLayout_test.cpp
@@ -38,31 +38,33 @@
CHECK_OFFSET(InputMessage::Body::Key, eventTime, 8);
CHECK_OFFSET(InputMessage::Body::Key, deviceId, 16);
CHECK_OFFSET(InputMessage::Body::Key, source, 20);
- CHECK_OFFSET(InputMessage::Body::Key, action, 24);
- CHECK_OFFSET(InputMessage::Body::Key, flags, 28);
- CHECK_OFFSET(InputMessage::Body::Key, keyCode, 32);
- CHECK_OFFSET(InputMessage::Body::Key, scanCode, 36);
- CHECK_OFFSET(InputMessage::Body::Key, metaState, 40);
- CHECK_OFFSET(InputMessage::Body::Key, repeatCount, 44);
- CHECK_OFFSET(InputMessage::Body::Key, downTime, 48);
+ CHECK_OFFSET(InputMessage::Body::Key, displayId, 24);
+ CHECK_OFFSET(InputMessage::Body::Key, action, 28);
+ CHECK_OFFSET(InputMessage::Body::Key, flags, 32);
+ CHECK_OFFSET(InputMessage::Body::Key, keyCode, 36);
+ CHECK_OFFSET(InputMessage::Body::Key, scanCode, 40);
+ CHECK_OFFSET(InputMessage::Body::Key, metaState, 44);
+ CHECK_OFFSET(InputMessage::Body::Key, repeatCount, 48);
+ CHECK_OFFSET(InputMessage::Body::Key, downTime, 56);
CHECK_OFFSET(InputMessage::Body::Motion, seq, 0);
CHECK_OFFSET(InputMessage::Body::Motion, eventTime, 8);
CHECK_OFFSET(InputMessage::Body::Motion, deviceId, 16);
CHECK_OFFSET(InputMessage::Body::Motion, source, 20);
- CHECK_OFFSET(InputMessage::Body::Motion, action, 24);
- CHECK_OFFSET(InputMessage::Body::Motion, actionButton, 28);
- CHECK_OFFSET(InputMessage::Body::Motion, flags, 32);
- CHECK_OFFSET(InputMessage::Body::Motion, metaState, 36);
- CHECK_OFFSET(InputMessage::Body::Motion, buttonState, 40);
- CHECK_OFFSET(InputMessage::Body::Motion, edgeFlags, 44);
- CHECK_OFFSET(InputMessage::Body::Motion, downTime, 48);
- CHECK_OFFSET(InputMessage::Body::Motion, xOffset, 56);
- CHECK_OFFSET(InputMessage::Body::Motion, yOffset, 60);
- CHECK_OFFSET(InputMessage::Body::Motion, xPrecision, 64);
- CHECK_OFFSET(InputMessage::Body::Motion, yPrecision, 68);
- CHECK_OFFSET(InputMessage::Body::Motion, pointerCount, 72);
- CHECK_OFFSET(InputMessage::Body::Motion, pointers, 80);
+ CHECK_OFFSET(InputMessage::Body::Motion, displayId, 24);
+ CHECK_OFFSET(InputMessage::Body::Motion, action, 28);
+ CHECK_OFFSET(InputMessage::Body::Motion, actionButton, 32);
+ CHECK_OFFSET(InputMessage::Body::Motion, flags, 36);
+ CHECK_OFFSET(InputMessage::Body::Motion, metaState, 40);
+ CHECK_OFFSET(InputMessage::Body::Motion, buttonState, 44);
+ CHECK_OFFSET(InputMessage::Body::Motion, edgeFlags, 48);
+ CHECK_OFFSET(InputMessage::Body::Motion, downTime, 56);
+ CHECK_OFFSET(InputMessage::Body::Motion, xOffset, 64);
+ CHECK_OFFSET(InputMessage::Body::Motion, yOffset, 68);
+ CHECK_OFFSET(InputMessage::Body::Motion, xPrecision, 72);
+ CHECK_OFFSET(InputMessage::Body::Motion, yPrecision, 76);
+ CHECK_OFFSET(InputMessage::Body::Motion, pointerCount, 80);
+ CHECK_OFFSET(InputMessage::Body::Motion, pointers, 88);
}
} // namespace android
diff --git a/libs/input/tests/VelocityTracker_test.cpp b/libs/input/tests/VelocityTracker_test.cpp
new file mode 100644
index 0000000..43b6012
--- /dev/null
+++ b/libs/input/tests/VelocityTracker_test.cpp
@@ -0,0 +1,664 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#define LOG_TAG "VelocityTracker_test"
+
+#include <math.h>
+
+#include <android-base/stringprintf.h>
+#include <gtest/gtest.h>
+#include <input/VelocityTracker.h>
+
+using android::base::StringPrintf;
+
+namespace android {
+
+constexpr int32_t DEFAULT_POINTER_ID = 0; // pointer ID used for manually defined tests
+
+// velocity must be in the range (1-tol)*EV <= velocity <= (1+tol)*EV
+// here EV = expected value, tol = VELOCITY_TOLERANCE
+constexpr float VELOCITY_TOLERANCE = 0.2;
+
+// --- VelocityTrackerTest ---
+class VelocityTrackerTest : public testing::Test { };
+
+static void checkVelocity(float Vactual, float Vtarget) {
+ // Compare directions
+ if ((Vactual > 0 && Vtarget <= 0) || (Vactual < 0 && Vtarget >= 0)) {
+ FAIL() << StringPrintf("Velocity %f does not have the same direction"
+ " as the target velocity %f", Vactual, Vtarget);
+ }
+
+ // Compare magnitudes
+ const float Vlower = fabsf(Vtarget * (1 - VELOCITY_TOLERANCE));
+ const float Vupper = fabsf(Vtarget * (1 + VELOCITY_TOLERANCE));
+ if (fabsf(Vactual) < Vlower) {
+ FAIL() << StringPrintf("Velocity %f is more than %.0f%% below target velocity %f",
+ Vactual, VELOCITY_TOLERANCE * 100, Vtarget);
+ }
+ if (fabsf(Vactual) > Vupper) {
+ FAIL() << StringPrintf("Velocity %f is more than %.0f%% above target velocity %f",
+ Vactual, VELOCITY_TOLERANCE * 100, Vtarget);
+ }
+ SUCCEED() << StringPrintf("Velocity %f within %.0f%% of target %f)",
+ Vactual, VELOCITY_TOLERANCE * 100, Vtarget);
+}
+
+void failWithMessage(std::string message) {
+ FAIL() << message; // cannot do this directly from a non-void function
+}
+
+struct Position {
+ nsecs_t time;
+ float x;
+ float y;
+};
+
+
+MotionEvent* createSimpleMotionEvent(const Position* positions, size_t numSamples) {
+ /**
+ * Only populate the basic fields of a MotionEvent, such as time and a single axis
+ * Designed for use with manually-defined tests.
+ * Create a new MotionEvent on the heap, caller responsible for destroying the object.
+ */
+ if (numSamples < 1) {
+ failWithMessage(StringPrintf("Need at least 1 sample to create a MotionEvent."
+ " Received numSamples=%zu", numSamples));
+ }
+
+ MotionEvent* event = new MotionEvent();
+ PointerCoords coords;
+ PointerProperties properties[1];
+
+ properties[0].id = DEFAULT_POINTER_ID;
+ properties[0].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER;
+
+ // First sample added separately with initialize
+ coords.setAxisValue(AMOTION_EVENT_AXIS_X, positions[0].x);
+ coords.setAxisValue(AMOTION_EVENT_AXIS_Y, positions[0].y);
+ event->initialize(0, AINPUT_SOURCE_TOUCHSCREEN, AMOTION_EVENT_ACTION_MOVE,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, positions[0].time, 1, properties, &coords);
+
+ for (size_t i = 1; i < numSamples; i++) {
+ coords.setAxisValue(AMOTION_EVENT_AXIS_X, positions[i].x);
+ coords.setAxisValue(AMOTION_EVENT_AXIS_Y, positions[i].y);
+ event->addSample(positions[i].time, &coords);
+ }
+ return event;
+}
+
+static void computeAndCheckVelocity(const Position* positions, size_t numSamples,
+ int32_t axis, float targetVelocity) {
+ VelocityTracker vt(nullptr);
+ float Vx, Vy;
+
+ MotionEvent* event = createSimpleMotionEvent(positions, numSamples);
+ vt.addMovement(event);
+
+ vt.getVelocity(DEFAULT_POINTER_ID, &Vx, &Vy);
+
+ switch (axis) {
+ case AMOTION_EVENT_AXIS_X:
+ checkVelocity(Vx, targetVelocity);
+ break;
+ case AMOTION_EVENT_AXIS_Y:
+ checkVelocity(Vy, targetVelocity);
+ break;
+ default:
+ FAIL() << "Axis must be either AMOTION_EVENT_AXIS_X or AMOTION_EVENT_AXIS_Y";
+ }
+ delete event;
+}
+
+/*
+ * ================== VelocityTracker tests generated manually =====================================
+ */
+ // @todo Currently disabled, enable when switching away from lsq2 VelocityTrackerStrategy
+TEST_F(VelocityTrackerTest, DISABLED_ThreePointsPositiveVelocityTest) {
+ // Same coordinate is reported 2 times in a row
+ // It is difficult to determine the correct answer here, but at least the direction
+ // of the reported velocity should be positive.
+ Position values[] = {
+ { 0, 273, NAN },
+ { 12585000, 293, NAN },
+ { 14730000, 293, NAN },
+ };
+ size_t count = sizeof(values) / sizeof(Position);
+ computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, 1600);
+}
+
+TEST_F(VelocityTrackerTest, ThreePointsZeroVelocityTest) {
+ // Same coordinate is reported 3 times in a row
+ Position values[] = {
+ { 0, 293, NAN },
+ { 6132000, 293, NAN },
+ { 11283000, 293, NAN },
+ };
+ size_t count = sizeof(values) / sizeof(Position);
+ computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, 0);
+}
+
+TEST_F(VelocityTrackerTest, ThreePointsLinearVelocityTest) {
+ // Fixed velocity at 5 points per 10 milliseconds
+ Position values[] = {
+ { 0, 0, NAN },
+ { 10000000, 5, NAN },
+ { 20000000, 10, NAN },
+ };
+ size_t count = sizeof(values) / sizeof(Position);
+ computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, 500);
+}
+
+
+/**
+ * ================== VelocityTracker tests generated by recording real events =====================
+ *
+ * To add a test, record the input coordinates and event times to all calls
+ * to void VelocityTracker::addMovement(const MotionEvent* event).
+ * Also record all calls to VelocityTracker::clear().
+ * Finally, record the output of VelocityTracker::getVelocity(...)
+ * This will give you the necessary data to create a new test.
+ */
+
+// --------------- Recorded by hand on swordfish ---------------------------------------------------
+// @todo Currently disabled, enable when switching away from lsq2 VelocityTrackerStrategy
+TEST_F(VelocityTrackerTest, DISABLED_SwordfishFlingDown) {
+ // Recording of a fling on Swordfish that could cause a fling in the wrong direction
+ Position values[] = {
+ { 0, 271, 96 },
+ { 16071042, 269.786346, 106.922775 },
+ { 35648403, 267.983063, 156.660034 },
+ { 52313925, 262.638397, 220.339081 },
+ { 68976522, 266.138824, 331.581116 },
+ { 85639375, 274.79245, 428.113159 },
+ { 96948871, 274.79245, 428.113159 },
+ };
+ size_t count = sizeof(values) / sizeof(Position);
+ computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, 623.577637);
+ computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 8523.348633);
+}
+
+// --------------- Recorded by hand on sailfish, generated by a script -----------------------------
+// For some of these tests, the X-direction velocity checking has been removed, because the lsq2
+// and the impulse VelocityTrackerStrategies did not agree within 20%.
+// Since the flings were recorded in the Y-direction, the intentional user action should only
+// be relevant for the Y axis.
+// There have been also cases where lsq2 and impulse disagreed more than 20% in the Y-direction.
+// Those recordings have been discarded because we didn't feel one strategy's interpretation was
+// more correct than another's but didn't want to increase the tolerance for the entire test suite.
+//
+// There are 18 tests total below: 9 in the positive Y direction and 9 in the opposite.
+// The recordings were loosely binned into 3 categories - slow, faster, and fast, which roughly
+// characterizes the velocity of the finger motion.
+// These can be treated approximately as:
+// slow - less than 1 page gets scrolled
+// faster - more than 1 page gets scrolled, but less than 3
+// fast - entire list is scrolled (fling is done as hard as possible)
+
+TEST_F(VelocityTrackerTest, SailfishFlingUpSlow1) {
+ // Sailfish - fling up - slow - 1
+ Position values[] = {
+ { 235089067457000, 528.00, 983.00 },
+ { 235089084684000, 527.00, 981.00 },
+ { 235089093349000, 527.00, 977.00 },
+ { 235089095677625, 527.00, 975.93 },
+ { 235089101859000, 527.00, 970.00 },
+ { 235089110378000, 528.00, 960.00 },
+ { 235089112497111, 528.25, 957.51 },
+ { 235089118760000, 531.00, 946.00 },
+ { 235089126686000, 535.00, 931.00 },
+ { 235089129316820, 536.33, 926.02 },
+ { 235089135199000, 540.00, 914.00 },
+ { 235089144297000, 546.00, 896.00 },
+ { 235089146136443, 547.21, 892.36 },
+ { 235089152923000, 553.00, 877.00 },
+ { 235089160784000, 559.00, 851.00 },
+ { 235089162955851, 560.66, 843.82 },
+ };
+ size_t count = sizeof(values) / sizeof(Position);
+ computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, 872.794617); // impulse
+ computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, 951.698181); // lsq2
+ computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -3604.819336); // impulse
+ computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -3044.966064); // lsq2
+}
+
+
+TEST_F(VelocityTrackerTest, SailfishFlingUpSlow2) {
+ // Sailfish - fling up - slow - 2
+ Position values[] = {
+ { 235110560704000, 522.00, 1107.00 },
+ { 235110575764000, 522.00, 1107.00 },
+ { 235110584385000, 522.00, 1107.00 },
+ { 235110588421179, 521.52, 1106.52 },
+ { 235110592830000, 521.00, 1106.00 },
+ { 235110601385000, 520.00, 1104.00 },
+ { 235110605088160, 519.14, 1102.27 },
+ { 235110609952000, 518.00, 1100.00 },
+ { 235110618353000, 517.00, 1093.00 },
+ { 235110621755146, 516.60, 1090.17 },
+ { 235110627010000, 517.00, 1081.00 },
+ { 235110634785000, 518.00, 1063.00 },
+ { 235110638422450, 518.87, 1052.58 },
+ { 235110643161000, 520.00, 1039.00 },
+ { 235110651767000, 524.00, 1011.00 },
+ { 235110655089581, 525.54, 1000.19 },
+ { 235110660368000, 530.00, 980.00 },
+ };
+ size_t count = sizeof(values) / sizeof(Position);
+ computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -4096.583008); // impulse
+ computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -3455.094238); // lsq2
+}
+
+
+TEST_F(VelocityTrackerTest, SailfishFlingUpSlow3) {
+ // Sailfish - fling up - slow - 3
+ Position values[] = {
+ { 792536237000, 580.00, 1317.00 },
+ { 792541538987, 580.63, 1311.94 },
+ { 792544613000, 581.00, 1309.00 },
+ { 792552301000, 583.00, 1295.00 },
+ { 792558362309, 585.13, 1282.92 },
+ { 792560828000, 586.00, 1278.00 },
+ { 792569446000, 589.00, 1256.00 },
+ { 792575185095, 591.54, 1241.41 },
+ { 792578491000, 593.00, 1233.00 },
+ { 792587044000, 597.00, 1211.00 },
+ { 792592008172, 600.28, 1195.92 },
+ { 792594616000, 602.00, 1188.00 },
+ { 792603129000, 607.00, 1167.00 },
+ { 792608831290, 609.48, 1155.83 },
+ { 792612321000, 611.00, 1149.00 },
+ { 792620768000, 615.00, 1131.00 },
+ { 792625653873, 617.32, 1121.73 },
+ { 792629200000, 619.00, 1115.00 },
+ };
+ size_t count = sizeof(values) / sizeof(Position);
+ computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, 574.33429); // impulse
+ computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, 617.40564); // lsq2
+ computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -2361.982666); // impulse
+ computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -2500.055664); // lsq2
+}
+
+
+TEST_F(VelocityTrackerTest, SailfishFlingUpFaster1) {
+ // Sailfish - fling up - faster - 1
+ Position values[] = {
+ { 235160420675000, 610.00, 1042.00 },
+ { 235160428220000, 609.00, 1026.00 },
+ { 235160436544000, 609.00, 1024.00 },
+ { 235160441852394, 609.64, 1020.82 },
+ { 235160444878000, 610.00, 1019.00 },
+ { 235160452673000, 613.00, 1006.00 },
+ { 235160458519743, 617.18, 992.06 },
+ { 235160461061000, 619.00, 986.00 },
+ { 235160469798000, 627.00, 960.00 },
+ { 235160475186713, 632.22, 943.02 },
+ { 235160478051000, 635.00, 934.00 },
+ { 235160486489000, 644.00, 906.00 },
+ { 235160491853697, 649.56, 890.56 },
+ { 235160495177000, 653.00, 881.00 },
+ { 235160504148000, 662.00, 858.00 },
+ { 235160509231495, 666.81, 845.37 },
+ { 235160512603000, 670.00, 837.00 },
+ { 235160520366000, 679.00, 814.00 },
+ };
+ size_t count = sizeof(values) / sizeof(Position);
+ computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, 1274.141724); // impulse
+ computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, 1438.53186); // lsq2
+ computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -3877.35498); // impulse
+ computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -3695.859619); // lsq2
+}
+
+
+TEST_F(VelocityTrackerTest, SailfishFlingUpFaster2) {
+ // Sailfish - fling up - faster - 2
+ Position values[] = {
+ { 847153808000, 576.00, 1264.00 },
+ { 847171174000, 576.00, 1262.00 },
+ { 847179640000, 576.00, 1257.00 },
+ { 847185187540, 577.41, 1249.22 },
+ { 847187487000, 578.00, 1246.00 },
+ { 847195710000, 581.00, 1227.00 },
+ { 847202027059, 583.93, 1209.40 },
+ { 847204324000, 585.00, 1203.00 },
+ { 847212672000, 590.00, 1176.00 },
+ { 847218861395, 594.36, 1157.11 },
+ { 847221190000, 596.00, 1150.00 },
+ { 847230484000, 602.00, 1124.00 },
+ { 847235701400, 607.56, 1103.83 },
+ { 847237986000, 610.00, 1095.00 },
+ };
+ size_t count = sizeof(values) / sizeof(Position);
+ computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -4280.07959); // impulse
+ computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -4241.004395); // lsq2
+}
+
+
+TEST_F(VelocityTrackerTest, SailfishFlingUpFaster3) {
+ // Sailfish - fling up - faster - 3
+ Position values[] = {
+ { 235200532789000, 507.00, 1084.00 },
+ { 235200549221000, 507.00, 1083.00 },
+ { 235200557841000, 507.00, 1081.00 },
+ { 235200558051189, 507.00, 1080.95 },
+ { 235200566314000, 507.00, 1078.00 },
+ { 235200574876586, 508.97, 1070.12 },
+ { 235200575006000, 509.00, 1070.00 },
+ { 235200582900000, 514.00, 1054.00 },
+ { 235200591276000, 525.00, 1023.00 },
+ { 235200591701829, 525.56, 1021.42 },
+ { 235200600064000, 542.00, 976.00 },
+ { 235200608519000, 563.00, 911.00 },
+ { 235200608527086, 563.02, 910.94 },
+ { 235200616933000, 590.00, 844.00 },
+ };
+ size_t count = sizeof(values) / sizeof(Position);
+ computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -8715.686523); // impulse
+ computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -7639.026367); // lsq2
+}
+
+
+TEST_F(VelocityTrackerTest, SailfishFlingUpFast1) {
+ // Sailfish - fling up - fast - 1
+ Position values[] = {
+ { 920922149000, 561.00, 1412.00 },
+ { 920930185000, 559.00, 1377.00 },
+ { 920930262463, 558.98, 1376.66 },
+ { 920938547000, 559.00, 1371.00 },
+ { 920947096857, 562.91, 1342.68 },
+ { 920947302000, 563.00, 1342.00 },
+ { 920955502000, 577.00, 1272.00 },
+ { 920963931021, 596.87, 1190.54 },
+ { 920963987000, 597.00, 1190.00 },
+ { 920972530000, 631.00, 1093.00 },
+ { 920980765511, 671.31, 994.68 },
+ { 920980906000, 672.00, 993.00 },
+ { 920989261000, 715.00, 903.00 },
+ };
+ size_t count = sizeof(values) / sizeof(Position);
+ computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, 5670.329102); // impulse
+ computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, 5991.866699); // lsq2
+ computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -13021.101562); // impulse
+ computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -15093.995117); // lsq2
+}
+
+
+TEST_F(VelocityTrackerTest, SailfishFlingUpFast2) {
+ // Sailfish - fling up - fast - 2
+ Position values[] = {
+ { 235247153233000, 518.00, 1168.00 },
+ { 235247170452000, 517.00, 1167.00 },
+ { 235247178908000, 515.00, 1159.00 },
+ { 235247179556213, 514.85, 1158.39 },
+ { 235247186821000, 515.00, 1125.00 },
+ { 235247195265000, 521.00, 1051.00 },
+ { 235247196389476, 521.80, 1041.15 },
+ { 235247203649000, 538.00, 932.00 },
+ { 235247212253000, 571.00, 794.00 },
+ { 235247213222491, 574.72, 778.45 },
+ { 235247220736000, 620.00, 641.00 },
+ };
+ size_t count = sizeof(values) / sizeof(Position);
+ computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -20286.958984); // impulse
+ computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -20494.587891); // lsq2
+}
+
+
+TEST_F(VelocityTrackerTest, SailfishFlingUpFast3) {
+ // Sailfish - fling up - fast - 3
+ Position values[] = {
+ { 235302568736000, 529.00, 1167.00 },
+ { 235302576644000, 523.00, 1140.00 },
+ { 235302579395063, 520.91, 1130.61 },
+ { 235302585140000, 522.00, 1130.00 },
+ { 235302593615000, 527.00, 1065.00 },
+ { 235302596207444, 528.53, 1045.12 },
+ { 235302602102000, 559.00, 872.00 },
+ { 235302610545000, 652.00, 605.00 },
+ { 235302613019881, 679.26, 526.73 },
+ };
+ size_t count = sizeof(values) / sizeof(Position);
+ computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -39295.941406); // impulse
+ computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -36461.421875); // lsq2
+}
+
+
+TEST_F(VelocityTrackerTest, SailfishFlingDownSlow1) {
+ // Sailfish - fling down - slow - 1
+ Position values[] = {
+ { 235655749552755, 582.00, 432.49 },
+ { 235655750638000, 582.00, 433.00 },
+ { 235655758865000, 582.00, 440.00 },
+ { 235655766221523, 581.16, 448.43 },
+ { 235655767594000, 581.00, 450.00 },
+ { 235655776044000, 580.00, 462.00 },
+ { 235655782890696, 579.18, 474.35 },
+ { 235655784360000, 579.00, 477.00 },
+ { 235655792795000, 578.00, 496.00 },
+ { 235655799559531, 576.27, 515.04 },
+ { 235655800612000, 576.00, 518.00 },
+ { 235655809535000, 574.00, 542.00 },
+ { 235655816988015, 572.17, 564.86 },
+ { 235655817685000, 572.00, 567.00 },
+ { 235655825981000, 569.00, 595.00 },
+ { 235655833808653, 566.26, 620.60 },
+ { 235655834541000, 566.00, 623.00 },
+ { 235655842893000, 563.00, 649.00 },
+ };
+ size_t count = sizeof(values) / sizeof(Position);
+ computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, -419.749695); // impulse
+ computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, -398.303894); // lsq2
+ computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 3309.016357); // impulse
+ computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 3969.099854); // lsq2
+}
+
+
+TEST_F(VelocityTrackerTest, SailfishFlingDownSlow2) {
+ // Sailfish - fling down - slow - 2
+ Position values[] = {
+ { 235671152083370, 485.24, 558.28 },
+ { 235671154126000, 485.00, 559.00 },
+ { 235671162497000, 484.00, 566.00 },
+ { 235671168750511, 483.27, 573.29 },
+ { 235671171071000, 483.00, 576.00 },
+ { 235671179390000, 482.00, 588.00 },
+ { 235671185417210, 481.31, 598.98 },
+ { 235671188173000, 481.00, 604.00 },
+ { 235671196371000, 480.00, 624.00 },
+ { 235671202084196, 479.27, 639.98 },
+ { 235671204235000, 479.00, 646.00 },
+ { 235671212554000, 478.00, 673.00 },
+ { 235671219471011, 476.39, 697.12 },
+ { 235671221159000, 476.00, 703.00 },
+ { 235671229592000, 474.00, 734.00 },
+ { 235671236281462, 472.43, 758.38 },
+ { 235671238098000, 472.00, 765.00 },
+ { 235671246532000, 470.00, 799.00 },
+ };
+ size_t count = sizeof(values) / sizeof(Position);
+ computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, -262.80426); // impulse
+ computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, -243.665344); // lsq2
+ computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 4215.682129); // impulse
+ computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 4587.986816); // lsq2
+}
+
+
+TEST_F(VelocityTrackerTest, SailfishFlingDownSlow3) {
+ // Sailfish - fling down - slow - 3
+ Position values[] = {
+ { 170983201000, 557.00, 533.00 },
+ { 171000668000, 556.00, 534.00 },
+ { 171007359750, 554.73, 535.27 },
+ { 171011197000, 554.00, 536.00 },
+ { 171017660000, 552.00, 540.00 },
+ { 171024201831, 549.97, 544.73 },
+ { 171027333000, 549.00, 547.00 },
+ { 171034603000, 545.00, 557.00 },
+ { 171041043371, 541.98, 567.55 },
+ { 171043147000, 541.00, 571.00 },
+ { 171051052000, 536.00, 586.00 },
+ };
+ size_t count = sizeof(values) / sizeof(Position);
+ computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, -723.413513); // impulse
+ computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, -651.038452); // lsq2
+ computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 2091.502441); // impulse
+ computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 1934.517456); // lsq2
+}
+
+
+TEST_F(VelocityTrackerTest, SailfishFlingDownFaster1) {
+ // Sailfish - fling down - faster - 1
+ Position values[] = {
+ { 235695280333000, 558.00, 451.00 },
+ { 235695283971237, 558.43, 454.45 },
+ { 235695289038000, 559.00, 462.00 },
+ { 235695297388000, 561.00, 478.00 },
+ { 235695300638465, 561.83, 486.25 },
+ { 235695305265000, 563.00, 498.00 },
+ { 235695313591000, 564.00, 521.00 },
+ { 235695317305492, 564.43, 532.68 },
+ { 235695322181000, 565.00, 548.00 },
+ { 235695330709000, 565.00, 577.00 },
+ { 235695333972227, 565.00, 588.10 },
+ { 235695339250000, 565.00, 609.00 },
+ { 235695347839000, 565.00, 642.00 },
+ { 235695351313257, 565.00, 656.18 },
+ { 235695356412000, 565.00, 677.00 },
+ { 235695364899000, 563.00, 710.00 },
+ { 235695368118682, 562.24, 722.52 },
+ { 235695373403000, 564.00, 744.00 },
+ };
+ size_t count = sizeof(values) / sizeof(Position);
+ computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 4254.639648); // impulse
+ computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 4698.415039); // lsq2
+}
+
+
+TEST_F(VelocityTrackerTest, SailfishFlingDownFaster2) {
+ // Sailfish - fling down - faster - 2
+ Position values[] = {
+ { 235709624766000, 535.00, 579.00 },
+ { 235709642256000, 534.00, 580.00 },
+ { 235709643350278, 533.94, 580.06 },
+ { 235709650760000, 532.00, 584.00 },
+ { 235709658615000, 530.00, 593.00 },
+ { 235709660170495, 529.60, 594.78 },
+ { 235709667095000, 527.00, 606.00 },
+ { 235709675616000, 524.00, 628.00 },
+ { 235709676983261, 523.52, 631.53 },
+ { 235709684289000, 521.00, 652.00 },
+ { 235709692763000, 518.00, 682.00 },
+ { 235709693804993, 517.63, 685.69 },
+ { 235709701438000, 515.00, 709.00 },
+ { 235709709830000, 512.00, 739.00 },
+ { 235709710626776, 511.72, 741.85 },
+ };
+ size_t count = sizeof(values) / sizeof(Position);
+ computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, -430.440247); // impulse
+ computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, -447.600311); // lsq2
+ computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 3953.859375); // impulse
+ computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 4316.155273); // lsq2
+}
+
+
+TEST_F(VelocityTrackerTest, SailfishFlingDownFaster3) {
+ // Sailfish - fling down - faster - 3
+ Position values[] = {
+ { 235727628927000, 540.00, 440.00 },
+ { 235727636810000, 537.00, 454.00 },
+ { 235727646176000, 536.00, 454.00 },
+ { 235727653586628, 535.12, 456.65 },
+ { 235727654557000, 535.00, 457.00 },
+ { 235727663024000, 534.00, 465.00 },
+ { 235727670410103, 533.04, 479.45 },
+ { 235727670691000, 533.00, 480.00 },
+ { 235727679255000, 531.00, 501.00 },
+ { 235727687233704, 529.09, 526.73 },
+ { 235727687628000, 529.00, 528.00 },
+ { 235727696113000, 526.00, 558.00 },
+ { 235727704057546, 523.18, 588.98 },
+ { 235727704576000, 523.00, 591.00 },
+ { 235727713099000, 520.00, 626.00 },
+ { 235727720880776, 516.33, 655.36 },
+ { 235727721580000, 516.00, 658.00 },
+ };
+ size_t count = sizeof(values) / sizeof(Position);
+ computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 4484.617676); // impulse
+ computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 4927.92627); // lsq2
+}
+
+
+TEST_F(VelocityTrackerTest, SailfishFlingDownFast1) {
+ // Sailfish - fling down - fast - 1
+ Position values[] = {
+ { 235762352849000, 467.00, 286.00 },
+ { 235762360250000, 443.00, 344.00 },
+ { 235762362787412, 434.77, 363.89 },
+ { 235762368807000, 438.00, 359.00 },
+ { 235762377220000, 425.00, 423.00 },
+ { 235762379608561, 421.31, 441.17 },
+ { 235762385698000, 412.00, 528.00 },
+ { 235762394133000, 406.00, 648.00 },
+ { 235762396429369, 404.37, 680.67 },
+ };
+ size_t count = sizeof(values) / sizeof(Position);
+ computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 19084.931641); // impulse
+ computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 16064.685547); // lsq2
+}
+
+
+TEST_F(VelocityTrackerTest, SailfishFlingDownFast2) {
+ // Sailfish - fling down - fast - 2
+ Position values[] = {
+ { 235772487188000, 576.00, 204.00 },
+ { 235772495159000, 553.00, 236.00 },
+ { 235772503568000, 551.00, 240.00 },
+ { 235772508192247, 545.55, 254.17 },
+ { 235772512051000, 541.00, 266.00 },
+ { 235772520794000, 520.00, 337.00 },
+ { 235772525015263, 508.92, 394.43 },
+ { 235772529174000, 498.00, 451.00 },
+ { 235772537635000, 484.00, 589.00 },
+ };
+ size_t count = sizeof(values) / sizeof(Position);
+ computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 18660.048828); // impulse
+ computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 16918.439453); // lsq2
+}
+
+
+TEST_F(VelocityTrackerTest, SailfishFlingDownFast3) {
+ // Sailfish - fling down - fast - 3
+ Position values[] = {
+ { 507650295000, 628.00, 233.00 },
+ { 507658234000, 605.00, 269.00 },
+ { 507666784000, 601.00, 274.00 },
+ { 507669660483, 599.65, 275.68 },
+ { 507675427000, 582.00, 308.00 },
+ { 507683740000, 541.00, 404.00 },
+ { 507686506238, 527.36, 435.95 },
+ { 507692220000, 487.00, 581.00 },
+ { 507700707000, 454.00, 792.00 },
+ { 507703352649, 443.71, 857.77 },
+ };
+ size_t count = sizeof(values) / sizeof(Position);
+ computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, -6772.508301); // impulse
+ computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, -6388.48877); // lsq2
+ computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 29765.908203); // impulse
+ computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 28354.796875); // lsq2
+}
+
+
+} // namespace android
diff --git a/libs/math/include/math/TMatHelpers.h b/libs/math/include/math/TMatHelpers.h
index 5cb725d..1423ade 100644
--- a/libs/math/include/math/TMatHelpers.h
+++ b/libs/math/include/math/TMatHelpers.h
@@ -342,9 +342,9 @@
template <typename MATRIX>
String8 asString(const MATRIX& m) {
String8 s;
- for (size_t c = 0; c < MATRIX::col_size(); c++) {
+ for (size_t c = 0; c < MATRIX::COL_SIZE; c++) {
s.append("| ");
- for (size_t r = 0; r < MATRIX::row_size(); r++) {
+ for (size_t r = 0; r < MATRIX::ROW_SIZE; r++) {
s.appendFormat("%7.2f ", m[r][c]);
}
s.append("|\n");
diff --git a/libs/math/tests/Android.bp b/libs/math/tests/Android.bp
index 0ed24a2..0184f56 100644
--- a/libs/math/tests/Android.bp
+++ b/libs/math/tests/Android.bp
@@ -18,22 +18,26 @@
name: "vec_test",
srcs: ["vec_test.cpp"],
static_libs: ["libmath"],
+ cflags: ["-Wall", "-Werror"],
}
cc_test {
name: "mat_test",
srcs: ["mat_test.cpp"],
static_libs: ["libmath"],
+ cflags: ["-Wall", "-Werror"],
}
cc_test {
name: "half_test",
srcs: ["half_test.cpp"],
static_libs: ["libmath"],
+ cflags: ["-Wall", "-Werror"],
}
cc_test {
name: "quat_test",
srcs: ["quat_test.cpp"],
static_libs: ["libmath"],
+ cflags: ["-Wall", "-Werror"],
}
diff --git a/libs/nativebase/include/nativebase/nativebase.h b/libs/nativebase/include/nativebase/nativebase.h
index 90afb3f..7ecdfbd 100644
--- a/libs/nativebase/include/nativebase/nativebase.h
+++ b/libs/nativebase/include/nativebase/nativebase.h
@@ -88,14 +88,18 @@
int height;
int stride;
int format;
- int usage;
+ int usage_deprecated;
uintptr_t layerCount;
void* reserved[1];
const native_handle_t* handle;
+ uint64_t usage;
- void* reserved_proc[8];
+ // we needed extra space for storing the 64-bits usage flags
+ // the number of slots to use from reserved_proc depends on the
+ // architecture.
+ void* reserved_proc[8 - (sizeof(uint64_t) / sizeof(void*))];
} ANativeWindowBuffer_t;
typedef struct ANativeWindowBuffer ANativeWindowBuffer;
diff --git a/libs/nativewindow/AHardwareBuffer.cpp b/libs/nativewindow/AHardwareBuffer.cpp
index c0602e7..ed292e7 100644
--- a/libs/nativewindow/AHardwareBuffer.cpp
+++ b/libs/nativewindow/AHardwareBuffer.cpp
@@ -44,12 +44,12 @@
if (!outBuffer || !desc)
return BAD_VALUE;
- int format = AHardwareBuffer_convertToPixelFormat(desc->format);
- if (format == 0) {
- ALOGE("Invalid pixel format %u", desc->format);
+ if (!AHardwareBuffer_isValidPixelFormat(desc->format)) {
+ ALOGE("Invalid AHardwareBuffer pixel format %u (%#x))", desc->format, desc->format);
return BAD_VALUE;
}
+ int format = AHardwareBuffer_convertToPixelFormat(desc->format);
if (desc->rfu0 != 0 || desc->rfu1 != 0) {
ALOGE("AHardwareBuffer_Desc::rfu fields must be 0");
return BAD_VALUE;
@@ -134,7 +134,10 @@
if (!buffer) return BAD_VALUE;
GraphicBuffer* gBuffer = AHardwareBuffer_to_GraphicBuffer(buffer);
- return gBuffer->unlockAsync(fence);
+ if (fence == nullptr)
+ return gBuffer->unlock();
+ else
+ return gBuffer->unlockAsync(fence);
}
int AHardwareBuffer_sendHandleToUnixSocket(const AHardwareBuffer* buffer, int socketFd) {
@@ -293,32 +296,95 @@
return (mask & bitsToCheck) == bitsToCheck && bitsToCheck;
}
-uint32_t AHardwareBuffer_convertFromPixelFormat(uint32_t format) {
+bool AHardwareBuffer_isValidPixelFormat(uint32_t format) {
+ static_assert(HAL_PIXEL_FORMAT_RGBA_8888 == AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM,
+ "HAL and AHardwareBuffer pixel format don't match");
+ static_assert(HAL_PIXEL_FORMAT_RGBX_8888 == AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM,
+ "HAL and AHardwareBuffer pixel format don't match");
+ static_assert(HAL_PIXEL_FORMAT_RGB_565 == AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM,
+ "HAL and AHardwareBuffer pixel format don't match");
+ static_assert(HAL_PIXEL_FORMAT_RGB_888 == AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM,
+ "HAL and AHardwareBuffer pixel format don't match");
+ static_assert(HAL_PIXEL_FORMAT_RGBA_FP16 == AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT,
+ "HAL and AHardwareBuffer pixel format don't match");
+ static_assert(HAL_PIXEL_FORMAT_RGBA_1010102 == AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM,
+ "HAL and AHardwareBuffer pixel format don't match");
+ static_assert(HAL_PIXEL_FORMAT_BLOB == AHARDWAREBUFFER_FORMAT_BLOB,
+ "HAL and AHardwareBuffer pixel format don't match");
+ static_assert(HAL_PIXEL_FORMAT_BGRA_8888 == AHARDWAREBUFFER_FORMAT_B8G8R8A8_UNORM,
+ "HAL and AHardwareBuffer pixel format don't match");
+ static_assert(HAL_PIXEL_FORMAT_YV12 == AHARDWAREBUFFER_FORMAT_YV12,
+ "HAL and AHardwareBuffer pixel format don't match");
+ static_assert(HAL_PIXEL_FORMAT_Y8 == AHARDWAREBUFFER_FORMAT_Y8,
+ "HAL and AHardwareBuffer pixel format don't match");
+ static_assert(HAL_PIXEL_FORMAT_Y16 == AHARDWAREBUFFER_FORMAT_Y16,
+ "HAL and AHardwareBuffer pixel format don't match");
+ static_assert(HAL_PIXEL_FORMAT_RAW16 == AHARDWAREBUFFER_FORMAT_RAW16,
+ "HAL and AHardwareBuffer pixel format don't match");
+ static_assert(HAL_PIXEL_FORMAT_RAW10 == AHARDWAREBUFFER_FORMAT_RAW10,
+ "HAL and AHardwareBuffer pixel format don't match");
+ static_assert(HAL_PIXEL_FORMAT_RAW12 == AHARDWAREBUFFER_FORMAT_RAW12,
+ "HAL and AHardwareBuffer pixel format don't match");
+ static_assert(HAL_PIXEL_FORMAT_RAW_OPAQUE == AHARDWAREBUFFER_FORMAT_RAW_OPAQUE,
+ "HAL and AHardwareBuffer pixel format don't match");
+ static_assert(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED == AHARDWAREBUFFER_FORMAT_IMPLEMENTATION_DEFINED,
+ "HAL and AHardwareBuffer pixel format don't match");
+ static_assert(HAL_PIXEL_FORMAT_YCBCR_420_888 == AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_420,
+ "HAL and AHardwareBuffer pixel format don't match");
+ static_assert(HAL_PIXEL_FORMAT_YCBCR_422_888 == AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_422,
+ "HAL and AHardwareBuffer pixel format don't match");
+ static_assert(HAL_PIXEL_FORMAT_YCBCR_444_888 == AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_444,
+ "HAL and AHardwareBuffer pixel format don't match");
+ static_assert(HAL_PIXEL_FORMAT_FLEX_RGB_888 == AHARDWAREBUFFER_FORMAT_FLEX_R8G8B8,
+ "HAL and AHardwareBuffer pixel format don't match");
+ static_assert(HAL_PIXEL_FORMAT_FLEX_RGBA_8888 == AHARDWAREBUFFER_FORMAT_FLEX_R8G8B8A8,
+ "HAL and AHardwareBuffer pixel format don't match");
+ static_assert(HAL_PIXEL_FORMAT_YCBCR_422_SP == AHARDWAREBUFFER_FORMAT_YCbCr_422_SP,
+ "HAL and AHardwareBuffer pixel format don't match");
+ static_assert(HAL_PIXEL_FORMAT_YCRCB_420_SP == AHARDWAREBUFFER_FORMAT_YCrCb_420_SP,
+ "HAL and AHardwareBuffer pixel format don't match");
+ static_assert(HAL_PIXEL_FORMAT_YCBCR_422_I == AHARDWAREBUFFER_FORMAT_YCbCr_422_I,
+ "HAL and AHardwareBuffer pixel format don't match");
+
switch (format) {
- case HAL_PIXEL_FORMAT_RGBA_8888: return AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
- case HAL_PIXEL_FORMAT_RGBX_8888: return AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM;
- case HAL_PIXEL_FORMAT_RGB_565: return AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM;
- case HAL_PIXEL_FORMAT_RGB_888: return AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM;
- case HAL_PIXEL_FORMAT_RGBA_FP16: return AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT;
- case HAL_PIXEL_FORMAT_RGBA_1010102: return AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM;
- case HAL_PIXEL_FORMAT_BLOB: return AHARDWAREBUFFER_FORMAT_BLOB;
- default:ALOGE("Unknown pixel format %u", format);
- return 0;
+ case AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM:
+ case AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM:
+ case AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM:
+ case AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM:
+ case AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT:
+ case AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM:
+ case AHARDWAREBUFFER_FORMAT_BLOB:
+ // VNDK formats only -- unfortunately we can't differentiate from where we're called
+ case AHARDWAREBUFFER_FORMAT_B8G8R8A8_UNORM:
+ case AHARDWAREBUFFER_FORMAT_YV12:
+ case AHARDWAREBUFFER_FORMAT_Y8:
+ case AHARDWAREBUFFER_FORMAT_Y16:
+ case AHARDWAREBUFFER_FORMAT_RAW16:
+ case AHARDWAREBUFFER_FORMAT_RAW10:
+ case AHARDWAREBUFFER_FORMAT_RAW12:
+ case AHARDWAREBUFFER_FORMAT_RAW_OPAQUE:
+ case AHARDWAREBUFFER_FORMAT_IMPLEMENTATION_DEFINED:
+ case AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_420:
+ case AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_422:
+ case AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_444:
+ case AHARDWAREBUFFER_FORMAT_FLEX_R8G8B8:
+ case AHARDWAREBUFFER_FORMAT_FLEX_R8G8B8A8:
+ case AHARDWAREBUFFER_FORMAT_YCbCr_422_SP:
+ case AHARDWAREBUFFER_FORMAT_YCrCb_420_SP:
+ case AHARDWAREBUFFER_FORMAT_YCbCr_422_I:
+ return true;
+
+ default:
+ return false;
}
}
-uint32_t AHardwareBuffer_convertToPixelFormat(uint32_t format) {
- switch (format) {
- case AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM: return HAL_PIXEL_FORMAT_RGBA_8888;
- case AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM: return HAL_PIXEL_FORMAT_RGBX_8888;
- case AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM: return HAL_PIXEL_FORMAT_RGB_565;
- case AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM: return HAL_PIXEL_FORMAT_RGB_888;
- case AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT: return HAL_PIXEL_FORMAT_RGBA_FP16;
- case AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM: return HAL_PIXEL_FORMAT_RGBA_1010102;
- case AHARDWAREBUFFER_FORMAT_BLOB: return HAL_PIXEL_FORMAT_BLOB;
- default:ALOGE("Unknown AHardwareBuffer format %u", format);
- return 0;
- }
+uint32_t AHardwareBuffer_convertFromPixelFormat(uint32_t hal_format) {
+ return hal_format;
+}
+
+uint32_t AHardwareBuffer_convertToPixelFormat(uint32_t ahardwarebuffer_format) {
+ return ahardwarebuffer_format;
}
uint64_t AHardwareBuffer_convertToGrallocUsageBits(uint64_t usage) {
diff --git a/libs/nativewindow/ANativeWindow.cpp b/libs/nativewindow/ANativeWindow.cpp
index 9224df6..c6994c30 100644
--- a/libs/nativewindow/ANativeWindow.cpp
+++ b/libs/nativewindow/ANativeWindow.cpp
@@ -190,8 +190,7 @@
}
int ANativeWindow_setUsage(ANativeWindow* window, uint64_t usage) {
- usage = AHardwareBuffer_convertToGrallocUsageBits(usage);
- return native_window_set_usage(window, (uint32_t)usage); // FIXME: we need a 64-bits version
+ return native_window_set_usage(window, usage);
}
int ANativeWindow_setBufferCount(ANativeWindow* window, size_t bufferCount) {
diff --git a/libs/nativewindow/Android.bp b/libs/nativewindow/Android.bp
index e61fbd6..64eb110 100644
--- a/libs/nativewindow/Android.bp
+++ b/libs/nativewindow/Android.bp
@@ -34,6 +34,12 @@
clang: true,
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wno-unused-function",
+ ],
+
cppflags: [
"-std=c++1z"
],
diff --git a/libs/nativewindow/include/private/android/AHardwareBufferHelpers.h b/libs/nativewindow/include/private/android/AHardwareBufferHelpers.h
index ed6b169..71f5634 100644
--- a/libs/nativewindow/include/private/android/AHardwareBufferHelpers.h
+++ b/libs/nativewindow/include/private/android/AHardwareBufferHelpers.h
@@ -32,11 +32,21 @@
namespace android {
+// whether this AHardwareBuffer format is valid
+bool AHardwareBuffer_isValidPixelFormat(uint32_t ahardwarebuffer_format);
+
+// convert AHardwareBuffer format to HAL format (note: this is a no-op)
uint32_t AHardwareBuffer_convertFromPixelFormat(uint32_t format);
+
+// convert HAL format to AHardwareBuffer format (note: this is a no-op)
uint32_t AHardwareBuffer_convertToPixelFormat(uint32_t format);
-uint64_t AHardwareBuffer_convertToGrallocUsageBits(uint64_t usage);
+
+// convert AHardwareBuffer usage bits to HAL usage bits (note: this is a no-op)
uint64_t AHardwareBuffer_convertFromGrallocUsageBits(uint64_t usage);
+// convert HAL usage bits to AHardwareBuffer usage bits (note: this is a no-op)
+uint64_t AHardwareBuffer_convertToGrallocUsageBits(uint64_t usage);
+
class GraphicBuffer;
const GraphicBuffer* AHardwareBuffer_to_GraphicBuffer(const AHardwareBuffer* buffer);
GraphicBuffer* AHardwareBuffer_to_GraphicBuffer(AHardwareBuffer* buffer);
diff --git a/libs/nativewindow/include/system/window.h b/libs/nativewindow/include/system/window.h
index 6429c52..6490804 100644
--- a/libs/nativewindow/include/system/window.h
+++ b/libs/nativewindow/include/system/window.h
@@ -115,7 +115,7 @@
* The consumer gralloc usage bits currently set by the consumer.
* The values are defined in hardware/libhardware/include/gralloc.h.
*/
- NATIVE_WINDOW_CONSUMER_USAGE_BITS = 10,
+ NATIVE_WINDOW_CONSUMER_USAGE_BITS = 10, /* deprecated */
/**
* Transformation that will by applied to buffers by the hwcomposer.
@@ -193,36 +193,38 @@
*/
enum {
// clang-format off
- NATIVE_WINDOW_SET_USAGE = 0,
- NATIVE_WINDOW_CONNECT = 1, /* deprecated */
- NATIVE_WINDOW_DISCONNECT = 2, /* deprecated */
- NATIVE_WINDOW_SET_CROP = 3, /* private */
- NATIVE_WINDOW_SET_BUFFER_COUNT = 4,
- NATIVE_WINDOW_SET_BUFFERS_GEOMETRY = 5, /* deprecated */
- NATIVE_WINDOW_SET_BUFFERS_TRANSFORM = 6,
- NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP = 7,
- NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS = 8,
- NATIVE_WINDOW_SET_BUFFERS_FORMAT = 9,
- NATIVE_WINDOW_SET_SCALING_MODE = 10, /* private */
- NATIVE_WINDOW_LOCK = 11, /* private */
- NATIVE_WINDOW_UNLOCK_AND_POST = 12, /* private */
- NATIVE_WINDOW_API_CONNECT = 13, /* private */
- NATIVE_WINDOW_API_DISCONNECT = 14, /* private */
- NATIVE_WINDOW_SET_BUFFERS_USER_DIMENSIONS = 15, /* private */
- NATIVE_WINDOW_SET_POST_TRANSFORM_CROP = 16, /* private */
- NATIVE_WINDOW_SET_BUFFERS_STICKY_TRANSFORM = 17,/* private */
- NATIVE_WINDOW_SET_SIDEBAND_STREAM = 18,
- NATIVE_WINDOW_SET_BUFFERS_DATASPACE = 19,
- NATIVE_WINDOW_SET_SURFACE_DAMAGE = 20, /* private */
- NATIVE_WINDOW_SET_SHARED_BUFFER_MODE = 21,
- NATIVE_WINDOW_SET_AUTO_REFRESH = 22,
- NATIVE_WINDOW_GET_REFRESH_CYCLE_DURATION= 23,
- NATIVE_WINDOW_GET_NEXT_FRAME_ID = 24,
- NATIVE_WINDOW_ENABLE_FRAME_TIMESTAMPS = 25,
- NATIVE_WINDOW_GET_COMPOSITOR_TIMING = 26,
- NATIVE_WINDOW_GET_FRAME_TIMESTAMPS = 27,
- NATIVE_WINDOW_GET_WIDE_COLOR_SUPPORT = 28,
- NATIVE_WINDOW_GET_HDR_SUPPORT = 29,
+ NATIVE_WINDOW_SET_USAGE = 0, /* deprecated */
+ NATIVE_WINDOW_CONNECT = 1, /* deprecated */
+ NATIVE_WINDOW_DISCONNECT = 2, /* deprecated */
+ NATIVE_WINDOW_SET_CROP = 3, /* private */
+ NATIVE_WINDOW_SET_BUFFER_COUNT = 4,
+ NATIVE_WINDOW_SET_BUFFERS_GEOMETRY = 5, /* deprecated */
+ NATIVE_WINDOW_SET_BUFFERS_TRANSFORM = 6,
+ NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP = 7,
+ NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS = 8,
+ NATIVE_WINDOW_SET_BUFFERS_FORMAT = 9,
+ NATIVE_WINDOW_SET_SCALING_MODE = 10, /* private */
+ NATIVE_WINDOW_LOCK = 11, /* private */
+ NATIVE_WINDOW_UNLOCK_AND_POST = 12, /* private */
+ NATIVE_WINDOW_API_CONNECT = 13, /* private */
+ NATIVE_WINDOW_API_DISCONNECT = 14, /* private */
+ NATIVE_WINDOW_SET_BUFFERS_USER_DIMENSIONS = 15, /* private */
+ NATIVE_WINDOW_SET_POST_TRANSFORM_CROP = 16, /* deprecated, unimplemented */
+ NATIVE_WINDOW_SET_BUFFERS_STICKY_TRANSFORM = 17, /* private */
+ NATIVE_WINDOW_SET_SIDEBAND_STREAM = 18,
+ NATIVE_WINDOW_SET_BUFFERS_DATASPACE = 19,
+ NATIVE_WINDOW_SET_SURFACE_DAMAGE = 20, /* private */
+ NATIVE_WINDOW_SET_SHARED_BUFFER_MODE = 21,
+ NATIVE_WINDOW_SET_AUTO_REFRESH = 22,
+ NATIVE_WINDOW_GET_REFRESH_CYCLE_DURATION = 23,
+ NATIVE_WINDOW_GET_NEXT_FRAME_ID = 24,
+ NATIVE_WINDOW_ENABLE_FRAME_TIMESTAMPS = 25,
+ NATIVE_WINDOW_GET_COMPOSITOR_TIMING = 26,
+ NATIVE_WINDOW_GET_FRAME_TIMESTAMPS = 27,
+ NATIVE_WINDOW_GET_WIDE_COLOR_SUPPORT = 28,
+ NATIVE_WINDOW_GET_HDR_SUPPORT = 29,
+ NATIVE_WINDOW_SET_USAGE64 = 30,
+ NATIVE_WINDOW_GET_CONSUMER_USAGE64 = 31,
// clang-format on
};
@@ -533,20 +535,18 @@
typedef struct ANativeWindow android_native_window_t __deprecated;
/*
- * native_window_set_usage(..., usage)
+ * native_window_set_usage64(..., usage)
* Sets the intended usage flags for the next buffers
* acquired with (*lockBuffer)() and on.
- * By default (if this function is never called), a usage of
- * GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE
- * is assumed.
+ *
+ * Valid usage flags are defined in android/hardware_buffer.h
+ * All AHARDWAREBUFFER_USAGE_* flags can be specified as needed.
+ *
* Calling this function will usually cause following buffers to be
* reallocated.
*/
-
-static inline int native_window_set_usage(
- struct ANativeWindow* window, int usage)
-{
- return window->perform(window, NATIVE_WINDOW_SET_USAGE, usage);
+static inline int native_window_set_usage(struct ANativeWindow* window, uint64_t usage) {
+ return window->perform(window, NATIVE_WINDOW_SET_USAGE64, usage);
}
/* deprecated. Always returns 0. Don't call. */
@@ -589,45 +589,6 @@
}
/*
- * native_window_set_post_transform_crop(..., crop)
- * Sets which region of the next queued buffers needs to be considered.
- * Depending on the scaling mode, a buffer's crop region is scaled and/or
- * cropped to match the surface's size. This function sets the crop in
- * post-transformed pixel coordinates.
- *
- * The specified crop region applies to all buffers queued after it is called.
- *
- * If 'crop' is NULL, subsequently queued buffers won't be cropped.
- *
- * An error is returned if for instance the crop region is invalid, out of the
- * buffer's bound or if the window is invalid.
- */
-static inline int native_window_set_post_transform_crop(
- struct ANativeWindow* window,
- android_native_rect_t const * crop)
-{
- return window->perform(window, NATIVE_WINDOW_SET_POST_TRANSFORM_CROP, crop);
-}
-
-/*
- * native_window_set_active_rect(..., active_rect)
- *
- * This function is deprecated and will be removed soon. For now it simply
- * sets the post-transform crop for compatibility while multi-project commits
- * get checked.
- */
-static inline int native_window_set_active_rect(
- struct ANativeWindow* window,
- android_native_rect_t const * active_rect) __deprecated;
-
-static inline int native_window_set_active_rect(
- struct ANativeWindow* window,
- android_native_rect_t const * active_rect)
-{
- return native_window_set_post_transform_crop(window, active_rect);
-}
-
-/*
* native_window_set_buffer_count(..., count)
* Sets the number of buffers associated with this native window.
*/
@@ -940,13 +901,18 @@
static inline int native_window_get_wide_color_support(
struct ANativeWindow* window, bool* outSupport) {
- return window->perform(window, NATIVE_WINDOW_GET_WIDE_COLOR_SUPPORT,
- outSupport);
+ return window->perform(window, NATIVE_WINDOW_GET_WIDE_COLOR_SUPPORT,
+ outSupport);
}
static inline int native_window_get_hdr_support(struct ANativeWindow* window,
bool* outSupport) {
- return window->perform(window, NATIVE_WINDOW_GET_HDR_SUPPORT, outSupport);
+ return window->perform(window, NATIVE_WINDOW_GET_HDR_SUPPORT, outSupport);
+}
+
+static inline int native_window_get_consumer_usage(struct ANativeWindow* window,
+ uint64_t* outUsage) {
+ return window->perform(window, NATIVE_WINDOW_GET_CONSUMER_USAGE64, outUsage);
}
__END_DECLS
diff --git a/libs/nativewindow/include/vndk/hardware_buffer.h b/libs/nativewindow/include/vndk/hardware_buffer.h
index dc2dcbe..802edcc 100644
--- a/libs/nativewindow/include/vndk/hardware_buffer.h
+++ b/libs/nativewindow/include/vndk/hardware_buffer.h
@@ -26,6 +26,49 @@
const native_handle_t* AHardwareBuffer_getNativeHandle(const AHardwareBuffer* buffer);
+
+/**
+ * Buffer pixel formats.
+ */
+enum {
+ /* for future proofing, keep these in sync with system/graphics-base.h */
+
+ /* same as HAL_PIXEL_FORMAT_BGRA_8888 */
+ AHARDWAREBUFFER_FORMAT_B8G8R8A8_UNORM = 5,
+ /* same as HAL_PIXEL_FORMAT_YV12 */
+ AHARDWAREBUFFER_FORMAT_YV12 = 0x32315659,
+ /* same as HAL_PIXEL_FORMAT_Y8 */
+ AHARDWAREBUFFER_FORMAT_Y8 = 0x20203859,
+ /* same as HAL_PIXEL_FORMAT_Y16 */
+ AHARDWAREBUFFER_FORMAT_Y16 = 0x20363159,
+ /* same as HAL_PIXEL_FORMAT_RAW16 */
+ AHARDWAREBUFFER_FORMAT_RAW16 = 0x20,
+ /* same as HAL_PIXEL_FORMAT_RAW10 */
+ AHARDWAREBUFFER_FORMAT_RAW10 = 0x25,
+ /* same as HAL_PIXEL_FORMAT_RAW12 */
+ AHARDWAREBUFFER_FORMAT_RAW12 = 0x26,
+ /* same as HAL_PIXEL_FORMAT_RAW_OPAQUE */
+ AHARDWAREBUFFER_FORMAT_RAW_OPAQUE = 0x24,
+ /* same as HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED */
+ AHARDWAREBUFFER_FORMAT_IMPLEMENTATION_DEFINED = 0x22,
+ /* same as HAL_PIXEL_FORMAT_YCBCR_420_888 */
+ AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_420 = 0x23,
+ /* same as HAL_PIXEL_FORMAT_YCBCR_422_888 */
+ AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_422 = 0x27,
+ /* same as HAL_PIXEL_FORMAT_YCBCR_444_888 */
+ AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_444 = 0x28,
+ /* same as HAL_PIXEL_FORMAT_FLEX_RGB_888 */
+ AHARDWAREBUFFER_FORMAT_FLEX_R8G8B8 = 0x29,
+ /* same as HAL_PIXEL_FORMAT_FLEX_RGBA_8888 */
+ AHARDWAREBUFFER_FORMAT_FLEX_R8G8B8A8 = 0x2A,
+ /* same as HAL_PIXEL_FORMAT_YCBCR_422_SP */
+ AHARDWAREBUFFER_FORMAT_YCbCr_422_SP = 0x10,
+ /* same as HAL_PIXEL_FORMAT_YCRCB_420_SP */
+ AHARDWAREBUFFER_FORMAT_YCrCb_420_SP = 0x11,
+ /* same as HAL_PIXEL_FORMAT_YCBCR_422_I */
+ AHARDWAREBUFFER_FORMAT_YCbCr_422_I = 0x14,
+};
+
__END_DECLS
#endif /* ANDROID_VNDK_NATIVEWINDOW_AHARDWAREBUFFER_H */
diff --git a/libs/nativewindow/tests/Android.bp b/libs/nativewindow/tests/Android.bp
index b89c35a..20071be 100644
--- a/libs/nativewindow/tests/Android.bp
+++ b/libs/nativewindow/tests/Android.bp
@@ -23,4 +23,5 @@
srcs: [
"AHardwareBufferTest.cpp",
"c_compatibility.c"],
+ cflags: ["-Wall", "-Werror"],
}
diff --git a/libs/sensor/Android.bp b/libs/sensor/Android.bp
index 171a627..940ff5a 100644
--- a/libs/sensor/Android.bp
+++ b/libs/sensor/Android.bp
@@ -16,9 +16,12 @@
name: "libsensor",
clang: true,
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
cppflags: [
"-Weverything",
- "-Werror",
// The static constructors and destructors in this library have not been noted to
// introduce significant overheads
diff --git a/libs/sensor/ISensorEventConnection.cpp b/libs/sensor/ISensorEventConnection.cpp
index 8a3a623..1cd8e01 100644
--- a/libs/sensor/ISensorEventConnection.cpp
+++ b/libs/sensor/ISensorEventConnection.cpp
@@ -36,7 +36,8 @@
ENABLE_DISABLE,
SET_EVENT_RATE,
FLUSH_SENSOR,
- CONFIGURE_CHANNEL
+ CONFIGURE_CHANNEL,
+ DESTROY,
};
class BpSensorEventConnection : public BpInterface<ISensorEventConnection>
@@ -96,11 +97,22 @@
remote()->transact(CONFIGURE_CHANNEL, data, &reply);
return reply.readInt32();
}
+
+ virtual void onLastStrongRef(const void* id) {
+ destroy();
+ BpInterface<ISensorEventConnection>::onLastStrongRef(id);
+ }
+
+protected:
+ virtual void destroy() {
+ Parcel data, reply;
+ remote()->transact(DESTROY, data, &reply);
+ }
};
// Out-of-line virtual method definition to trigger vtable emission in this
// translation unit (see clang warning -Wweak-vtables)
-BpSensorEventConnection::~BpSensorEventConnection() {}
+BpSensorEventConnection::~BpSensorEventConnection() { }
IMPLEMENT_META_INTERFACE(SensorEventConnection, "android.gui.SensorEventConnection");
@@ -150,6 +162,10 @@
reply->writeInt32(result);
return NO_ERROR;
}
+ case DESTROY: {
+ destroy();
+ return NO_ERROR;
+ }
}
return BBinder::onTransact(code, data, reply, flags);
diff --git a/libs/sensor/ISensorServer.cpp b/libs/sensor/ISensorServer.cpp
index f20668d..efbbf7d 100644
--- a/libs/sensor/ISensorServer.cpp
+++ b/libs/sensor/ISensorServer.cpp
@@ -63,7 +63,8 @@
Vector<Sensor> v;
uint32_t n = reply.readUint32();
v.setCapacity(n);
- while (n--) {
+ while (n) {
+ n--;
reply.read(s);
v.add(s);
}
@@ -80,7 +81,8 @@
Vector<Sensor> v;
uint32_t n = reply.readUint32();
v.setCapacity(n);
- while (n--) {
+ while (n) {
+ n--;
reply.read(s);
v.add(s);
}
diff --git a/libs/sensor/OWNERS b/libs/sensor/OWNERS
new file mode 100644
index 0000000..6a38a1f
--- /dev/null
+++ b/libs/sensor/OWNERS
@@ -0,0 +1,2 @@
+ashutoshj@google.com
+pengxu@google.com
diff --git a/libs/sensor/Sensor.cpp b/libs/sensor/Sensor.cpp
index c2d477e..a0e368c 100644
--- a/libs/sensor/Sensor.cpp
+++ b/libs/sensor/Sensor.cpp
@@ -30,7 +30,7 @@
mName(name), mHandle(0), mType(0),
mMinValue(0), mMaxValue(0), mResolution(0),
mPower(0), mMinDelay(0), mVersion(0), mFifoReservedEventCount(0),
- mFifoMaxEventCount(0), mRequiredAppOp(0),
+ mFifoMaxEventCount(0), mRequiredAppOp(-1),
mMaxDelay(0), mFlags(0) {
}
@@ -38,7 +38,8 @@
Sensor(*hwSensor, uuid_t(), halVersion) {
}
-Sensor::Sensor(struct sensor_t const& hwSensor, const uuid_t& uuid, int halVersion) {
+Sensor::Sensor(struct sensor_t const& hwSensor, const uuid_t& uuid, int halVersion) :
+ Sensor("") {
mName = hwSensor.name;
mVendor = hwSensor.vendor;
mVersion = hwSensor.version;
@@ -412,6 +413,10 @@
return (mFlags & SENSOR_FLAG_DYNAMIC_SENSOR) != 0;
}
+bool Sensor::isDataInjectionSupported() const {
+ return (mFlags & SENSOR_FLAG_DATA_INJECTION) != 0;
+}
+
bool Sensor::hasAdditionalInfo() const {
return (mFlags & SENSOR_FLAG_ADDITIONAL_INFO) != 0;
}
diff --git a/libs/sensor/include/sensor/ISensorEventConnection.h b/libs/sensor/include/sensor/ISensorEventConnection.h
index 07cc7e8..b62e18c 100644
--- a/libs/sensor/include/sensor/ISensorEventConnection.h
+++ b/libs/sensor/include/sensor/ISensorEventConnection.h
@@ -42,6 +42,8 @@
virtual status_t setEventRate(int handle, nsecs_t ns) = 0;
virtual status_t flush() = 0;
virtual int32_t configureChannel(int32_t handle, int32_t rateLevel) = 0;
+protected:
+ virtual void destroy() = 0; // synchronously release resource hold by remote object
};
// ----------------------------------------------------------------------------
diff --git a/libs/sensor/include/sensor/Sensor.h b/libs/sensor/include/sensor/Sensor.h
index 043e635..6926f7f 100644
--- a/libs/sensor/include/sensor/Sensor.h
+++ b/libs/sensor/include/sensor/Sensor.h
@@ -90,6 +90,7 @@
uint32_t getFlags() const;
bool isWakeUpSensor() const;
bool isDynamicSensor() const;
+ bool isDataInjectionSupported() const;
bool hasAdditionalInfo() const;
int32_t getHighestDirectReportRateLevel() const;
bool isDirectChannelTypeSupported(int32_t sharedMemType) const;
diff --git a/libs/sensor/tests/Android.bp b/libs/sensor/tests/Android.bp
index 9d530fc..9fd84bc 100644
--- a/libs/sensor/tests/Android.bp
+++ b/libs/sensor/tests/Android.bp
@@ -17,6 +17,8 @@
clang: true,
+ cflags: ["-Wall", "-Werror"],
+
srcs: [
"Sensor_test.cpp",
],
diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp
index d9cfed7..102964f 100644
--- a/libs/ui/Android.bp
+++ b/libs/ui/Android.bp
@@ -15,11 +15,17 @@
cc_library_shared {
name: "libui",
vendor_available: true,
+ vndk: {
+ enabled: true,
+ },
clang: true,
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
cppflags: [
"-Weverything",
- "-Werror",
// The static constructors and destructors in this library have not been noted to
// introduce significant overheads
@@ -41,7 +47,7 @@
],
sanitize: {
- //misc_undefined: ["integer"],
+ integer_overflow: true,
},
srcs: [
@@ -68,6 +74,7 @@
shared_libs: [
"android.hardware.graphics.allocator@2.0",
"android.hardware.graphics.mapper@2.0",
+ "android.hardware.graphics.mapper@2.1",
"android.hardware.configstore@1.0",
"android.hardware.configstore-utils",
"libbase",
@@ -89,6 +96,7 @@
header_libs: [
"libnativebase_headers",
+ "libhardware_headers",
],
export_include_dirs: ["include"],
@@ -100,7 +108,17 @@
export_header_lib_headers: [
"libnativebase_headers",
+ "libhardware_headers",
],
}
-subdirs = ["tests"]
+cc_library_headers {
+ name: "libui_headers",
+ export_include_dirs: ["include"],
+ vendor_available: true,
+}
+
+subdirs = [
+ "tests",
+ "tools",
+]
diff --git a/libs/ui/DebugUtils.cpp b/libs/ui/DebugUtils.cpp
index 94b68e7..2d72944 100644
--- a/libs/ui/DebugUtils.cpp
+++ b/libs/ui/DebugUtils.cpp
@@ -16,10 +16,13 @@
#include <ui/DebugUtils.h>
#include <ui/PixelFormat.h>
+#include <ui/Rect.h>
#include <android-base/stringprintf.h>
#include <string>
+using android::base::StringPrintf;
+
std::string decodeStandard(android_dataspace dataspace) {
const uint32_t dataspaceSelect = (dataspace & HAL_DATASPACE_STANDARD_MASK);
switch (dataspaceSelect) {
@@ -59,24 +62,20 @@
case 0:
switch (dataspace & 0xffff) {
case HAL_DATASPACE_JFIF:
- return std::string("(deprecated) JFIF (BT601_625, SMPTE_170M Full range)");
+ return std::string("(deprecated) JFIF (BT601_625)");
case HAL_DATASPACE_BT601_625:
- return std::string("(deprecated) BT601_625 (BT601_625, SMPTE_170M Limited "
- "range)");
+ return std::string("(deprecated) BT601_625");
case HAL_DATASPACE_BT601_525:
- return std::string("(deprecated) BT601_525 (BT601_525, SMPTE_170M Limited "
- "range)");
+ return std::string("(deprecated) BT601_525");
case HAL_DATASPACE_SRGB_LINEAR:
- return std::string("(deprecated) SRGB Linear Full range");
-
case HAL_DATASPACE_SRGB:
return std::string("(deprecated) sRGB");
case HAL_DATASPACE_V0_BT709:
- return std::string("(deprecated) BT709 (BT709, SMPTE_170M Limited range)");
+ return std::string("(deprecated) BT709");
case HAL_DATASPACE_ARBITRARY:
return std::string("ARBITRARY");
@@ -93,6 +92,29 @@
}
std::string decodeTransfer(android_dataspace dataspace) {
+ const uint32_t dataspaceSelect = (dataspace & HAL_DATASPACE_STANDARD_MASK);
+ if (dataspaceSelect == 0) {
+ switch (dataspace & 0xffff) {
+ case HAL_DATASPACE_JFIF:
+ case HAL_DATASPACE_BT601_625:
+ case HAL_DATASPACE_BT601_525:
+ case HAL_DATASPACE_V0_BT709:
+ return std::string("SMPTE_170M");
+
+ case HAL_DATASPACE_SRGB_LINEAR:
+ case HAL_DATASPACE_ARBITRARY:
+ return std::string("Linear");
+
+ case HAL_DATASPACE_SRGB:
+ return std::string("sRGB");
+
+ case HAL_DATASPACE_UNKNOWN:
+ // Fallthrough
+ default:
+ return std::string("");
+ }
+ }
+
const uint32_t dataspaceTransfer = (dataspace & HAL_DATASPACE_TRANSFER_MASK);
switch (dataspaceTransfer) {
case HAL_DATASPACE_TRANSFER_UNSPECIFIED:
@@ -127,6 +149,27 @@
}
std::string decodeRange(android_dataspace dataspace) {
+ const uint32_t dataspaceSelect = (dataspace & HAL_DATASPACE_STANDARD_MASK);
+ if (dataspaceSelect == 0) {
+ switch (dataspace & 0xffff) {
+ case HAL_DATASPACE_JFIF:
+ case HAL_DATASPACE_SRGB_LINEAR:
+ case HAL_DATASPACE_SRGB:
+ return std::string("Full range");
+
+ case HAL_DATASPACE_BT601_625:
+ case HAL_DATASPACE_BT601_525:
+ case HAL_DATASPACE_V0_BT709:
+ return std::string("Limited range)");
+
+ case HAL_DATASPACE_ARBITRARY:
+ case HAL_DATASPACE_UNKNOWN:
+ // Fallthrough
+ default:
+ return std::string("unspecified range");
+ }
+ }
+
const uint32_t dataspaceRange = (dataspace & HAL_DATASPACE_RANGE_MASK);
switch (dataspaceRange) {
case HAL_DATASPACE_RANGE_UNSPECIFIED:
@@ -147,7 +190,7 @@
std::string dataspaceDetails(android_dataspace dataspace) {
if (dataspace == 0) {
- return "Default (0)";
+ return "Default";
}
return android::base::StringPrintf("%s %s %s", decodeStandard(dataspace).c_str(),
decodeTransfer(dataspace).c_str(),
@@ -222,3 +265,7 @@
return android::base::StringPrintf("Unknown %#08x", format);
}
}
+
+std::string to_string(const android::Rect& rect) {
+ return StringPrintf("(%4d,%4d,%4d,%4d)", rect.left, rect.top, rect.right, rect.bottom);
+}
diff --git a/libs/ui/Gralloc2.cpp b/libs/ui/Gralloc2.cpp
index 87dbaf4..1f746a2 100644
--- a/libs/ui/Gralloc2.cpp
+++ b/libs/ui/Gralloc2.cpp
@@ -16,6 +16,7 @@
#define LOG_TAG "Gralloc2"
+#include <hidl/ServiceManagement.h>
#include <hwbinder/IPCThreadState.h>
#include <ui/Gralloc2.h>
@@ -31,12 +32,22 @@
static constexpr Error kTransactionError = Error::NO_RESOURCES;
+void Mapper::preload() {
+ android::hardware::preloadPassthroughService<hardware::graphics::mapper::V2_0::IMapper>();
+}
+
Mapper::Mapper()
{
mMapper = IMapper::getService();
- if (mMapper == nullptr || mMapper->isRemote()) {
+ if (mMapper == nullptr) {
+ LOG_ALWAYS_FATAL("gralloc-mapper is missing");
+ }
+ if (mMapper->isRemote()) {
LOG_ALWAYS_FATAL("gralloc-mapper must be in passthrough mode");
}
+
+ // IMapper 2.1 is optional
+ mMapperV2_1 = hardware::graphics::mapper::V2_1::IMapper::castFrom(mMapper);
}
Error Mapper::createDescriptor(
@@ -86,6 +97,50 @@
buffer, error);
}
+Error Mapper::validateBufferSize(buffer_handle_t bufferHandle,
+ const IMapper::BufferDescriptorInfo& descriptorInfo,
+ uint32_t stride) const
+{
+ if (mMapperV2_1 == nullptr) {
+ return Error::NONE;
+ }
+
+ auto buffer = const_cast<native_handle_t*>(bufferHandle);
+ auto ret = mMapperV2_1->validateBufferSize(buffer, descriptorInfo, stride);
+
+ return (ret.isOk()) ? static_cast<Error>(ret) : kTransactionError;
+}
+
+void Mapper::getTransportSize(buffer_handle_t bufferHandle,
+ uint32_t* outNumFds, uint32_t* outNumInts) const
+{
+ *outNumFds = uint32_t(bufferHandle->numFds);
+ *outNumInts = uint32_t(bufferHandle->numInts);
+
+ if (mMapperV2_1 == nullptr) {
+ return;
+ }
+
+ Error error;
+ auto buffer = const_cast<native_handle_t*>(bufferHandle);
+ auto ret = mMapperV2_1->getTransportSize(buffer,
+ [&](const auto& tmpError, const auto& tmpNumFds, const auto& tmpNumInts) {
+ error = tmpError;
+ if (error != Error::NONE) {
+ return;
+ }
+
+ *outNumFds = tmpNumFds;
+ *outNumInts = tmpNumInts;
+ });
+
+ if (!ret.isOk()) {
+ error = kTransactionError;
+ }
+ ALOGE_IF(error != Error::NONE, "getTransportSize(%p) failed with %d",
+ buffer, error);
+}
+
Error Mapper::lock(buffer_handle_t bufferHandle, uint64_t usage,
const IMapper::Rect& accessRegion,
int acquireFence, void** outData) const
diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp
index ee85c9b..4ed2aa4 100644
--- a/libs/ui/GraphicBuffer.cpp
+++ b/libs/ui/GraphicBuffer.cpp
@@ -51,6 +51,7 @@
height =
stride =
format =
+ usage_deprecated = 0;
usage = 0;
layerCount = 0;
handle = NULL;
@@ -59,14 +60,12 @@
// deprecated
GraphicBuffer::GraphicBuffer(uint32_t inWidth, uint32_t inHeight,
PixelFormat inFormat, uint32_t inUsage, std::string requestorName)
- : GraphicBuffer(inWidth, inHeight, inFormat, 1, static_cast<uint64_t>(inUsage),
- requestorName)
+ : GraphicBuffer(inWidth, inHeight, inFormat, 1, static_cast<uint64_t>(inUsage), requestorName)
{
}
GraphicBuffer::GraphicBuffer(uint32_t inWidth, uint32_t inHeight,
- PixelFormat inFormat, uint32_t inLayerCount, uint64_t usage,
- std::string requestorName)
+ PixelFormat inFormat, uint32_t inLayerCount, uint64_t usage, std::string requestorName)
: GraphicBuffer()
{
mInitCheck = initWithSize(inWidth, inHeight, inFormat, inLayerCount,
@@ -139,7 +138,7 @@
static_cast<int>(inHeight) == height &&
inFormat == format &&
inLayerCount == layerCount &&
- static_cast<int>(inUsage) == usage)
+ inUsage == usage)
return NO_ERROR;
if (handle) {
@@ -147,8 +146,7 @@
allocator.free(handle);
handle = 0;
}
- return initWithSize(inWidth, inHeight, inFormat, inLayerCount,
- inUsage, "[Reallocation]");
+ return initWithSize(inWidth, inHeight, inFormat, inLayerCount, inUsage, "[Reallocation]");
}
bool GraphicBuffer::needsReallocation(uint32_t inWidth, uint32_t inHeight,
@@ -158,7 +156,7 @@
if (static_cast<int>(inHeight) != height) return true;
if (inFormat != format) return true;
if (inLayerCount != layerCount) return true;
- if ((static_cast<uint32_t>(usage) & inUsage) != inUsage) return true;
+ if ((usage & inUsage) != inUsage) return true;
return false;
}
@@ -172,11 +170,14 @@
inUsage, &handle, &outStride, mId,
std::move(requestorName));
if (err == NO_ERROR) {
+ mBufferMapper.getTransportSize(handle, &mTransportNumFds, &mTransportNumInts);
+
width = static_cast<int>(inWidth);
height = static_cast<int>(inHeight);
format = inFormat;
layerCount = inLayerCount;
- usage = static_cast<int>(inUsage);
+ usage = inUsage;
+ usage_deprecated = int(usage);
stride = static_cast<int>(outStride);
}
return err;
@@ -191,7 +192,8 @@
ANativeWindowBuffer::height = static_cast<int>(height);
ANativeWindowBuffer::stride = static_cast<int>(stride);
ANativeWindowBuffer::format = format;
- ANativeWindowBuffer::usage = static_cast<int>(usage);
+ ANativeWindowBuffer::usage = usage;
+ ANativeWindowBuffer::usage_deprecated = int(usage);
ANativeWindowBuffer::layerCount = layerCount;
@@ -199,7 +201,8 @@
if (method == TAKE_UNREGISTERED_HANDLE || method == CLONE_HANDLE) {
buffer_handle_t importedHandle;
- status_t err = mBufferMapper.importBuffer(handle, &importedHandle);
+ status_t err = mBufferMapper.importBuffer(handle, width, height,
+ layerCount, format, usage, stride, &importedHandle);
if (err != NO_ERROR) {
initWithHandle(nullptr, WRAP_HANDLE, 0, 0, 0, 0, 0, 0);
@@ -212,6 +215,7 @@
}
handle = importedHandle;
+ mBufferMapper.getTransportSize(handle, &mTransportNumFds, &mTransportNumInts);
}
ANativeWindowBuffer::handle = handle;
@@ -312,8 +316,7 @@
width, height);
return BAD_VALUE;
}
- status_t res = getBufferMapper().lockAsyncYCbCr(handle, inUsage, rect,
- ycbcr, fenceFd);
+ status_t res = getBufferMapper().lockAsyncYCbCr(handle, inUsage, rect, ycbcr, fenceFd);
return res;
}
@@ -324,11 +327,11 @@
}
size_t GraphicBuffer::getFlattenedSize() const {
- return static_cast<size_t>(12 + (handle ? handle->numInts : 0)) * sizeof(int);
+ return static_cast<size_t>(13 + (handle ? mTransportNumInts : 0)) * sizeof(int);
}
size_t GraphicBuffer::getFdCount() const {
- return static_cast<size_t>(handle ? handle->numFds : 0);
+ return static_cast<size_t>(handle ? mTransportNumFds : 0);
}
status_t GraphicBuffer::flatten(void*& buffer, size_t& size, int*& fds, size_t& count) const {
@@ -339,33 +342,33 @@
if (count < fdCountNeeded) return NO_MEMORY;
int32_t* buf = static_cast<int32_t*>(buffer);
- buf[0] = 'GBFR';
+ buf[0] = 'GB01';
buf[1] = width;
buf[2] = height;
buf[3] = stride;
buf[4] = format;
buf[5] = static_cast<int32_t>(layerCount);
- buf[6] = usage;
+ buf[6] = int(usage); // low 32-bits
buf[7] = static_cast<int32_t>(mId >> 32);
buf[8] = static_cast<int32_t>(mId & 0xFFFFFFFFull);
buf[9] = static_cast<int32_t>(mGenerationNumber);
buf[10] = 0;
buf[11] = 0;
+ buf[12] = int(usage >> 32); // high 32-bits
if (handle) {
- buf[10] = handle->numFds;
- buf[11] = handle->numInts;
- memcpy(fds, handle->data,
- static_cast<size_t>(handle->numFds) * sizeof(int));
- memcpy(&buf[12], handle->data + handle->numFds,
- static_cast<size_t>(handle->numInts) * sizeof(int));
+ buf[10] = int32_t(mTransportNumFds);
+ buf[11] = int32_t(mTransportNumInts);
+ memcpy(fds, handle->data, static_cast<size_t>(mTransportNumFds) * sizeof(int));
+ memcpy(buf + 13, handle->data + handle->numFds,
+ static_cast<size_t>(mTransportNumInts) * sizeof(int));
}
buffer = static_cast<void*>(static_cast<uint8_t*>(buffer) + sizeNeeded);
size -= sizeNeeded;
if (handle) {
- fds += handle->numFds;
- count -= static_cast<size_t>(handle->numFds);
+ fds += mTransportNumFds;
+ count -= static_cast<size_t>(mTransportNumFds);
}
return NO_ERROR;
@@ -373,10 +376,21 @@
status_t GraphicBuffer::unflatten(
void const*& buffer, size_t& size, int const*& fds, size_t& count) {
- if (size < 12 * sizeof(int)) return NO_MEMORY;
int const* buf = static_cast<int const*>(buffer);
- if (buf[0] != 'GBFR') return BAD_TYPE;
+
+ // NOTE: it turns out that some media code generates a flattened GraphicBuffer manually!!!!!
+ // see H2BGraphicBufferProducer.cpp
+ uint32_t flattenWordCount = 0;
+ if (buf[0] == 'GB01') {
+ // new version with 64-bits usage bits
+ flattenWordCount = 13;
+ } else if (buf[0] == 'GBFR') {
+ // old version, when usage bits were 32-bits
+ flattenWordCount = 12;
+ } else {
+ return BAD_TYPE;
+ }
const size_t numFds = static_cast<size_t>(buf[10]);
const size_t numInts = static_cast<size_t>(buf[11]);
@@ -386,15 +400,16 @@
// chosen to be high enough to not cause issues and low enough to prevent
// overflow problems.
const size_t maxNumber = 4096;
- if (numFds >= maxNumber || numInts >= (maxNumber - 12)) {
- width = height = stride = format = layerCount = usage = 0;
+ if (numFds >= maxNumber || numInts >= (maxNumber - flattenWordCount)) {
+ width = height = stride = format = usage_deprecated = 0;
+ layerCount = 0;
+ usage = 0;
handle = NULL;
- ALOGE("unflatten: numFds or numInts is too large: %zd, %zd",
- numFds, numInts);
+ ALOGE("unflatten: numFds or numInts is too large: %zd, %zd", numFds, numInts);
return BAD_VALUE;
}
- const size_t sizeNeeded = (12 + numInts) * sizeof(int);
+ const size_t sizeNeeded = (flattenWordCount + numInts) * sizeof(int);
if (size < sizeNeeded) return NO_MEMORY;
size_t fdCountNeeded = numFds;
@@ -411,20 +426,29 @@
stride = buf[3];
format = buf[4];
layerCount = static_cast<uintptr_t>(buf[5]);
- usage = buf[6];
+ usage_deprecated = buf[6];
+ if (flattenWordCount == 13) {
+ usage = (uint64_t(buf[12]) << 32) | uint32_t(buf[6]);
+ } else {
+ usage = uint64_t(usage_deprecated);
+ }
native_handle* h = native_handle_create(
static_cast<int>(numFds), static_cast<int>(numInts));
if (!h) {
- width = height = stride = format = layerCount = usage = 0;
+ width = height = stride = format = usage_deprecated = 0;
+ layerCount = 0;
+ usage = 0;
handle = NULL;
ALOGE("unflatten: native_handle_create failed");
return NO_MEMORY;
}
memcpy(h->data, fds, numFds * sizeof(int));
- memcpy(h->data + numFds, &buf[12], numInts * sizeof(int));
+ memcpy(h->data + numFds, buf + flattenWordCount, numInts * sizeof(int));
handle = h;
} else {
- width = height = stride = format = layerCount = usage = 0;
+ width = height = stride = format = usage_deprecated = 0;
+ layerCount = 0;
+ usage = 0;
handle = NULL;
}
@@ -437,18 +461,21 @@
if (handle != 0) {
buffer_handle_t importedHandle;
- status_t err = mBufferMapper.importBuffer(handle, &importedHandle);
+ status_t err = mBufferMapper.importBuffer(handle, uint32_t(width), uint32_t(height),
+ uint32_t(layerCount), format, usage, uint32_t(stride), &importedHandle);
if (err != NO_ERROR) {
- width = height = stride = format = layerCount = usage = 0;
+ width = height = stride = format = usage_deprecated = 0;
+ layerCount = 0;
+ usage = 0;
handle = NULL;
- ALOGE("unflatten: registerBuffer failed: %s (%d)",
- strerror(-err), err);
+ ALOGE("unflatten: registerBuffer failed: %s (%d)", strerror(-err), err);
return err;
}
native_handle_close(handle);
native_handle_delete(const_cast<native_handle_t*>(handle));
handle = importedHandle;
+ mBufferMapper.getTransportSize(handle, &mTransportNumFds, &mTransportNumInts);
}
buffer = static_cast<void const*>(static_cast<uint8_t const*>(buffer) + sizeNeeded);
diff --git a/libs/ui/GraphicBufferMapper.cpp b/libs/ui/GraphicBufferMapper.cpp
index b9fa640..2cac287 100644
--- a/libs/ui/GraphicBufferMapper.cpp
+++ b/libs/ui/GraphicBufferMapper.cpp
@@ -42,23 +42,52 @@
ANDROID_SINGLETON_STATIC_INSTANCE( GraphicBufferMapper )
+void GraphicBufferMapper::preloadHal() {
+ Gralloc2::Mapper::preload();
+}
+
GraphicBufferMapper::GraphicBufferMapper()
: mMapper(std::make_unique<const Gralloc2::Mapper>())
{
}
status_t GraphicBufferMapper::importBuffer(buffer_handle_t rawHandle,
+ uint32_t width, uint32_t height, uint32_t layerCount,
+ PixelFormat format, uint64_t usage, uint32_t stride,
buffer_handle_t* outHandle)
{
ATRACE_CALL();
+ buffer_handle_t bufferHandle;
Gralloc2::Error error = mMapper->importBuffer(
- hardware::hidl_handle(rawHandle), outHandle);
+ hardware::hidl_handle(rawHandle), &bufferHandle);
+ if (error != Gralloc2::Error::NONE) {
+ ALOGW("importBuffer(%p) failed: %d", rawHandle, error);
+ return static_cast<status_t>(error);
+ }
- ALOGW_IF(error != Gralloc2::Error::NONE, "importBuffer(%p) failed: %d",
- rawHandle, error);
+ Gralloc2::IMapper::BufferDescriptorInfo info = {};
+ info.width = width;
+ info.height = height;
+ info.layerCount = layerCount;
+ info.format = static_cast<Gralloc2::PixelFormat>(format);
+ info.usage = usage;
+ error = mMapper->validateBufferSize(bufferHandle, info, stride);
+ if (error != Gralloc2::Error::NONE) {
+ ALOGE("validateBufferSize(%p) failed: %d", rawHandle, error);
+ freeBuffer(bufferHandle);
+ return static_cast<status_t>(error);
+ }
- return static_cast<status_t>(error);
+ *outHandle = bufferHandle;
+
+ return NO_ERROR;
+}
+
+void GraphicBufferMapper::getTransportSize(buffer_handle_t handle,
+ uint32_t* outTransportNumFds, uint32_t* outTransportNumInts)
+{
+ mMapper->getTransportSize(handle, outTransportNumFds, outTransportNumInts);
}
status_t GraphicBufferMapper::freeBuffer(buffer_handle_t handle)
@@ -95,7 +124,7 @@
{
int32_t fenceFd = -1;
status_t error = unlockAsync(handle, &fenceFd);
- if (error == NO_ERROR) {
+ if (error == NO_ERROR && fenceFd >= 0) {
sync_wait(fenceFd, -1);
close(fenceFd);
}
@@ -125,29 +154,6 @@
return static_cast<status_t>(error);
}
-static inline bool isValidYCbCrPlane(const android_flex_plane_t& plane) {
- if (plane.bits_per_component != 8) {
- ALOGV("Invalid number of bits per component: %d",
- plane.bits_per_component);
- return false;
- }
- if (plane.bits_used != 8) {
- ALOGV("Invalid number of bits used: %d", plane.bits_used);
- return false;
- }
-
- bool hasValidIncrement = plane.h_increment == 1 ||
- (plane.component != FLEX_COMPONENT_Y && plane.h_increment == 2);
- hasValidIncrement = hasValidIncrement && plane.v_increment > 0;
- if (!hasValidIncrement) {
- ALOGV("Invalid increment: h %d v %d", plane.h_increment,
- plane.v_increment);
- return false;
- }
-
- return true;
-}
-
status_t GraphicBufferMapper::lockAsyncYCbCr(buffer_handle_t handle,
uint32_t usage, const Rect& bounds, android_ycbcr *ycbcr, int fenceFd)
{
diff --git a/libs/ui/HdrCapabilities.cpp b/libs/ui/HdrCapabilities.cpp
index 39adc5e..755e60c 100644
--- a/libs/ui/HdrCapabilities.cpp
+++ b/libs/ui/HdrCapabilities.cpp
@@ -76,7 +76,7 @@
mMaxAverageLuminance = reinterpret_cast<float const&>(buf[1]);
mMinLuminance = reinterpret_cast<float const&>(buf[2]);
if (itemCount) {
- mSupportedHdrTypes.reserve(itemCount);
+ mSupportedHdrTypes.resize(itemCount);
for (size_t i = 0; i < itemCount; ++i) {
mSupportedHdrTypes[i] = buf[4 + i];
}
diff --git a/libs/ui/include/ui/DebugUtils.h b/libs/ui/include/ui/DebugUtils.h
index 30f4a59..dad9446 100644
--- a/libs/ui/include/ui/DebugUtils.h
+++ b/libs/ui/include/ui/DebugUtils.h
@@ -21,9 +21,14 @@
#include <string>
+namespace android {
+class Rect;
+}
+
std::string decodeStandard(android_dataspace dataspace);
std::string decodeTransfer(android_dataspace dataspace);
std::string decodeRange(android_dataspace dataspace);
std::string dataspaceDetails(android_dataspace dataspace);
std::string decodeColorMode(android_color_mode colormode);
std::string decodePixelFormat(android::PixelFormat format);
+std::string to_string(const android::Rect& rect);
diff --git a/libs/ui/include/ui/Gralloc2.h b/libs/ui/include/ui/Gralloc2.h
index e7b8ca9..69c35f7 100644
--- a/libs/ui/include/ui/Gralloc2.h
+++ b/libs/ui/include/ui/Gralloc2.h
@@ -21,6 +21,7 @@
#include <android/hardware/graphics/allocator/2.0/IAllocator.h>
#include <android/hardware/graphics/mapper/2.0/IMapper.h>
+#include <android/hardware/graphics/mapper/2.1/IMapper.h>
#include <utils/StrongPointer.h>
namespace android {
@@ -38,6 +39,8 @@
// A wrapper to IMapper
class Mapper {
public:
+ static void preload();
+
Mapper();
Error createDescriptor(
@@ -53,6 +56,13 @@
void freeBuffer(buffer_handle_t bufferHandle) const;
+ Error validateBufferSize(buffer_handle_t bufferHandle,
+ const IMapper::BufferDescriptorInfo& descriptorInfo,
+ uint32_t stride) const;
+
+ void getTransportSize(buffer_handle_t bufferHandle,
+ uint32_t* outNumFds, uint32_t* outNumInts) const;
+
// The ownership of acquireFence is always transferred to the callee, even
// on errors.
Error lock(buffer_handle_t bufferHandle, uint64_t usage,
@@ -71,6 +81,7 @@
private:
sp<IMapper> mMapper;
+ sp<hardware::graphics::mapper::V2_1::IMapper> mMapperV2_1;
};
// A wrapper to IAllocator
diff --git a/libs/ui/include/ui/GraphicBuffer.h b/libs/ui/include/ui/GraphicBuffer.h
index 9a5aa69..e794462 100644
--- a/libs/ui/include/ui/GraphicBuffer.h
+++ b/libs/ui/include/ui/GraphicBuffer.h
@@ -141,7 +141,7 @@
uint32_t getWidth() const { return static_cast<uint32_t>(width); }
uint32_t getHeight() const { return static_cast<uint32_t>(height); }
uint32_t getStride() const { return static_cast<uint32_t>(stride); }
- uint32_t getUsage() const { return static_cast<uint32_t>(usage); }
+ uint64_t getUsage() const { return usage; }
PixelFormat getPixelFormat() const { return format; }
uint32_t getLayerCount() const { return static_cast<uint32_t>(layerCount); }
Rect getBounds() const { return Rect(width, height); }
@@ -230,6 +230,10 @@
GraphicBufferMapper& mBufferMapper;
ssize_t mInitCheck;
+ // numbers of fds/ints in native_handle_t to flatten
+ uint32_t mTransportNumFds;
+ uint32_t mTransportNumInts;
+
uint64_t mId;
// Stores the generation number of this buffer. If this number does not
diff --git a/libs/ui/include/ui/GraphicBufferMapper.h b/libs/ui/include/ui/GraphicBufferMapper.h
index e0702e9..7cf003d 100644
--- a/libs/ui/include/ui/GraphicBufferMapper.h
+++ b/libs/ui/include/ui/GraphicBufferMapper.h
@@ -22,6 +22,7 @@
#include <memory>
+#include <ui/PixelFormat.h>
#include <utils/Singleton.h>
@@ -43,15 +44,21 @@
class GraphicBufferMapper : public Singleton<GraphicBufferMapper>
{
public:
+ static void preloadHal();
static inline GraphicBufferMapper& get() { return getInstance(); }
// The imported outHandle must be freed with freeBuffer when no longer
// needed. rawHandle is owned by the caller.
status_t importBuffer(buffer_handle_t rawHandle,
+ uint32_t width, uint32_t height, uint32_t layerCount,
+ PixelFormat format, uint64_t usage, uint32_t stride,
buffer_handle_t* outHandle);
status_t freeBuffer(buffer_handle_t handle);
+ void getTransportSize(buffer_handle_t handle,
+ uint32_t* outTransportNumFds, uint32_t* outTransportNumInts);
+
status_t lock(buffer_handle_t handle,
uint32_t usage, const Rect& bounds, void** vaddr);
diff --git a/libs/ui/tests/Android.bp b/libs/ui/tests/Android.bp
index 6733505..08067fc 100644
--- a/libs/ui/tests/Android.bp
+++ b/libs/ui/tests/Android.bp
@@ -18,10 +18,12 @@
name: "Region_test",
shared_libs: ["libui"],
srcs: ["Region_test.cpp"],
+ cflags: ["-Wall", "-Werror"],
}
cc_test {
name: "colorspace_test",
shared_libs: ["libui"],
srcs: ["colorspace_test.cpp"],
+ cflags: ["-Wall", "-Werror"],
}
diff --git a/libs/vr/libbufferhub/Android.bp b/libs/vr/libbufferhub/Android.bp
index da0ea24..e3cb494 100644
--- a/libs/vr/libbufferhub/Android.bp
+++ b/libs/vr/libbufferhub/Android.bp
@@ -37,7 +37,8 @@
"libnativewindow"
]
-HeaderLibraries = [
+headerLibraries = [
+ "libdvr_headers",
"libnativebase_headers",
]
@@ -45,12 +46,13 @@
srcs: sourceFiles,
cflags: [
"-DLOG_TAG=\"libbufferhub\"",
- "-DTRACE=0"
+ "-DTRACE=0",
+ "-DATRACE_TAG=ATRACE_TAG_GRAPHICS",
],
export_include_dirs: localIncludeFiles,
static_libs: staticLibraries,
shared_libs: sharedLibraries,
- header_libs: HeaderLibraries,
+ header_libs: headerLibraries,
name: "libbufferhub",
export_header_lib_headers: [
"libnativebase_headers",
@@ -59,9 +61,10 @@
cc_test {
tags: ["optional"],
- srcs: ["bufferhub_tests.cpp"],
+ srcs: ["buffer_hub-test.cpp"],
static_libs: ["libbufferhub"] + staticLibraries,
shared_libs: sharedLibraries,
- name: "bufferhub_tests",
+ header_libs: headerLibraries,
+ name: "buffer_hub-test",
}
diff --git a/libs/vr/libbufferhub/buffer_hub-test.cpp b/libs/vr/libbufferhub/buffer_hub-test.cpp
new file mode 100644
index 0000000..a5cf9ae
--- /dev/null
+++ b/libs/vr/libbufferhub/buffer_hub-test.cpp
@@ -0,0 +1,781 @@
+#include <gtest/gtest.h>
+#include <poll.h>
+#include <private/dvr/buffer_hub_client.h>
+#include <private/dvr/bufferhub_rpc.h>
+#include <sys/epoll.h>
+#include <sys/eventfd.h>
+
+#include <mutex>
+#include <thread>
+
+#define RETRY_EINTR(fnc_call) \
+ ([&]() -> decltype(fnc_call) { \
+ decltype(fnc_call) result; \
+ do { \
+ result = (fnc_call); \
+ } while (result == -1 && errno == EINTR); \
+ return result; \
+ })()
+
+using android::dvr::BufferConsumer;
+using android::dvr::BufferHubDefs::kConsumerStateMask;
+using android::dvr::BufferHubDefs::kProducerStateBit;
+using android::dvr::BufferHubDefs::IsBufferGained;
+using android::dvr::BufferHubDefs::IsBufferPosted;
+using android::dvr::BufferHubDefs::IsBufferAcquired;
+using android::dvr::BufferHubDefs::IsBufferReleased;
+using android::dvr::BufferProducer;
+using android::pdx::LocalHandle;
+
+const int kWidth = 640;
+const int kHeight = 480;
+const int kFormat = HAL_PIXEL_FORMAT_RGBA_8888;
+const int kUsage = 0;
+const uint64_t kContext = 42;
+const size_t kMaxConsumerCount = 63;
+const int kPollTimeoutMs = 100;
+
+using LibBufferHubTest = ::testing::Test;
+
+TEST_F(LibBufferHubTest, TestBasicUsage) {
+ std::unique_ptr<BufferProducer> p = BufferProducer::Create(
+ kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
+ ASSERT_TRUE(p.get() != nullptr);
+ std::unique_ptr<BufferConsumer> c =
+ BufferConsumer::Import(p->CreateConsumer());
+ ASSERT_TRUE(c.get() != nullptr);
+ // Check that consumers can spawn other consumers.
+ std::unique_ptr<BufferConsumer> c2 =
+ BufferConsumer::Import(c->CreateConsumer());
+ ASSERT_TRUE(c2.get() != nullptr);
+
+ // Producer state mask is unique, i.e. 1.
+ EXPECT_EQ(p->buffer_state_bit(), kProducerStateBit);
+ // Consumer state mask cannot have producer bit on.
+ EXPECT_EQ(c->buffer_state_bit() & kProducerStateBit, 0U);
+ // Consumer state mask must be a single, i.e. power of 2.
+ EXPECT_NE(c->buffer_state_bit(), 0U);
+ EXPECT_EQ(c->buffer_state_bit() & (c->buffer_state_bit() - 1), 0U);
+ // Consumer state mask cannot have producer bit on.
+ EXPECT_EQ(c2->buffer_state_bit() & kProducerStateBit, 0U);
+ // Consumer state mask must be a single, i.e. power of 2.
+ EXPECT_NE(c2->buffer_state_bit(), 0U);
+ EXPECT_EQ(c2->buffer_state_bit() & (c2->buffer_state_bit() - 1), 0U);
+ // Each consumer should have unique bit.
+ EXPECT_EQ(c->buffer_state_bit() & c2->buffer_state_bit(), 0U);
+
+ // Initial state: producer not available, consumers not available.
+ EXPECT_EQ(0, RETRY_EINTR(p->Poll(kPollTimeoutMs)));
+ EXPECT_EQ(0, RETRY_EINTR(c->Poll(kPollTimeoutMs)));
+ EXPECT_EQ(0, RETRY_EINTR(c2->Poll(kPollTimeoutMs)));
+
+ EXPECT_EQ(0, p->Post(LocalHandle(), kContext));
+
+ // New state: producer not available, consumers available.
+ EXPECT_EQ(0, RETRY_EINTR(p->Poll(kPollTimeoutMs)));
+ EXPECT_EQ(1, RETRY_EINTR(c->Poll(kPollTimeoutMs)));
+ EXPECT_EQ(1, RETRY_EINTR(c2->Poll(kPollTimeoutMs)));
+
+ uint64_t context;
+ LocalHandle fence;
+ EXPECT_EQ(0, c->Acquire(&fence, &context));
+ EXPECT_EQ(kContext, context);
+ EXPECT_EQ(0, RETRY_EINTR(c->Poll(kPollTimeoutMs)));
+ EXPECT_EQ(1, RETRY_EINTR(c2->Poll(kPollTimeoutMs)));
+
+ EXPECT_EQ(0, c2->Acquire(&fence, &context));
+ EXPECT_EQ(kContext, context);
+ EXPECT_EQ(0, RETRY_EINTR(c2->Poll(kPollTimeoutMs)));
+ EXPECT_EQ(0, RETRY_EINTR(c->Poll(kPollTimeoutMs)));
+
+ EXPECT_EQ(0, c->Release(LocalHandle()));
+ EXPECT_EQ(0, RETRY_EINTR(p->Poll(kPollTimeoutMs)));
+ EXPECT_EQ(0, c2->Discard());
+
+ EXPECT_EQ(1, RETRY_EINTR(p->Poll(kPollTimeoutMs)));
+ EXPECT_EQ(0, p->Gain(&fence));
+ EXPECT_EQ(0, RETRY_EINTR(p->Poll(kPollTimeoutMs)));
+ EXPECT_EQ(0, RETRY_EINTR(c->Poll(kPollTimeoutMs)));
+ EXPECT_EQ(0, RETRY_EINTR(c2->Poll(kPollTimeoutMs)));
+}
+
+TEST_F(LibBufferHubTest, TestEpoll) {
+ std::unique_ptr<BufferProducer> p = BufferProducer::Create(
+ kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
+ ASSERT_TRUE(p.get() != nullptr);
+ std::unique_ptr<BufferConsumer> c =
+ BufferConsumer::Import(p->CreateConsumer());
+ ASSERT_TRUE(c.get() != nullptr);
+
+ LocalHandle epoll_fd{epoll_create1(EPOLL_CLOEXEC)};
+ ASSERT_TRUE(epoll_fd.IsValid());
+
+ epoll_event event;
+ std::array<epoll_event, 64> events;
+
+ auto event_sources = p->GetEventSources();
+ ASSERT_LT(event_sources.size(), events.size());
+
+ for (const auto& event_source : event_sources) {
+ event = {.events = event_source.event_mask | EPOLLET,
+ .data = {.fd = p->event_fd()}};
+ ASSERT_EQ(0, epoll_ctl(epoll_fd.Get(), EPOLL_CTL_ADD, event_source.event_fd,
+ &event));
+ }
+
+ event_sources = c->GetEventSources();
+ ASSERT_LT(event_sources.size(), events.size());
+
+ for (const auto& event_source : event_sources) {
+ event = {.events = event_source.event_mask | EPOLLET,
+ .data = {.fd = c->event_fd()}};
+ ASSERT_EQ(0, epoll_ctl(epoll_fd.Get(), EPOLL_CTL_ADD, event_source.event_fd,
+ &event));
+ }
+
+ // No events should be signaled initially.
+ ASSERT_EQ(0, epoll_wait(epoll_fd.Get(), events.data(), events.size(), 0));
+
+ // Post the producer and check for consumer signal.
+ EXPECT_EQ(0, p->Post({}, kContext));
+ ASSERT_EQ(1, epoll_wait(epoll_fd.Get(), events.data(), events.size(),
+ kPollTimeoutMs));
+ ASSERT_TRUE(events[0].events & EPOLLIN);
+ ASSERT_EQ(c->event_fd(), events[0].data.fd);
+
+ // Save the event bits to translate later.
+ event = events[0];
+
+ // Check for events again. Edge-triggered mode should prevent any.
+ EXPECT_EQ(0, epoll_wait(epoll_fd.Get(), events.data(), events.size(),
+ kPollTimeoutMs));
+ EXPECT_EQ(0, epoll_wait(epoll_fd.Get(), events.data(), events.size(),
+ kPollTimeoutMs));
+ EXPECT_EQ(0, epoll_wait(epoll_fd.Get(), events.data(), events.size(),
+ kPollTimeoutMs));
+ EXPECT_EQ(0, epoll_wait(epoll_fd.Get(), events.data(), events.size(),
+ kPollTimeoutMs));
+
+ // Translate the events.
+ auto event_status = c->GetEventMask(event.events);
+ ASSERT_TRUE(event_status);
+ ASSERT_TRUE(event_status.get() & EPOLLIN);
+
+ // Check for events again. Edge-triggered mode should prevent any.
+ EXPECT_EQ(0, epoll_wait(epoll_fd.Get(), events.data(), events.size(),
+ kPollTimeoutMs));
+}
+
+TEST_F(LibBufferHubTest, TestStateMask) {
+ std::unique_ptr<BufferProducer> p = BufferProducer::Create(
+ kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
+ ASSERT_TRUE(p.get() != nullptr);
+
+ // It's ok to create up to kMaxConsumerCount consumer buffers.
+ uint64_t buffer_state_bits = p->buffer_state_bit();
+ std::array<std::unique_ptr<BufferConsumer>, kMaxConsumerCount> cs;
+ for (size_t i = 0; i < kMaxConsumerCount; i++) {
+ cs[i] = BufferConsumer::Import(p->CreateConsumer());
+ ASSERT_TRUE(cs[i].get() != nullptr);
+ // Expect all buffers have unique state mask.
+ EXPECT_EQ(buffer_state_bits & cs[i]->buffer_state_bit(), 0U);
+ buffer_state_bits |= cs[i]->buffer_state_bit();
+ }
+ EXPECT_EQ(buffer_state_bits, kProducerStateBit | kConsumerStateMask);
+
+ // The 64th creation will fail with out-of-memory error.
+ auto state = p->CreateConsumer();
+ EXPECT_EQ(state.error(), E2BIG);
+
+ // Release any consumer should allow us to re-create.
+ for (size_t i = 0; i < kMaxConsumerCount; i++) {
+ buffer_state_bits &= ~cs[i]->buffer_state_bit();
+ cs[i] = nullptr;
+ cs[i] = BufferConsumer::Import(p->CreateConsumer());
+ ASSERT_TRUE(cs[i].get() != nullptr);
+ // The released state mask will be reused.
+ EXPECT_EQ(buffer_state_bits & cs[i]->buffer_state_bit(), 0U);
+ buffer_state_bits |= cs[i]->buffer_state_bit();
+ EXPECT_EQ(buffer_state_bits, kProducerStateBit | kConsumerStateMask);
+ }
+}
+
+TEST_F(LibBufferHubTest, TestStateTransitions) {
+ std::unique_ptr<BufferProducer> p = BufferProducer::Create(
+ kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
+ ASSERT_TRUE(p.get() != nullptr);
+ std::unique_ptr<BufferConsumer> c =
+ BufferConsumer::Import(p->CreateConsumer());
+ ASSERT_TRUE(c.get() != nullptr);
+
+ uint64_t context;
+ LocalHandle fence;
+
+ // The producer buffer starts in gained state.
+
+ // Acquire, release, and gain in gained state should fail.
+ EXPECT_EQ(-EBUSY, c->Acquire(&fence, &context));
+ EXPECT_EQ(-EBUSY, c->Release(LocalHandle()));
+ EXPECT_EQ(-EALREADY, p->Gain(&fence));
+
+ // Post in gained state should succeed.
+ EXPECT_EQ(0, p->Post(LocalHandle(), kContext));
+
+ // Post, release, and gain in posted state should fail.
+ EXPECT_EQ(-EBUSY, p->Post(LocalHandle(), kContext));
+ EXPECT_EQ(-EBUSY, c->Release(LocalHandle()));
+ EXPECT_EQ(-EBUSY, p->Gain(&fence));
+
+ // Acquire in posted state should succeed.
+ EXPECT_LE(0, c->Acquire(&fence, &context));
+
+ // Acquire, post, and gain in acquired state should fail.
+ EXPECT_EQ(-EBUSY, c->Acquire(&fence, &context));
+ EXPECT_EQ(-EBUSY, p->Post(LocalHandle(), kContext));
+ EXPECT_EQ(-EBUSY, p->Gain(&fence));
+
+ // Release in acquired state should succeed.
+ EXPECT_EQ(0, c->Release(LocalHandle()));
+ EXPECT_LT(0, RETRY_EINTR(p->Poll(kPollTimeoutMs)));
+
+ // Release, acquire, and post in released state should fail.
+ EXPECT_EQ(-EBUSY, c->Release(LocalHandle()));
+ EXPECT_EQ(-EBUSY, c->Acquire(&fence, &context));
+ EXPECT_EQ(-EBUSY, p->Post(LocalHandle(), kContext));
+
+ // Gain in released state should succeed.
+ EXPECT_EQ(0, p->Gain(&fence));
+
+ // Acquire, release, and gain in gained state should fail.
+ EXPECT_EQ(-EBUSY, c->Acquire(&fence, &context));
+ EXPECT_EQ(-EBUSY, c->Release(LocalHandle()));
+ EXPECT_EQ(-EALREADY, p->Gain(&fence));
+}
+
+TEST_F(LibBufferHubTest, TestAsyncStateTransitions) {
+ std::unique_ptr<BufferProducer> p = BufferProducer::Create(
+ kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
+ ASSERT_TRUE(p.get() != nullptr);
+ std::unique_ptr<BufferConsumer> c =
+ BufferConsumer::Import(p->CreateConsumer());
+ ASSERT_TRUE(c.get() != nullptr);
+
+ DvrNativeBufferMetadata metadata;
+ LocalHandle invalid_fence;
+
+ // The producer buffer starts in gained state.
+
+ // Acquire, release, and gain in gained state should fail.
+ EXPECT_EQ(-EBUSY, c->AcquireAsync(&metadata, &invalid_fence));
+ EXPECT_FALSE(invalid_fence.IsValid());
+ EXPECT_EQ(-EBUSY, c->ReleaseAsync(&metadata, invalid_fence));
+ EXPECT_EQ(-EALREADY, p->GainAsync(&metadata, &invalid_fence));
+ EXPECT_FALSE(invalid_fence.IsValid());
+
+ // Post in gained state should succeed.
+ EXPECT_EQ(0, p->PostAsync(&metadata, invalid_fence));
+ EXPECT_EQ(p->buffer_state(), c->buffer_state());
+ EXPECT_TRUE(IsBufferPosted(p->buffer_state()));
+
+ // Post, release, and gain in posted state should fail.
+ EXPECT_EQ(-EBUSY, p->PostAsync(&metadata, invalid_fence));
+ EXPECT_EQ(-EBUSY, c->ReleaseAsync(&metadata, invalid_fence));
+ EXPECT_EQ(-EBUSY, p->GainAsync(&metadata, &invalid_fence));
+ EXPECT_FALSE(invalid_fence.IsValid());
+
+ // Acquire in posted state should succeed.
+ EXPECT_LT(0, RETRY_EINTR(c->Poll(kPollTimeoutMs)));
+ EXPECT_EQ(0, c->AcquireAsync(&metadata, &invalid_fence));
+ EXPECT_FALSE(invalid_fence.IsValid());
+ EXPECT_EQ(p->buffer_state(), c->buffer_state());
+ EXPECT_TRUE(IsBufferAcquired(p->buffer_state()));
+
+ // Acquire, post, and gain in acquired state should fail.
+ EXPECT_EQ(-EBUSY, c->AcquireAsync(&metadata, &invalid_fence));
+ EXPECT_FALSE(invalid_fence.IsValid());
+ EXPECT_EQ(-EBUSY, p->PostAsync(&metadata, invalid_fence));
+ EXPECT_EQ(-EBUSY, p->GainAsync(&metadata, &invalid_fence));
+ EXPECT_FALSE(invalid_fence.IsValid());
+
+ // Release in acquired state should succeed.
+ EXPECT_EQ(0, c->ReleaseAsync(&metadata, invalid_fence));
+ EXPECT_LT(0, RETRY_EINTR(p->Poll(kPollTimeoutMs)));
+ EXPECT_EQ(p->buffer_state(), c->buffer_state());
+ EXPECT_TRUE(IsBufferReleased(p->buffer_state()));
+
+ // Release, acquire, and post in released state should fail.
+ EXPECT_EQ(-EBUSY, c->ReleaseAsync(&metadata, invalid_fence));
+ EXPECT_EQ(-EBUSY, c->AcquireAsync(&metadata, &invalid_fence));
+ EXPECT_FALSE(invalid_fence.IsValid());
+ EXPECT_EQ(-EBUSY, p->PostAsync(&metadata, invalid_fence));
+
+ // Gain in released state should succeed.
+ EXPECT_EQ(0, p->GainAsync(&metadata, &invalid_fence));
+ EXPECT_FALSE(invalid_fence.IsValid());
+ EXPECT_EQ(p->buffer_state(), c->buffer_state());
+ EXPECT_TRUE(IsBufferGained(p->buffer_state()));
+
+ // Acquire, release, and gain in gained state should fail.
+ EXPECT_EQ(-EBUSY, c->AcquireAsync(&metadata, &invalid_fence));
+ EXPECT_FALSE(invalid_fence.IsValid());
+ EXPECT_EQ(-EBUSY, c->ReleaseAsync(&metadata, invalid_fence));
+ EXPECT_EQ(-EALREADY, p->GainAsync(&metadata, &invalid_fence));
+ EXPECT_FALSE(invalid_fence.IsValid());
+}
+
+TEST_F(LibBufferHubTest, TestZeroConsumer) {
+ std::unique_ptr<BufferProducer> p = BufferProducer::Create(
+ kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
+ ASSERT_TRUE(p.get() != nullptr);
+
+ DvrNativeBufferMetadata metadata;
+ LocalHandle invalid_fence;
+
+ // Newly created.
+ EXPECT_TRUE(IsBufferGained(p->buffer_state()));
+ EXPECT_EQ(0, p->PostAsync(&metadata, invalid_fence));
+ EXPECT_TRUE(IsBufferPosted(p->buffer_state()));
+
+ // The buffer should stay in posted stay until a consumer picks it up.
+ EXPECT_GE(0, RETRY_EINTR(p->Poll(kPollTimeoutMs)));
+
+ // A new consumer should still be able to acquire the buffer immediately.
+ std::unique_ptr<BufferConsumer> c =
+ BufferConsumer::Import(p->CreateConsumer());
+ ASSERT_TRUE(c.get() != nullptr);
+ EXPECT_EQ(0, c->AcquireAsync(&metadata, &invalid_fence));
+ EXPECT_TRUE(IsBufferAcquired(c->buffer_state()));
+}
+
+TEST_F(LibBufferHubTest, TestMaxConsumers) {
+ std::unique_ptr<BufferProducer> p = BufferProducer::Create(
+ kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
+ ASSERT_TRUE(p.get() != nullptr);
+
+ std::array<std::unique_ptr<BufferConsumer>, kMaxConsumerCount> cs;
+ for (size_t i = 0; i < kMaxConsumerCount; i++) {
+ cs[i] = BufferConsumer::Import(p->CreateConsumer());
+ ASSERT_TRUE(cs[i].get() != nullptr);
+ EXPECT_TRUE(IsBufferGained(cs[i]->buffer_state()));
+ }
+
+ DvrNativeBufferMetadata metadata;
+ LocalHandle invalid_fence;
+
+ // Post the producer should trigger all consumers to be available.
+ EXPECT_EQ(0, p->PostAsync(&metadata, invalid_fence));
+ EXPECT_TRUE(IsBufferPosted(p->buffer_state()));
+ for (size_t i = 0; i < kMaxConsumerCount; i++) {
+ EXPECT_TRUE(IsBufferPosted(cs[i]->buffer_state(),
+ cs[i]->buffer_state_bit()));
+ EXPECT_LT(0, RETRY_EINTR(cs[i]->Poll(kPollTimeoutMs)));
+ EXPECT_EQ(0, cs[i]->AcquireAsync(&metadata, &invalid_fence));
+ EXPECT_TRUE(IsBufferAcquired(p->buffer_state()));
+ }
+
+ // All consumers have to release before the buffer is considered to be
+ // released.
+ for (size_t i = 0; i < kMaxConsumerCount; i++) {
+ EXPECT_FALSE(IsBufferReleased(p->buffer_state()));
+ EXPECT_EQ(0, cs[i]->ReleaseAsync(&metadata, invalid_fence));
+ }
+
+ EXPECT_LT(0, RETRY_EINTR(p->Poll(kPollTimeoutMs)));
+ EXPECT_TRUE(IsBufferReleased(p->buffer_state()));
+
+ // Buffer state cross all clients must be consistent.
+ for (size_t i = 0; i < kMaxConsumerCount; i++) {
+ EXPECT_EQ(p->buffer_state(), cs[i]->buffer_state());
+ }
+}
+
+TEST_F(LibBufferHubTest, TestCreateConsumerWhenBufferGained) {
+ std::unique_ptr<BufferProducer> p = BufferProducer::Create(
+ kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
+ ASSERT_TRUE(p.get() != nullptr);
+ EXPECT_TRUE(IsBufferGained(p->buffer_state()));
+
+ std::unique_ptr<BufferConsumer> c =
+ BufferConsumer::Import(p->CreateConsumer());
+ ASSERT_TRUE(c.get() != nullptr);
+ EXPECT_TRUE(IsBufferGained(c->buffer_state()));
+
+ DvrNativeBufferMetadata metadata;
+ LocalHandle invalid_fence;
+
+ // Post the gained buffer should signal already created consumer.
+ EXPECT_EQ(0, p->PostAsync(&metadata, invalid_fence));
+ EXPECT_TRUE(IsBufferPosted(p->buffer_state()));
+ EXPECT_LT(0, RETRY_EINTR(c->Poll(kPollTimeoutMs)));
+ EXPECT_EQ(0, c->AcquireAsync(&metadata, &invalid_fence));
+ EXPECT_TRUE(IsBufferAcquired(c->buffer_state()));
+}
+
+TEST_F(LibBufferHubTest, TestCreateConsumerWhenBufferPosted) {
+ std::unique_ptr<BufferProducer> p = BufferProducer::Create(
+ kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
+ ASSERT_TRUE(p.get() != nullptr);
+ EXPECT_TRUE(IsBufferGained(p->buffer_state()));
+
+ DvrNativeBufferMetadata metadata;
+ LocalHandle invalid_fence;
+
+ // Post the gained buffer before any consumer gets created.
+ EXPECT_EQ(0, p->PostAsync(&metadata, invalid_fence));
+ EXPECT_TRUE(IsBufferPosted(p->buffer_state()));
+
+ // Newly created consumer should be automatically sigalled.
+ std::unique_ptr<BufferConsumer> c =
+ BufferConsumer::Import(p->CreateConsumer());
+ ASSERT_TRUE(c.get() != nullptr);
+ EXPECT_TRUE(IsBufferPosted(c->buffer_state()));
+ EXPECT_EQ(0, c->AcquireAsync(&metadata, &invalid_fence));
+ EXPECT_TRUE(IsBufferAcquired(c->buffer_state()));
+}
+
+TEST_F(LibBufferHubTest, TestCreateConsumerWhenBufferReleased) {
+ std::unique_ptr<BufferProducer> p = BufferProducer::Create(
+ kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
+ ASSERT_TRUE(p.get() != nullptr);
+
+ std::unique_ptr<BufferConsumer> c1 =
+ BufferConsumer::Import(p->CreateConsumer());
+ ASSERT_TRUE(c1.get() != nullptr);
+
+ DvrNativeBufferMetadata metadata;
+ LocalHandle invalid_fence;
+
+ // Post, acquire, and release the buffer..
+ EXPECT_EQ(0, p->PostAsync(&metadata, invalid_fence));
+ EXPECT_LT(0, RETRY_EINTR(c1->Poll(kPollTimeoutMs)));
+ EXPECT_EQ(0, c1->AcquireAsync(&metadata, &invalid_fence));
+ EXPECT_EQ(0, c1->ReleaseAsync(&metadata, invalid_fence));
+
+ // Create another consumer immediately after the release, should not make the
+ // buffer un-released. This is guaranteed by IPC execution order in bufferhubd.
+ std::unique_ptr<BufferConsumer> c2 =
+ BufferConsumer::Import(p->CreateConsumer());
+ ASSERT_TRUE(c2.get() != nullptr);
+
+ EXPECT_LT(0, RETRY_EINTR(p->Poll(kPollTimeoutMs)));
+ EXPECT_TRUE(IsBufferReleased(p->buffer_state()));
+ EXPECT_EQ(0, p->GainAsync(&metadata, &invalid_fence));
+ EXPECT_TRUE(IsBufferGained(p->buffer_state()));
+}
+
+TEST_F(LibBufferHubTest, TestWithCustomMetadata) {
+ struct Metadata {
+ int64_t field1;
+ int64_t field2;
+ };
+ std::unique_ptr<BufferProducer> p = BufferProducer::Create(
+ kWidth, kHeight, kFormat, kUsage, sizeof(Metadata));
+ ASSERT_TRUE(p.get() != nullptr);
+ std::unique_ptr<BufferConsumer> c =
+ BufferConsumer::Import(p->CreateConsumer());
+ ASSERT_TRUE(c.get() != nullptr);
+
+ Metadata m = {1, 3};
+ EXPECT_EQ(0, p->Post(LocalHandle(), m));
+ EXPECT_LE(0, RETRY_EINTR(c->Poll(kPollTimeoutMs)));
+
+ LocalHandle fence;
+ Metadata m2 = {};
+ EXPECT_EQ(0, c->Acquire(&fence, &m2));
+ EXPECT_EQ(m.field1, m2.field1);
+ EXPECT_EQ(m.field2, m2.field2);
+
+ EXPECT_EQ(0, c->Release(LocalHandle()));
+ EXPECT_LT(0, RETRY_EINTR(p->Poll(0)));
+}
+
+TEST_F(LibBufferHubTest, TestPostWithWrongMetaSize) {
+ struct Metadata {
+ int64_t field1;
+ int64_t field2;
+ };
+ struct OverSizedMetadata {
+ int64_t field1;
+ int64_t field2;
+ int64_t field3;
+ };
+ std::unique_ptr<BufferProducer> p = BufferProducer::Create(
+ kWidth, kHeight, kFormat, kUsage, sizeof(Metadata));
+ ASSERT_TRUE(p.get() != nullptr);
+ std::unique_ptr<BufferConsumer> c =
+ BufferConsumer::Import(p->CreateConsumer());
+ ASSERT_TRUE(c.get() != nullptr);
+
+ // It is illegal to post metadata larger than originally requested during
+ // buffer allocation.
+ OverSizedMetadata evil_meta = {};
+ EXPECT_NE(0, p->Post(LocalHandle(), evil_meta));
+ EXPECT_GE(0, RETRY_EINTR(c->Poll(kPollTimeoutMs)));
+
+ // It is ok to post metadata smaller than originally requested during
+ // buffer allocation.
+ int64_t sequence = 42;
+ EXPECT_EQ(0, p->Post(LocalHandle(), sequence));
+}
+
+TEST_F(LibBufferHubTest, TestAcquireWithWrongMetaSize) {
+ struct Metadata {
+ int64_t field1;
+ int64_t field2;
+ };
+ struct OverSizedMetadata {
+ int64_t field1;
+ int64_t field2;
+ int64_t field3;
+ };
+ std::unique_ptr<BufferProducer> p = BufferProducer::Create(
+ kWidth, kHeight, kFormat, kUsage, sizeof(Metadata));
+ ASSERT_TRUE(p.get() != nullptr);
+ std::unique_ptr<BufferConsumer> c =
+ BufferConsumer::Import(p->CreateConsumer());
+ ASSERT_TRUE(c.get() != nullptr);
+
+ Metadata m = {1, 3};
+ EXPECT_EQ(0, p->Post(LocalHandle(), m));
+
+ LocalHandle fence;
+ int64_t sequence;
+ OverSizedMetadata e;
+
+ // It is illegal to acquire metadata larger than originally requested during
+ // buffer allocation.
+ EXPECT_NE(0, c->Acquire(&fence, &e));
+
+ // It is ok to acquire metadata smaller than originally requested during
+ // buffer allocation.
+ EXPECT_EQ(0, c->Acquire(&fence, &sequence));
+ EXPECT_EQ(m.field1, sequence);
+}
+
+TEST_F(LibBufferHubTest, TestAcquireWithNoMeta) {
+ std::unique_ptr<BufferProducer> p = BufferProducer::Create(
+ kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
+ ASSERT_TRUE(p.get() != nullptr);
+ std::unique_ptr<BufferConsumer> c =
+ BufferConsumer::Import(p->CreateConsumer());
+ ASSERT_TRUE(c.get() != nullptr);
+
+ int64_t sequence = 3;
+ EXPECT_EQ(0, p->Post(LocalHandle(), sequence));
+
+ LocalHandle fence;
+ EXPECT_EQ(0, c->Acquire(&fence));
+}
+
+TEST_F(LibBufferHubTest, TestWithNoMeta) {
+ std::unique_ptr<BufferProducer> p =
+ BufferProducer::Create(kWidth, kHeight, kFormat, kUsage);
+ ASSERT_TRUE(p.get() != nullptr);
+ std::unique_ptr<BufferConsumer> c =
+ BufferConsumer::Import(p->CreateConsumer());
+ ASSERT_TRUE(c.get() != nullptr);
+
+ LocalHandle fence;
+
+ EXPECT_EQ(0, p->Post<void>(LocalHandle()));
+ EXPECT_EQ(0, c->Acquire(&fence));
+}
+
+TEST_F(LibBufferHubTest, TestFailureToPostMetaFromABufferWithoutMeta) {
+ std::unique_ptr<BufferProducer> p =
+ BufferProducer::Create(kWidth, kHeight, kFormat, kUsage);
+ ASSERT_TRUE(p.get() != nullptr);
+ std::unique_ptr<BufferConsumer> c =
+ BufferConsumer::Import(p->CreateConsumer());
+ ASSERT_TRUE(c.get() != nullptr);
+
+ int64_t sequence = 3;
+ EXPECT_NE(0, p->Post(LocalHandle(), sequence));
+}
+
+TEST_F(LibBufferHubTest, TestPersistentBufferPersistence) {
+ auto p = BufferProducer::Create("TestPersistentBuffer", -1, -1, kWidth,
+ kHeight, kFormat, kUsage);
+ ASSERT_NE(nullptr, p);
+
+ // Record the original buffer id for later comparison.
+ const int buffer_id = p->id();
+
+ auto c = BufferConsumer::Import(p->CreateConsumer());
+ ASSERT_NE(nullptr, c);
+
+ EXPECT_EQ(0, p->Post<void>(LocalHandle()));
+
+ // Close the connection to the producer. This should not affect the consumer.
+ p = nullptr;
+
+ LocalHandle fence;
+ EXPECT_EQ(0, c->Acquire(&fence));
+ EXPECT_EQ(0, c->Release(LocalHandle()));
+
+ // Attempt to reconnect to the persistent buffer.
+ p = BufferProducer::Create("TestPersistentBuffer");
+ ASSERT_NE(nullptr, p);
+ EXPECT_EQ(buffer_id, p->id());
+ EXPECT_EQ(0, p->Gain(&fence));
+}
+
+TEST_F(LibBufferHubTest, TestPersistentBufferMismatchParams) {
+ auto p = BufferProducer::Create("TestPersistentBuffer", -1, -1, kWidth,
+ kHeight, kFormat, kUsage);
+ ASSERT_NE(nullptr, p);
+
+ // Close the connection to the producer.
+ p = nullptr;
+
+ // Mismatch the params.
+ p = BufferProducer::Create("TestPersistentBuffer", -1, -1, kWidth * 2,
+ kHeight, kFormat, kUsage);
+ ASSERT_EQ(nullptr, p);
+}
+
+TEST_F(LibBufferHubTest, TestRemovePersistentBuffer) {
+ auto p = BufferProducer::Create("TestPersistentBuffer", -1, -1, kWidth,
+ kHeight, kFormat, kUsage);
+ ASSERT_NE(nullptr, p);
+
+ LocalHandle fence;
+ auto c = BufferConsumer::Import(p->CreateConsumer());
+ ASSERT_NE(nullptr, c);
+ EXPECT_EQ(0, p->Post<void>(LocalHandle()));
+ EXPECT_EQ(0, c->Acquire(&fence));
+ EXPECT_EQ(0, c->Release(LocalHandle()));
+ EXPECT_LT(0, RETRY_EINTR(p->Poll(kPollTimeoutMs)));
+
+ // Test that removing persistence and closing the producer orphans the
+ // consumer.
+ EXPECT_EQ(0, p->Gain(&fence));
+ EXPECT_EQ(0, p->Post<void>(LocalHandle()));
+ EXPECT_EQ(0, p->RemovePersistence());
+ p = nullptr;
+
+ // Orphaned consumer can acquire the posted buffer one more time in
+ // asynchronous manner. But synchronous call will fail.
+ DvrNativeBufferMetadata meta;
+ EXPECT_EQ(0, c->AcquireAsync(&meta, &fence));
+ EXPECT_EQ(-EPIPE, c->Release(LocalHandle()));
+}
+
+namespace {
+
+int PollFd(int fd, int timeout_ms) {
+ pollfd p = {fd, POLLIN, 0};
+ return poll(&p, 1, timeout_ms);
+}
+
+} // namespace
+
+TEST_F(LibBufferHubTest, TestAcquireFence) {
+ std::unique_ptr<BufferProducer> p = BufferProducer::Create(
+ kWidth, kHeight, kFormat, kUsage, /*metadata_size=*/0);
+ ASSERT_TRUE(p.get() != nullptr);
+ std::unique_ptr<BufferConsumer> c =
+ BufferConsumer::Import(p->CreateConsumer());
+ ASSERT_TRUE(c.get() != nullptr);
+
+ DvrNativeBufferMetadata meta;
+ LocalHandle f1(eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK));
+
+ // Post with unsignaled fence.
+ EXPECT_EQ(0, p->PostAsync(&meta, f1));
+
+ // Should acquire a valid fence.
+ LocalHandle f2;
+ EXPECT_LT(0, RETRY_EINTR(c->Poll(kPollTimeoutMs)));
+ EXPECT_EQ(0, c->AcquireAsync(&meta, &f2));
+ EXPECT_TRUE(f2.IsValid());
+ // The original fence and acquired fence should have different fd number.
+ EXPECT_NE(f1.Get(), f2.Get());
+ EXPECT_GE(0, PollFd(f2.Get(), 0));
+
+ // Signal the original fence will trigger the new fence.
+ eventfd_write(f1.Get(), 1);
+ // Now the original FD has been signaled.
+ EXPECT_LT(0, PollFd(f2.Get(), kPollTimeoutMs));
+
+ // Release the consumer with an invalid fence.
+ EXPECT_EQ(0, c->ReleaseAsync(&meta, LocalHandle()));
+
+ // Should gain an invalid fence.
+ LocalHandle f3;
+ EXPECT_LT(0, RETRY_EINTR(p->Poll(kPollTimeoutMs)));
+ EXPECT_EQ(0, p->GainAsync(&meta, &f3));
+ EXPECT_FALSE(f3.IsValid());
+
+ // Post with a signaled fence.
+ EXPECT_EQ(0, p->PostAsync(&meta, f1));
+
+ // Should acquire a valid fence and it's already signalled.
+ LocalHandle f4;
+ EXPECT_LT(0, RETRY_EINTR(c->Poll(kPollTimeoutMs)));
+ EXPECT_EQ(0, c->AcquireAsync(&meta, &f4));
+ EXPECT_TRUE(f4.IsValid());
+ EXPECT_LT(0, PollFd(f4.Get(), kPollTimeoutMs));
+
+ // Release with an unsignalled fence and signal it immediately after release
+ // without producer gainning.
+ LocalHandle f5(eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK));
+ EXPECT_EQ(0, c->ReleaseAsync(&meta, f5));
+ eventfd_write(f5.Get(), 1);
+
+ // Should gain a valid fence, which is already signaled.
+ LocalHandle f6;
+ EXPECT_LT(0, RETRY_EINTR(p->Poll(kPollTimeoutMs)));
+ EXPECT_EQ(0, p->GainAsync(&meta, &f6));
+ EXPECT_TRUE(f6.IsValid());
+ EXPECT_LT(0, PollFd(f6.Get(), kPollTimeoutMs));
+}
+
+TEST_F(LibBufferHubTest, TestOrphanedAcquire) {
+ std::unique_ptr<BufferProducer> p = BufferProducer::Create(
+ kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
+ ASSERT_TRUE(p.get() != nullptr);
+ std::unique_ptr<BufferConsumer> c1 =
+ BufferConsumer::Import(p->CreateConsumer());
+ ASSERT_TRUE(c1.get() != nullptr);
+ const uint64_t consumer_state_bit1 = c1->buffer_state_bit();
+
+ DvrNativeBufferMetadata meta;
+ EXPECT_EQ(0, p->PostAsync(&meta, LocalHandle()));
+
+ LocalHandle fence;
+ EXPECT_LT(0, RETRY_EINTR(c1->Poll(kPollTimeoutMs)));
+ EXPECT_LE(0, c1->AcquireAsync(&meta, &fence));
+ // Destroy the consumer now will make it orphaned and the buffer is still
+ // acquired.
+ c1 = nullptr;
+ EXPECT_GE(0, RETRY_EINTR(p->Poll(kPollTimeoutMs)));
+
+ std::unique_ptr<BufferConsumer> c2 =
+ BufferConsumer::Import(p->CreateConsumer());
+ ASSERT_TRUE(c2.get() != nullptr);
+ const uint64_t consumer_state_bit2 = c2->buffer_state_bit();
+ EXPECT_NE(consumer_state_bit1, consumer_state_bit2);
+
+ // The new consumer is available for acquire.
+ EXPECT_LT(0, RETRY_EINTR(c2->Poll(kPollTimeoutMs)));
+ EXPECT_LE(0, c2->AcquireAsync(&meta, &fence));
+ // Releasing the consumer makes the buffer gainable.
+ EXPECT_EQ(0, c2->ReleaseAsync(&meta, LocalHandle()));
+
+ // The buffer is now available for the producer to gain.
+ EXPECT_LT(0, RETRY_EINTR(p->Poll(kPollTimeoutMs)));
+
+ // But if another consumer is created in released state.
+ std::unique_ptr<BufferConsumer> c3 =
+ BufferConsumer::Import(p->CreateConsumer());
+ ASSERT_TRUE(c3.get() != nullptr);
+ const uint64_t consumer_state_bit3 = c3->buffer_state_bit();
+ EXPECT_NE(consumer_state_bit2, consumer_state_bit3);
+ // The consumer buffer is not acquirable.
+ EXPECT_GE(0, RETRY_EINTR(c3->Poll(kPollTimeoutMs)));
+ EXPECT_EQ(-EBUSY, c3->AcquireAsync(&meta, &fence));
+
+ // Producer should be able to gain no matter what.
+ EXPECT_EQ(0, p->GainAsync(&meta, &fence));
+}
diff --git a/libs/vr/libbufferhub/buffer_hub_client.cpp b/libs/vr/libbufferhub/buffer_hub_client.cpp
index b9a53b0..97341b1 100644
--- a/libs/vr/libbufferhub/buffer_hub_client.cpp
+++ b/libs/vr/libbufferhub/buffer_hub_client.cpp
@@ -2,7 +2,7 @@
#include <log/log.h>
#include <poll.h>
-#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+#include <sys/epoll.h>
#include <utils/Trace.h>
#include <mutex>
@@ -12,9 +12,8 @@
#include "include/private/dvr/bufferhub_rpc.h"
-using android::pdx::LocalHandle;
using android::pdx::LocalChannelHandle;
-using android::pdx::rpc::WrapBuffer;
+using android::pdx::LocalHandle;
using android::pdx::Status;
namespace android {
@@ -29,7 +28,11 @@
endpoint_path)},
id_(-1) {}
-BufferHubBuffer::~BufferHubBuffer() {}
+BufferHubBuffer::~BufferHubBuffer() {
+ if (metadata_header_ != nullptr) {
+ metadata_buffer_.Unlock();
+ }
+}
Status<LocalChannelHandle> BufferHubBuffer::CreateConsumer() {
Status<LocalChannelHandle> status =
@@ -43,7 +46,7 @@
int BufferHubBuffer::ImportBuffer() {
ATRACE_NAME("BufferHubBuffer::ImportBuffer");
- Status<NativeBufferHandle<LocalHandle>> status =
+ Status<BufferDescription<LocalHandle>> status =
InvokeRemoteMethod<BufferHubRPC::GetBuffer>();
if (!status) {
ALOGE("BufferHubBuffer::ImportBuffer: Failed to get buffer: %s",
@@ -54,24 +57,135 @@
return -EIO;
}
- auto buffer_handle = status.take();
+ auto buffer_desc = status.take();
// Stash the buffer id to replace the value in id_.
- const int new_id = buffer_handle.id();
+ const int new_id = buffer_desc.id();
// Import the buffer.
IonBuffer ion_buffer;
- ALOGD_IF(
- TRACE, "BufferHubBuffer::ImportBuffer: id=%d FdCount=%zu IntCount=%zu",
- buffer_handle.id(), buffer_handle.FdCount(), buffer_handle.IntCount());
+ ALOGD_IF(TRACE, "BufferHubBuffer::ImportBuffer: id=%d.", buffer_desc.id());
- const int ret = buffer_handle.Import(&ion_buffer);
- if (ret < 0)
+ if (const int ret = buffer_desc.ImportBuffer(&ion_buffer))
return ret;
- // If the import succeeds, replace the previous buffer and id.
+ // Import the metadata.
+ IonBuffer metadata_buffer;
+ if (const int ret = buffer_desc.ImportMetadata(&metadata_buffer)) {
+ ALOGE("Failed to import metadata buffer, error=%d", ret);
+ return ret;
+ }
+ size_t metadata_buf_size = metadata_buffer.width();
+ if (metadata_buf_size < BufferHubDefs::kMetadataHeaderSize) {
+ ALOGE("BufferHubBuffer::ImportBuffer: metadata buffer too small: %zu",
+ metadata_buf_size);
+ return -ENOMEM;
+ }
+
+ // If all imports succee, replace the previous buffer and id.
buffer_ = std::move(ion_buffer);
+ metadata_buffer_ = std::move(metadata_buffer);
+ metadata_buf_size_ = metadata_buf_size;
+ user_metadata_size_ = metadata_buf_size_ - BufferHubDefs::kMetadataHeaderSize;
+
+ void* metadata_ptr = nullptr;
+ if (const int ret =
+ metadata_buffer_.Lock(BufferHubDefs::kMetadataUsage, /*x=*/0,
+ /*y=*/0, metadata_buf_size_,
+ /*height=*/1, &metadata_ptr)) {
+ ALOGE("BufferHubBuffer::ImportBuffer: Failed to lock metadata.");
+ return ret;
+ }
+
+ // Set up shared fences.
+ shared_acquire_fence_ = buffer_desc.take_acquire_fence();
+ shared_release_fence_ = buffer_desc.take_release_fence();
+ if (!shared_acquire_fence_ || !shared_release_fence_) {
+ ALOGE("BufferHubBuffer::ImportBuffer: Failed to import shared fences.");
+ return -EIO;
+ }
+
+ metadata_header_ =
+ reinterpret_cast<BufferHubDefs::MetadataHeader*>(metadata_ptr);
+ if (user_metadata_size_) {
+ user_metadata_ptr_ =
+ reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(metadata_ptr) +
+ BufferHubDefs::kMetadataHeaderSize);
+ } else {
+ user_metadata_ptr_ = nullptr;
+ }
+
id_ = new_id;
+ buffer_state_bit_ = buffer_desc.buffer_state_bit();
+
+ // Note that here the buffer state is mapped from shared memory as an atomic
+ // object. The std::atomic's constructor will not be called so that the
+ // original value stored in the memory region will be preserved.
+ buffer_state_ = &metadata_header_->buffer_state;
+ ALOGD_IF(TRACE,
+ "BufferHubBuffer::ImportBuffer: id=%d, buffer_state=%" PRIx64 ".",
+ id(), buffer_state_->load());
+ fence_state_ = &metadata_header_->fence_state;
+ ALOGD_IF(TRACE,
+ "BufferHubBuffer::ImportBuffer: id=%d, fence_state=%" PRIx64 ".",
+ id(), fence_state_->load());
+
+ return 0;
+}
+
+inline int BufferHubBuffer::CheckMetadata(size_t user_metadata_size) const {
+ if (user_metadata_size && !user_metadata_ptr_) {
+ ALOGE("BufferHubBuffer::CheckMetadata: doesn't support custom metadata.");
+ return -EINVAL;
+ }
+ if (user_metadata_size > user_metadata_size_) {
+ ALOGE("BufferHubBuffer::CheckMetadata: too big: %zu, maximum: %zu.",
+ user_metadata_size, user_metadata_size_);
+ return -E2BIG;
+ }
+ return 0;
+}
+
+int BufferHubBuffer::UpdateSharedFence(const LocalHandle& new_fence,
+ const LocalHandle& shared_fence) {
+ if (pending_fence_fd_.Get() != new_fence.Get()) {
+ // First, replace the old fd if there was already one. Skipping if the new
+ // one is the same as the old.
+ if (pending_fence_fd_.IsValid()) {
+ const int ret = epoll_ctl(shared_fence.Get(), EPOLL_CTL_DEL,
+ pending_fence_fd_.Get(), nullptr);
+ ALOGW_IF(ret,
+ "BufferHubBuffer::UpdateSharedFence: failed to remove old fence "
+ "fd from epoll set, error: %s.",
+ strerror(errno));
+ }
+
+ if (new_fence.IsValid()) {
+ // If ready fence is valid, we put that into the epoll set.
+ epoll_event event;
+ event.events = EPOLLIN;
+ event.data.u64 = buffer_state_bit();
+ pending_fence_fd_ = new_fence.Duplicate();
+ if (epoll_ctl(shared_fence.Get(), EPOLL_CTL_ADD, pending_fence_fd_.Get(),
+ &event) < 0) {
+ const int error = errno;
+ ALOGE(
+ "BufferHubBuffer::UpdateSharedFence: failed to add new fence fd "
+ "into epoll set, error: %s.",
+ strerror(error));
+ return -error;
+ }
+ // Set bit in fence state to indicate that there is a fence from this
+ // producer or consumer.
+ fence_state_->fetch_or(buffer_state_bit());
+ } else {
+ // Unset bit in fence state to indicate that there is no fence, so that
+ // when consumer to acquire or producer to acquire, it knows no need to
+ // check fence for this buffer.
+ fence_state_->fetch_and(~buffer_state_bit());
+ }
+ }
+
return 0;
}
@@ -131,31 +245,144 @@
: LocalChannelHandle{nullptr, -status.error()});
}
+int BufferConsumer::LocalAcquire(DvrNativeBufferMetadata* out_meta,
+ LocalHandle* out_fence) {
+ if (!out_meta)
+ return -EINVAL;
+
+ // Only check producer bit and this consumer buffer's particular consumer bit.
+ // The buffer is can be acquired iff: 1) producer bit is set; 2) consumer bit
+ // is not set.
+ uint64_t buffer_state = buffer_state_->load();
+ if (!BufferHubDefs::IsBufferPosted(buffer_state, buffer_state_bit())) {
+ ALOGE("BufferConsumer::LocalAcquire: not posted, id=%d state=%" PRIx64
+ " buffer_state_bit=%" PRIx64 ".",
+ id(), buffer_state, buffer_state_bit());
+ return -EBUSY;
+ }
+
+ // Copy the canonical metadata.
+ void* metadata_ptr = reinterpret_cast<void*>(&metadata_header_->metadata);
+ memcpy(out_meta, metadata_ptr, sizeof(DvrNativeBufferMetadata));
+ // Fill in the user_metadata_ptr in address space of the local process.
+ if (out_meta->user_metadata_size) {
+ out_meta->user_metadata_ptr =
+ reinterpret_cast<uint64_t>(user_metadata_ptr_);
+ } else {
+ out_meta->user_metadata_ptr = 0;
+ }
+
+ uint64_t fence_state = fence_state_->load();
+ // If there is an acquire fence from producer, we need to return it.
+ if (fence_state & BufferHubDefs::kProducerStateBit) {
+ *out_fence = shared_acquire_fence_.Duplicate();
+ }
+
+ // Set the consumer bit unique to this consumer.
+ BufferHubDefs::ModifyBufferState(buffer_state_, 0ULL, buffer_state_bit());
+ return 0;
+}
+
int BufferConsumer::Acquire(LocalHandle* ready_fence) {
return Acquire(ready_fence, nullptr, 0);
}
int BufferConsumer::Acquire(LocalHandle* ready_fence, void* meta,
- size_t meta_size_bytes) {
+ size_t user_metadata_size) {
ATRACE_NAME("BufferConsumer::Acquire");
- LocalFence fence;
- auto return_value =
- std::make_pair(std::ref(fence), WrapBuffer(meta, meta_size_bytes));
- auto status = InvokeRemoteMethodInPlace<BufferHubRPC::ConsumerAcquire>(
- &return_value, meta_size_bytes);
- if (status && ready_fence)
- *ready_fence = fence.take();
- return status ? 0 : -status.error();
+
+ if (const int error = CheckMetadata(user_metadata_size))
+ return error;
+
+ DvrNativeBufferMetadata canonical_meta;
+ if (const int error = LocalAcquire(&canonical_meta, ready_fence))
+ return error;
+
+ if (meta && user_metadata_size) {
+ void* metadata_src =
+ reinterpret_cast<void*>(canonical_meta.user_metadata_ptr);
+ if (metadata_src) {
+ memcpy(meta, metadata_src, user_metadata_size);
+ } else {
+ ALOGW("BufferConsumer::Acquire: no user-defined metadata.");
+ }
+ }
+
+ auto status = InvokeRemoteMethod<BufferHubRPC::ConsumerAcquire>();
+ if (!status)
+ return -status.error();
+ return 0;
+}
+
+int BufferConsumer::AcquireAsync(DvrNativeBufferMetadata* out_meta,
+ LocalHandle* out_fence) {
+ ATRACE_NAME("BufferConsumer::AcquireAsync");
+
+ if (const int error = LocalAcquire(out_meta, out_fence))
+ return error;
+
+ auto status = SendImpulse(BufferHubRPC::ConsumerAcquire::Opcode);
+ if (!status)
+ return -status.error();
+ return 0;
+}
+
+int BufferConsumer::LocalRelease(const DvrNativeBufferMetadata* meta,
+ const LocalHandle& release_fence) {
+ if (const int error = CheckMetadata(meta->user_metadata_size))
+ return error;
+
+ // Check invalid state transition.
+ uint64_t buffer_state = buffer_state_->load();
+ if (!BufferHubDefs::IsBufferAcquired(buffer_state)) {
+ ALOGE("BufferConsumer::LocalRelease: not acquired id=%d state=%" PRIx64 ".",
+ id(), buffer_state);
+ return -EBUSY;
+ }
+
+ // On release, only the user requested metadata is copied back into the shared
+ // memory for metadata. Since there are multiple consumers, it doesn't make
+ // sense to send the canonical metadata back to the producer. However, one of
+ // the consumer can still choose to write up to user_metadata_size bytes of
+ // data into user_metadata_ptr.
+ if (meta->user_metadata_ptr && meta->user_metadata_size) {
+ void* metadata_src = reinterpret_cast<void*>(meta->user_metadata_ptr);
+ memcpy(user_metadata_ptr_, metadata_src, meta->user_metadata_size);
+ }
+
+ // Send out the release fence through the shared epoll fd. Note that during
+ // releasing the producer is not expected to be polling on the fence.
+ if (const int error = UpdateSharedFence(release_fence, shared_release_fence_))
+ return error;
+
+ // For release operation, the client don't need to change the state as it's
+ // bufferhubd's job to flip the produer bit once all consumers are released.
+ return 0;
}
int BufferConsumer::Release(const LocalHandle& release_fence) {
ATRACE_NAME("BufferConsumer::Release");
+
+ DvrNativeBufferMetadata meta;
+ if (const int error = LocalRelease(&meta, release_fence))
+ return error;
+
return ReturnStatusOrError(InvokeRemoteMethod<BufferHubRPC::ConsumerRelease>(
BorrowedFence(release_fence.Borrow())));
}
int BufferConsumer::ReleaseAsync() {
+ DvrNativeBufferMetadata meta;
+ return ReleaseAsync(&meta, LocalHandle());
+}
+
+int BufferConsumer::ReleaseAsync(const DvrNativeBufferMetadata* meta,
+ const LocalHandle& release_fence) {
ATRACE_NAME("BufferConsumer::ReleaseAsync");
+
+ if (const int error = LocalRelease(meta, release_fence))
+ return error;
+
return ReturnStatusOrError(
SendImpulse(BufferHubRPC::ConsumerRelease::Opcode));
}
@@ -168,24 +395,25 @@
}
BufferProducer::BufferProducer(uint32_t width, uint32_t height, uint32_t format,
- uint32_t usage, size_t metadata_size)
- : BufferProducer(width, height, format, usage, usage, metadata_size) {}
+ uint32_t usage, size_t user_metadata_size)
+ : BufferProducer(width, height, format, usage, usage, user_metadata_size) {}
BufferProducer::BufferProducer(uint32_t width, uint32_t height, uint32_t format,
uint64_t producer_usage, uint64_t consumer_usage,
- size_t metadata_size)
+ size_t user_metadata_size)
: BASE(BufferHubRPC::kClientPath) {
ATRACE_NAME("BufferProducer::BufferProducer");
ALOGD_IF(TRACE,
"BufferProducer::BufferProducer: fd=%d width=%u height=%u format=%u "
"producer_usage=%" PRIx64 " consumer_usage=%" PRIx64
- " metadata_size=%zu",
+ " user_metadata_size=%zu",
event_fd(), width, height, format, producer_usage, consumer_usage,
- metadata_size);
+ user_metadata_size);
// (b/37881101) Deprecate producer/consumer usage
auto status = InvokeRemoteMethod<BufferHubRPC::CreateBuffer>(
- width, height, format, (producer_usage | consumer_usage), metadata_size);
+ width, height, format, (producer_usage | consumer_usage),
+ user_metadata_size);
if (!status) {
ALOGE(
"BufferProducer::BufferProducer: Failed to create producer buffer: %s",
@@ -206,27 +434,28 @@
BufferProducer::BufferProducer(const std::string& name, int user_id,
int group_id, uint32_t width, uint32_t height,
uint32_t format, uint32_t usage,
- size_t meta_size_bytes)
+ size_t user_metadata_size)
: BufferProducer(name, user_id, group_id, width, height, format, usage,
- usage, meta_size_bytes) {}
+ usage, user_metadata_size) {}
BufferProducer::BufferProducer(const std::string& name, int user_id,
int group_id, uint32_t width, uint32_t height,
uint32_t format, uint64_t producer_usage,
- uint64_t consumer_usage, size_t meta_size_bytes)
+ uint64_t consumer_usage,
+ size_t user_metadata_size)
: BASE(BufferHubRPC::kClientPath) {
ATRACE_NAME("BufferProducer::BufferProducer");
ALOGD_IF(TRACE,
"BufferProducer::BufferProducer: fd=%d name=%s user_id=%d "
"group_id=%d width=%u height=%u format=%u producer_usage=%" PRIx64
- " consumer_usage=%" PRIx64 " meta_size_bytes=%zu",
+ " consumer_usage=%" PRIx64 " user_metadata_size=%zu",
event_fd(), name.c_str(), user_id, group_id, width, height, format,
- producer_usage, consumer_usage, meta_size_bytes);
+ producer_usage, consumer_usage, user_metadata_size);
// (b/37881101) Deprecate producer/consumer usage
auto status = InvokeRemoteMethod<BufferHubRPC::CreatePersistentBuffer>(
name, user_id, group_id, width, height, format,
- (producer_usage | consumer_usage), meta_size_bytes);
+ (producer_usage | consumer_usage), user_metadata_size);
if (!status) {
ALOGE(
"BufferProducer::BufferProducer: Failed to create/get persistent "
@@ -260,12 +489,12 @@
const int width = static_cast<int>(size);
const int height = 1;
const int format = HAL_PIXEL_FORMAT_BLOB;
- const size_t meta_size_bytes = 0;
+ const size_t user_metadata_size = 0;
// (b/37881101) Deprecate producer/consumer usage
auto status = InvokeRemoteMethod<BufferHubRPC::CreateBuffer>(
width, height, format, (producer_usage | consumer_usage),
- meta_size_bytes);
+ user_metadata_size);
if (!status) {
ALOGE("BufferProducer::BufferProducer: Failed to create blob: %s",
status.GetErrorMessage().c_str());
@@ -299,12 +528,12 @@
const int width = static_cast<int>(size);
const int height = 1;
const int format = HAL_PIXEL_FORMAT_BLOB;
- const size_t meta_size_bytes = 0;
+ const size_t user_metadata_size = 0;
// (b/37881101) Deprecate producer/consumer usage
auto status = InvokeRemoteMethod<BufferHubRPC::CreatePersistentBuffer>(
name, user_id, group_id, width, height, format,
- (producer_usage | consumer_usage), meta_size_bytes);
+ (producer_usage | consumer_usage), user_metadata_size);
if (!status) {
ALOGE(
"BufferProducer::BufferProducer: Failed to create persistent "
@@ -360,28 +589,141 @@
}
}
+int BufferProducer::LocalPost(const DvrNativeBufferMetadata* meta,
+ const LocalHandle& ready_fence) {
+ if (const int error = CheckMetadata(meta->user_metadata_size))
+ return error;
+
+ // Check invalid state transition.
+ uint64_t buffer_state = buffer_state_->load();
+ if (!BufferHubDefs::IsBufferGained(buffer_state)) {
+ ALOGE("BufferProducer::LocalPost: not gained, id=%d state=%" PRIx64 ".",
+ id(), buffer_state);
+ return -EBUSY;
+ }
+
+ // Copy the canonical metadata.
+ void* metadata_ptr = reinterpret_cast<void*>(&metadata_header_->metadata);
+ memcpy(metadata_ptr, meta, sizeof(DvrNativeBufferMetadata));
+ // Copy extra user requested metadata.
+ if (meta->user_metadata_ptr && meta->user_metadata_size) {
+ void* metadata_src = reinterpret_cast<void*>(meta->user_metadata_ptr);
+ memcpy(user_metadata_ptr_, metadata_src, meta->user_metadata_size);
+ }
+
+ // Send out the acquire fence through the shared epoll fd. Note that during
+ // posting no consumer is not expected to be polling on the fence.
+ if (const int error = UpdateSharedFence(ready_fence, shared_acquire_fence_))
+ return error;
+
+ // Set the producer bit atomically to transit into posted state.
+ BufferHubDefs::ModifyBufferState(buffer_state_, 0ULL,
+ BufferHubDefs::kProducerStateBit);
+ return 0;
+}
+
int BufferProducer::Post(const LocalHandle& ready_fence, const void* meta,
- size_t meta_size_bytes) {
+ size_t user_metadata_size) {
ATRACE_NAME("BufferProducer::Post");
+
+ // Populate cononical metadata for posting.
+ DvrNativeBufferMetadata canonical_meta;
+ canonical_meta.user_metadata_ptr = reinterpret_cast<uint64_t>(meta);
+ canonical_meta.user_metadata_size = user_metadata_size;
+
+ if (const int error = LocalPost(&canonical_meta, ready_fence))
+ return error;
+
return ReturnStatusOrError(InvokeRemoteMethod<BufferHubRPC::ProducerPost>(
- BorrowedFence(ready_fence.Borrow()), WrapBuffer(meta, meta_size_bytes)));
+ BorrowedFence(ready_fence.Borrow())));
+}
+
+int BufferProducer::PostAsync(const DvrNativeBufferMetadata* meta,
+ const LocalHandle& ready_fence) {
+ ATRACE_NAME("BufferProducer::PostAsync");
+
+ if (const int error = LocalPost(meta, ready_fence))
+ return error;
+
+ return ReturnStatusOrError(SendImpulse(BufferHubRPC::ProducerPost::Opcode));
+}
+
+int BufferProducer::LocalGain(DvrNativeBufferMetadata* out_meta,
+ LocalHandle* out_fence) {
+ uint64_t buffer_state = buffer_state_->load();
+ ALOGD_IF(TRACE, "BufferProducer::LocalGain: buffer=%d, state=%" PRIx64 ".",
+ id(), buffer_state);
+
+ if (!out_meta)
+ return -EINVAL;
+
+ if (!BufferHubDefs::IsBufferReleased(buffer_state)) {
+ if (BufferHubDefs::IsBufferGained(buffer_state)) {
+ // We don't want to log error when gaining a newly allocated
+ // buffer.
+ ALOGI("BufferProducer::LocalGain: already gained id=%d.", id());
+ return -EALREADY;
+ }
+ ALOGE("BufferProducer::LocalGain: not released id=%d state=%" PRIx64 ".",
+ id(), buffer_state);
+ return -EBUSY;
+ }
+
+ // Canonical metadata is undefined on Gain. Except for user_metadata and
+ // release_fence_mask. Fill in the user_metadata_ptr in address space of the
+ // local process.
+ if (metadata_header_->metadata.user_metadata_size && user_metadata_ptr_) {
+ out_meta->user_metadata_size =
+ metadata_header_->metadata.user_metadata_size;
+ out_meta->user_metadata_ptr =
+ reinterpret_cast<uint64_t>(user_metadata_ptr_);
+ } else {
+ out_meta->user_metadata_size = 0;
+ out_meta->user_metadata_ptr = 0;
+ }
+
+ uint64_t fence_state = fence_state_->load();
+ // If there is an release fence from consumer, we need to return it.
+ if (fence_state & BufferHubDefs::kConsumerStateMask) {
+ *out_fence = shared_release_fence_.Duplicate();
+ out_meta->release_fence_mask =
+ fence_state & BufferHubDefs::kConsumerStateMask;
+ }
+
+ // Clear out all bits and the buffer is now back to gained state.
+ buffer_state_->store(0ULL);
+ return 0;
}
int BufferProducer::Gain(LocalHandle* release_fence) {
ATRACE_NAME("BufferProducer::Gain");
+
+ DvrNativeBufferMetadata meta;
+ if (const int error = LocalGain(&meta, release_fence))
+ return error;
+
auto status = InvokeRemoteMethod<BufferHubRPC::ProducerGain>();
if (!status)
return -status.error();
- if (release_fence)
- *release_fence = status.take().take();
return 0;
}
-int BufferProducer::GainAsync() {
+int BufferProducer::GainAsync(DvrNativeBufferMetadata* out_meta,
+ LocalHandle* release_fence) {
ATRACE_NAME("BufferProducer::GainAsync");
+
+ if (const int error = LocalGain(out_meta, release_fence))
+ return error;
+
return ReturnStatusOrError(SendImpulse(BufferHubRPC::ProducerGain::Opcode));
}
+int BufferProducer::GainAsync() {
+ DvrNativeBufferMetadata meta;
+ LocalHandle fence;
+ return GainAsync(&meta, &fence);
+}
+
std::unique_ptr<BufferProducer> BufferProducer::Import(
LocalChannelHandle channel) {
ALOGD_IF(TRACE, "BufferProducer::Import: channel=%d", channel.value());
diff --git a/libs/vr/libbufferhub/bufferhub_tests.cpp b/libs/vr/libbufferhub/bufferhub_tests.cpp
deleted file mode 100644
index fa61c4a..0000000
--- a/libs/vr/libbufferhub/bufferhub_tests.cpp
+++ /dev/null
@@ -1,226 +0,0 @@
-#include <gtest/gtest.h>
-#include <private/dvr/buffer_hub_client.h>
-
-#include <mutex>
-#include <thread>
-
-#define RETRY_EINTR(fnc_call) \
- ([&]() -> decltype(fnc_call) { \
- decltype(fnc_call) result; \
- do { \
- result = (fnc_call); \
- } while (result == -1 && errno == EINTR); \
- return result; \
- })()
-
-using android::dvr::BufferProducer;
-using android::dvr::BufferConsumer;
-using android::pdx::LocalHandle;
-
-const int kWidth = 640;
-const int kHeight = 480;
-const int kFormat = HAL_PIXEL_FORMAT_RGBA_8888;
-const int kUsage = 0;
-const uint64_t kContext = 42;
-
-using LibBufferHubTest = ::testing::Test;
-
-TEST_F(LibBufferHubTest, TestBasicUsage) {
- std::unique_ptr<BufferProducer> p = BufferProducer::Create(
- kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
- ASSERT_TRUE(p.get() != nullptr);
- std::unique_ptr<BufferConsumer> c =
- BufferConsumer::Import(p->CreateConsumer());
- ASSERT_TRUE(c.get() != nullptr);
- // Check that consumers can spawn other consumers.
- std::unique_ptr<BufferConsumer> c2 =
- BufferConsumer::Import(c->CreateConsumer());
- ASSERT_TRUE(c2.get() != nullptr);
-
- EXPECT_EQ(0, p->Post(LocalHandle(), kContext));
- // Both consumers should be triggered.
- EXPECT_GE(0, RETRY_EINTR(p->Poll(0)));
- EXPECT_LT(0, RETRY_EINTR(c->Poll(10)));
- EXPECT_LT(0, RETRY_EINTR(c2->Poll(10)));
-
- uint64_t context;
- LocalHandle fence;
- EXPECT_LE(0, c->Acquire(&fence, &context));
- EXPECT_EQ(kContext, context);
- EXPECT_GE(0, RETRY_EINTR(c->Poll(0)));
-
- EXPECT_LE(0, c2->Acquire(&fence, &context));
- EXPECT_EQ(kContext, context);
- EXPECT_GE(0, RETRY_EINTR(c2->Poll(0)));
-
- EXPECT_EQ(0, c->Release(LocalHandle()));
- EXPECT_GE(0, RETRY_EINTR(p->Poll(0)));
- EXPECT_EQ(0, c2->Discard());
-
- EXPECT_LE(0, RETRY_EINTR(p->Poll(0)));
- EXPECT_EQ(0, p->Gain(&fence));
- EXPECT_GE(0, RETRY_EINTR(p->Poll(0)));
-}
-
-TEST_F(LibBufferHubTest, TestWithCustomMetadata) {
- struct Metadata {
- int64_t field1;
- int64_t field2;
- };
- std::unique_ptr<BufferProducer> p = BufferProducer::Create(
- kWidth, kHeight, kFormat, kUsage, sizeof(Metadata));
- ASSERT_TRUE(p.get() != nullptr);
- std::unique_ptr<BufferConsumer> c =
- BufferConsumer::Import(p->CreateConsumer());
- ASSERT_TRUE(c.get() != nullptr);
-
- Metadata m = {1, 3};
- EXPECT_EQ(0, p->Post(LocalHandle(), m));
- EXPECT_LE(0, RETRY_EINTR(c->Poll(10)));
-
- LocalHandle fence;
- Metadata m2 = {};
- EXPECT_EQ(0, c->Acquire(&fence, &m2));
- EXPECT_EQ(m.field1, m2.field1);
- EXPECT_EQ(m.field2, m2.field2);
-
- EXPECT_EQ(0, c->Release(LocalHandle()));
- EXPECT_LT(0, RETRY_EINTR(p->Poll(0)));
-}
-
-TEST_F(LibBufferHubTest, TestPostWithWrongMetaSize) {
- struct Metadata {
- int64_t field1;
- int64_t field2;
- };
- std::unique_ptr<BufferProducer> p = BufferProducer::Create(
- kWidth, kHeight, kFormat, kUsage, sizeof(Metadata));
- ASSERT_TRUE(p.get() != nullptr);
- std::unique_ptr<BufferConsumer> c =
- BufferConsumer::Import(p->CreateConsumer());
- ASSERT_TRUE(c.get() != nullptr);
-
- int64_t sequence = 3;
- EXPECT_NE(0, p->Post(LocalHandle(), sequence));
- EXPECT_GE(0, RETRY_EINTR(c->Poll(10)));
-}
-
-TEST_F(LibBufferHubTest, TestAcquireWithWrongMetaSize) {
- struct Metadata {
- int64_t field1;
- int64_t field2;
- };
- std::unique_ptr<BufferProducer> p = BufferProducer::Create(
- kWidth, kHeight, kFormat, kUsage, sizeof(Metadata));
- ASSERT_TRUE(p.get() != nullptr);
- std::unique_ptr<BufferConsumer> c =
- BufferConsumer::Import(p->CreateConsumer());
- ASSERT_TRUE(c.get() != nullptr);
-
- Metadata m = {1, 3};
- EXPECT_EQ(0, p->Post(LocalHandle(), m));
-
- LocalHandle fence;
- int64_t sequence;
- EXPECT_NE(0, c->Acquire(&fence, &sequence));
-}
-
-TEST_F(LibBufferHubTest, TestAcquireWithNoMeta) {
- std::unique_ptr<BufferProducer> p = BufferProducer::Create(
- kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
- ASSERT_TRUE(p.get() != nullptr);
- std::unique_ptr<BufferConsumer> c =
- BufferConsumer::Import(p->CreateConsumer());
- ASSERT_TRUE(c.get() != nullptr);
-
- int64_t sequence = 3;
- EXPECT_EQ(0, p->Post(LocalHandle(), sequence));
-
- LocalHandle fence;
- EXPECT_EQ(0, c->Acquire(&fence));
-}
-
-TEST_F(LibBufferHubTest, TestWithNoMeta) {
- std::unique_ptr<BufferProducer> p =
- BufferProducer::Create(kWidth, kHeight, kFormat, kUsage);
- ASSERT_TRUE(p.get() != nullptr);
- std::unique_ptr<BufferConsumer> c =
- BufferConsumer::Import(p->CreateConsumer());
- ASSERT_TRUE(c.get() != nullptr);
-
- LocalHandle fence;
-
- EXPECT_EQ(0, p->Post<void>(LocalHandle()));
- EXPECT_EQ(0, c->Acquire(&fence));
-}
-
-TEST_F(LibBufferHubTest, TestFailureToPostMetaFromABufferWithoutMeta) {
- std::unique_ptr<BufferProducer> p =
- BufferProducer::Create(kWidth, kHeight, kFormat, kUsage);
- ASSERT_TRUE(p.get() != nullptr);
- std::unique_ptr<BufferConsumer> c =
- BufferConsumer::Import(p->CreateConsumer());
- ASSERT_TRUE(c.get() != nullptr);
-
- int64_t sequence = 3;
- EXPECT_NE(0, p->Post(LocalHandle(), sequence));
-}
-
-TEST_F(LibBufferHubTest, TestPersistentBufferPersistence) {
- auto p = BufferProducer::Create("TestPersistentBuffer", -1, -1, kWidth,
- kHeight, kFormat, kUsage);
- ASSERT_NE(nullptr, p);
-
- // Record the original buffer id for later comparison.
- const int buffer_id = p->id();
-
- auto c = BufferConsumer::Import(p->CreateConsumer());
- ASSERT_NE(nullptr, c);
-
- EXPECT_EQ(0, p->Post<void>(LocalHandle()));
-
- // Close the connection to the producer. This should not affect the consumer.
- p = nullptr;
-
- LocalHandle fence;
- EXPECT_EQ(0, c->Acquire(&fence));
- EXPECT_EQ(0, c->Release(LocalHandle()));
-
- // Attempt to reconnect to the persistent buffer.
- p = BufferProducer::Create("TestPersistentBuffer");
- ASSERT_NE(nullptr, p);
- EXPECT_EQ(buffer_id, p->id());
- EXPECT_EQ(0, p->Gain(&fence));
-}
-
-TEST_F(LibBufferHubTest, TestPersistentBufferMismatchParams) {
- auto p = BufferProducer::Create("TestPersistentBuffer", -1, -1, kWidth,
- kHeight, kFormat, kUsage);
- ASSERT_NE(nullptr, p);
-
- // Close the connection to the producer.
- p = nullptr;
-
- // Mismatch the params.
- p = BufferProducer::Create("TestPersistentBuffer", -1, -1, kWidth * 2,
- kHeight, kFormat, kUsage);
- ASSERT_EQ(nullptr, p);
-}
-
-TEST_F(LibBufferHubTest, TestRemovePersistentBuffer) {
- auto p = BufferProducer::Create("TestPersistentBuffer", -1, -1, kWidth,
- kHeight, kFormat, kUsage);
- ASSERT_NE(nullptr, p);
-
- LocalHandle fence;
- auto c = BufferConsumer::Import(p->CreateConsumer());
- ASSERT_NE(nullptr, c);
- EXPECT_NE(-EPIPE, c->Acquire(&fence));
-
- // Test that removing persistence and closing the producer orphans the
- // consumer.
- EXPECT_EQ(0, p->RemovePersistence());
- p = nullptr;
-
- EXPECT_EQ(-EPIPE, c->Release(LocalHandle()));
-}
diff --git a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_client.h b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_client.h
index be20e72..a356959 100644
--- a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_client.h
+++ b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_client.h
@@ -11,6 +11,8 @@
#include <private/dvr/ion_buffer.h>
+#include "bufferhub_rpc.h"
+
namespace android {
namespace dvr {
@@ -75,6 +77,14 @@
}
}
+ std::vector<pdx::ClientChannel::EventSource> GetEventSources() const {
+ if (auto* client_channel = GetChannel()) {
+ return client_channel->GetEventSources();
+ } else {
+ return {};
+ }
+ }
+
native_handle_t* native_handle() const {
return const_cast<native_handle_t*>(buffer_.handle());
}
@@ -84,6 +94,13 @@
int id() const { return id_; }
+ // Returns the buffer buffer state.
+ uint64_t buffer_state() { return buffer_state_->load(); };
+
+ // A state mask which is unique to a buffer hub client among all its siblings
+ // sharing the same concrete graphic buffer.
+ uint64_t buffer_state_bit() const { return buffer_state_bit_; }
+
// The following methods return settings of the first buffer. Currently,
// it is only possible to create multi-buffer BufferHubBuffers with the same
// settings.
@@ -98,6 +115,9 @@
uint64_t producer_usage() const { return buffer_.usage(); }
uint64_t consumer_usage() const { return buffer_.usage(); }
+ uint64_t GetQueueIndex() const { return metadata_header_->queue_index; }
+ void SetQueueIndex(uint64_t index) { metadata_header_->queue_index = index; }
+
protected:
explicit BufferHubBuffer(LocalChannelHandle channel);
explicit BufferHubBuffer(const std::string& endpoint_path);
@@ -106,6 +126,31 @@
// Initialization helper.
int ImportBuffer();
+ // Check invalid metadata operation. Returns 0 if requested metadata is valid.
+ int CheckMetadata(size_t user_metadata_size) const;
+
+ // Send out the new fence by updating the shared fence (shared_release_fence
+ // for producer and shared_acquire_fence for consumer). Note that during this
+ // should only be used in LocalPost() or LocalRelease, and the shared fence
+ // shouldn't be poll'ed by the other end.
+ int UpdateSharedFence(const LocalHandle& new_fence,
+ const LocalHandle& shared_fence);
+
+ // IonBuffer that is shared between bufferhubd, producer, and consumers.
+ size_t metadata_buf_size_{0};
+ size_t user_metadata_size_{0};
+ BufferHubDefs::MetadataHeader* metadata_header_{nullptr};
+ void* user_metadata_ptr_{nullptr};
+ std::atomic<uint64_t>* buffer_state_{nullptr};
+ std::atomic<uint64_t>* fence_state_{nullptr};
+
+ LocalHandle shared_acquire_fence_;
+ LocalHandle shared_release_fence_;
+
+ // A local fence fd that holds the ownership of the fence fd on Post (for
+ // producer) and Release (for consumer).
+ LocalHandle pending_fence_fd_;
+
private:
BufferHubBuffer(const BufferHubBuffer&) = delete;
void operator=(const BufferHubBuffer&) = delete;
@@ -114,8 +159,9 @@
// for logging and debugging purposes only and should not be used for lookup
// or any other functional purpose as a security precaution.
int id_;
-
+ uint64_t buffer_state_bit_{0ULL};
IonBuffer buffer_;
+ IonBuffer metadata_buffer_;
};
// This represents a writable buffer. Calling Post notifies all clients and
@@ -136,12 +182,17 @@
static std::unique_ptr<BufferProducer> Import(
Status<LocalChannelHandle> status);
+ // Asynchronously posts a buffer. The fence and metadata are passed to
+ // consumer via shared fd and shared memory.
+ int PostAsync(const DvrNativeBufferMetadata* meta,
+ const LocalHandle& ready_fence);
+
// Post this buffer, passing |ready_fence| to the consumers. The bytes in
// |meta| are passed unaltered to the consumers. The producer must not modify
// the buffer until it is re-gained.
// This returns zero or a negative unix error code.
int Post(const LocalHandle& ready_fence, const void* meta,
- size_t meta_size_bytes);
+ size_t user_metadata_size);
template <typename Meta,
typename = typename std::enable_if<std::is_void<Meta>::value>::type>
@@ -160,16 +211,15 @@
// is in the released state.
// This returns zero or a negative unix error code.
int Gain(LocalHandle* release_fence);
+ int GainAsync();
// Asynchronously marks a released buffer as gained. This method is similar to
// the synchronous version above, except that it does not wait for BufferHub
- // to acknowledge success or failure, nor does it transfer a release fence to
- // the client. This version may be used in situations where a release fence is
- // not needed. Because of the asynchronous nature of the underlying message,
- // no error is returned if this method is called when the buffer is in an
- // incorrect state. Returns zero if sending the message succeeded, or a
- // negative errno code otherwise.
- int GainAsync();
+ // to acknowledge success or failure. Because of the asynchronous nature of
+ // the underlying message, no error is returned if this method is called when
+ // the buffer is in an incorrect state. Returns zero if sending the message
+ // succeeded, or a negative errno code if local error check fails.
+ int GainAsync(DvrNativeBufferMetadata* out_meta, LocalHandle* out_fence);
// Attaches the producer to |name| so that it becomes a persistent buffer that
// may be retrieved by name at a later time. This may be used in cases where a
@@ -216,7 +266,7 @@
BufferProducer(const std::string& name, int user_id, int group_id,
uint32_t width, uint32_t height, uint32_t format,
uint64_t producer_usage, uint64_t consumer_usage,
- size_t meta_size_bytes);
+ size_t user_metadata_size);
// Constructs a blob (flat) buffer with the given usage flags.
BufferProducer(uint32_t usage, size_t size);
@@ -234,6 +284,11 @@
// Imports the given file handle to a producer channel, taking ownership.
explicit BufferProducer(LocalChannelHandle channel);
+
+ // Local state transition helpers.
+ int LocalGain(DvrNativeBufferMetadata* out_meta, LocalHandle* out_fence);
+ int LocalPost(const DvrNativeBufferMetadata* meta,
+ const LocalHandle& ready_fence);
};
// This is a connection to a producer buffer, which can be located in another
@@ -263,7 +318,7 @@
// are available. This call will only succeed if the buffer is in the posted
// state.
// Returns zero on success, or a negative errno code otherwise.
- int Acquire(LocalHandle* ready_fence, void* meta, size_t meta_size_bytes);
+ int Acquire(LocalHandle* ready_fence, void* meta, size_t user_metadata_size);
// Attempt to retrieve a post event from buffer hub. If successful,
// |ready_fence| is set to a fence to wait on until the buffer is ready. This
@@ -274,20 +329,22 @@
return Acquire(ready_fence, meta, sizeof(*meta));
}
+ // Asynchronously acquires a bufer.
+ int AcquireAsync(DvrNativeBufferMetadata* out_meta, LocalHandle* out_fence);
+
// This should be called after a successful Acquire call. If the fence is
// valid the fence determines the buffer usage, otherwise the buffer is
// released immediately.
// This returns zero or a negative unix error code.
int Release(const LocalHandle& release_fence);
+ int ReleaseAsync();
// Asynchronously releases a buffer. Similar to the synchronous version above,
- // except that it does not wait for BufferHub to reply with success or error,
- // nor does it transfer a release fence. This version may be used in
- // situations where a release fence is not needed. Because of the asynchronous
- // nature of the underlying message, no error is returned if this method is
- // called when the buffer is in an incorrect state. Returns zero if sending
- // the message succeeded, or a negative errno code otherwise.
- int ReleaseAsync();
+ // except that it does not wait for BufferHub to reply with success or error.
+ // The fence and metadata are passed to consumer via shared fd and shared
+ // memory.
+ int ReleaseAsync(const DvrNativeBufferMetadata* meta,
+ const LocalHandle& release_fence);
// May be called after or instead of Acquire to indicate that the consumer
// does not need to access the buffer this cycle. This returns zero or a
@@ -305,6 +362,11 @@
friend BASE;
explicit BufferConsumer(LocalChannelHandle channel);
+
+ // Local state transition helpers.
+ int LocalAcquire(DvrNativeBufferMetadata* out_meta, LocalHandle* out_fence);
+ int LocalRelease(const DvrNativeBufferMetadata* meta,
+ const LocalHandle& release_fence);
};
} // namespace dvr
diff --git a/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h b/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h
index ca0e0e0..f9fd42d 100644
--- a/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h
+++ b/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h
@@ -5,6 +5,7 @@
#include <gui/BufferQueueDefs.h>
#include <sys/types.h>
+#include <dvr/dvr_api.h>
#include <pdx/channel_handle.h>
#include <pdx/file_handle.h>
#include <pdx/rpc/remote_method.h>
@@ -14,6 +15,71 @@
namespace android {
namespace dvr {
+namespace BufferHubDefs {
+
+static constexpr uint32_t kMetadataFormat = HAL_PIXEL_FORMAT_BLOB;
+static constexpr uint32_t kMetadataUsage =
+ GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN;
+
+// Single producuer multiple (up to 63) consumers ownership signal.
+// 64-bit atomic unsigned int.
+//
+// MSB LSB
+// | |
+// v v
+// [P|C62|...|C1|C0]
+// Gain'ed state: [0|..|0|0] -> Exclusively Writable.
+// Post'ed state: [1|..|0|0]
+// Acquired'ed state: [1|..|X|X] -> At least one bit is set in lower 63 bits
+// Released'ed state: [0|..|X|X] -> At least one bit is set in lower 63 bits
+static constexpr uint64_t kProducerStateBit = 1ULL << 63;
+static constexpr uint64_t kConsumerStateMask = (1ULL << 63) - 1;
+
+static inline void ModifyBufferState(std::atomic<uint64_t>* buffer_state,
+ uint64_t clear_mask, uint64_t set_mask) {
+ uint64_t old_state;
+ uint64_t new_state;
+ do {
+ old_state = buffer_state->load();
+ new_state = (old_state & ~clear_mask) | set_mask;
+ } while (!buffer_state->compare_exchange_weak(old_state, new_state));
+}
+
+static inline bool IsBufferGained(uint64_t state) { return state == 0; }
+
+static inline bool IsBufferPosted(uint64_t state,
+ uint64_t consumer_bit = kConsumerStateMask) {
+ return (state & kProducerStateBit) && !(state & consumer_bit);
+}
+
+static inline bool IsBufferAcquired(uint64_t state) {
+ return (state & kProducerStateBit) && (state & kConsumerStateMask);
+}
+
+static inline bool IsBufferReleased(uint64_t state) {
+ return !(state & kProducerStateBit) && (state & kConsumerStateMask);
+}
+
+struct __attribute__((packed, aligned(8))) MetadataHeader {
+ // Internal data format, which can be updated as long as the size, padding and
+ // field alignment of the struct is consistent within the same ABI. As this
+ // part is subject for future updates, it's not stable cross Android version,
+ // so don't have it visible from outside of the Android platform (include Apps
+ // and vendor HAL).
+ std::atomic<uint64_t> buffer_state;
+ std::atomic<uint64_t> fence_state;
+ uint64_t queue_index;
+
+ // Public data format, which should be updated with caution. See more details
+ // in dvr_api.h
+ DvrNativeBufferMetadata metadata;
+};
+
+static_assert(sizeof(MetadataHeader) == 128, "Unexpected MetadataHeader size");
+static constexpr size_t kMetadataHeaderSize = sizeof(MetadataHeader);
+
+} // namespace BufferHubDefs
+
template <typename FileHandleType>
class NativeBufferHandle {
public:
@@ -93,6 +159,57 @@
void operator=(const NativeBufferHandle&) = delete;
};
+template <typename FileHandleType>
+class BufferDescription {
+ public:
+ BufferDescription() = default;
+ BufferDescription(const IonBuffer& buffer, const IonBuffer& metadata, int id,
+ uint64_t buffer_state_bit,
+ const FileHandleType& acquire_fence_fd,
+ const FileHandleType& release_fence_fd)
+ : id_(id),
+ buffer_state_bit_(buffer_state_bit),
+ buffer_(buffer, id),
+ metadata_(metadata, id),
+ acquire_fence_fd_(acquire_fence_fd.Borrow()),
+ release_fence_fd_(release_fence_fd.Borrow()) {}
+
+ BufferDescription(BufferDescription&& other) = default;
+ BufferDescription& operator=(BufferDescription&& other) = default;
+
+ // ID of the buffer client. All BufferHubBuffer clients derived from the same
+ // buffer in bufferhubd share the same buffer id.
+ int id() const { return id_; }
+ // State mask of the buffer client. Each BufferHubBuffer client backed by the
+ // same buffer channel has uniqued state bit among its siblings. For a
+ // producer buffer the bit must be kProducerStateBit; for a consumer the bit
+ // must be one of the kConsumerStateMask.
+ uint64_t buffer_state_bit() const { return buffer_state_bit_; }
+ FileHandleType take_acquire_fence() { return std::move(acquire_fence_fd_); }
+ FileHandleType take_release_fence() { return std::move(release_fence_fd_); }
+
+ int ImportBuffer(IonBuffer* buffer) { return buffer_.Import(buffer); }
+ int ImportMetadata(IonBuffer* metadata) { return metadata_.Import(metadata); }
+
+ private:
+ int id_{-1};
+ uint64_t buffer_state_bit_{0};
+ // Two IonBuffers: one for the graphic buffer and one for metadata.
+ NativeBufferHandle<FileHandleType> buffer_;
+ NativeBufferHandle<FileHandleType> metadata_;
+
+ // Pamameters for shared fences.
+ FileHandleType acquire_fence_fd_;
+ FileHandleType release_fence_fd_;
+
+ PDX_SERIALIZABLE_MEMBERS(BufferDescription<FileHandleType>, id_,
+ buffer_state_bit_, buffer_, metadata_,
+ acquire_fence_fd_, release_fence_fd_);
+
+ BufferDescription(const BufferDescription&) = delete;
+ void operator=(const BufferDescription&) = delete;
+};
+
using BorrowedNativeBufferHandle = NativeBufferHandle<pdx::BorrowedHandle>;
using LocalNativeBufferHandle = NativeBufferHandle<pdx::LocalHandle>;
@@ -149,11 +266,11 @@
// Size of the meta data associated with all the buffers allocated from the
// queue.
- size_t meta_size_bytes;
+ size_t user_metadata_size;
private:
PDX_SERIALIZABLE_MEMBERS(ProducerQueueConfig, is_async, default_width,
- default_height, default_format, meta_size_bytes);
+ default_height, default_format, user_metadata_size);
};
class ProducerQueueConfigBuilder {
@@ -161,7 +278,7 @@
// Build a ProducerQueueConfig object.
ProducerQueueConfig Build() {
return {is_async_, default_width_, default_height_, default_format_,
- meta_size_bytes_};
+ user_metadata_size_};
}
ProducerQueueConfigBuilder& SetIsAsync(bool is_async) {
@@ -186,12 +303,12 @@
template <typename Meta>
ProducerQueueConfigBuilder& SetMetadata() {
- meta_size_bytes_ = sizeof(Meta);
+ user_metadata_size_ = sizeof(Meta);
return *this;
}
- ProducerQueueConfigBuilder& SetMetadataSize(size_t meta_size_bytes) {
- meta_size_bytes_ = meta_size_bytes;
+ ProducerQueueConfigBuilder& SetMetadataSize(size_t user_metadata_size) {
+ user_metadata_size_ = user_metadata_size;
return *this;
}
@@ -200,7 +317,7 @@
uint32_t default_width_{1};
uint32_t default_height_{1};
uint32_t default_format_{1}; // PIXEL_FORMAT_RGBA_8888
- size_t meta_size_bytes_{0};
+ size_t user_metadata_size_{0};
};
// Explicit specializations of ProducerQueueConfigBuilder::Build for void
@@ -208,7 +325,7 @@
template <>
inline ProducerQueueConfigBuilder&
ProducerQueueConfigBuilder::SetMetadata<void>() {
- meta_size_bytes_ = 0;
+ user_metadata_size_ = 0;
return *this;
}
@@ -269,7 +386,6 @@
};
// Aliases.
- using MetaData = pdx::rpc::BufferWrapper<std::uint8_t*>;
using LocalChannelHandle = pdx::LocalChannelHandle;
using LocalHandle = pdx::LocalHandle;
using Void = pdx::rpc::Void;
@@ -277,25 +393,24 @@
// Methods.
PDX_REMOTE_METHOD(CreateBuffer, kOpCreateBuffer,
void(uint32_t width, uint32_t height, uint32_t format,
- uint64_t usage, size_t meta_size_bytes));
+ uint64_t usage, size_t user_metadata_size));
PDX_REMOTE_METHOD(CreatePersistentBuffer, kOpCreatePersistentBuffer,
void(const std::string& name, int user_id, int group_id,
uint32_t width, uint32_t height, uint32_t format,
- uint64_t usage, size_t meta_size_bytes));
+ uint64_t usage, size_t user_metadata_size));
PDX_REMOTE_METHOD(GetPersistentBuffer, kOpGetPersistentBuffer,
void(const std::string& name));
PDX_REMOTE_METHOD(GetBuffer, kOpGetBuffer,
- NativeBufferHandle<LocalHandle>(Void));
+ BufferDescription<LocalHandle>(Void));
PDX_REMOTE_METHOD(NewConsumer, kOpNewConsumer, LocalChannelHandle(Void));
PDX_REMOTE_METHOD(ProducerMakePersistent, kOpProducerMakePersistent,
void(const std::string& name, int user_id, int group_id));
PDX_REMOTE_METHOD(ProducerRemovePersistence, kOpProducerRemovePersistence,
void(Void));
PDX_REMOTE_METHOD(ProducerPost, kOpProducerPost,
- void(LocalFence acquire_fence, MetaData));
+ void(LocalFence acquire_fence));
PDX_REMOTE_METHOD(ProducerGain, kOpProducerGain, LocalFence(Void));
- PDX_REMOTE_METHOD(ConsumerAcquire, kOpConsumerAcquire,
- std::pair<LocalFence, MetaData>(std::size_t metadata_size));
+ PDX_REMOTE_METHOD(ConsumerAcquire, kOpConsumerAcquire, LocalFence(Void));
PDX_REMOTE_METHOD(ConsumerRelease, kOpConsumerRelease,
void(LocalFence release_fence));
PDX_REMOTE_METHOD(ConsumerSetIgnore, kOpConsumerSetIgnore, void(bool ignore));
@@ -305,7 +420,7 @@
QueueInfo(const ProducerQueueConfig& producer_config,
const UsagePolicy& usage_policy));
PDX_REMOTE_METHOD(CreateConsumerQueue, kOpCreateConsumerQueue,
- LocalChannelHandle(Void));
+ LocalChannelHandle(bool silent_queue));
PDX_REMOTE_METHOD(GetQueueInfo, kOpGetQueueInfo, QueueInfo(Void));
PDX_REMOTE_METHOD(ProducerQueueAllocateBuffers,
kOpProducerQueueAllocateBuffers,
diff --git a/libs/vr/libbufferhub/include/private/dvr/native_buffer.h b/libs/vr/libbufferhub/include/private/dvr/native_buffer.h
index a54579f..140ffc5 100644
--- a/libs/vr/libbufferhub/include/private/dvr/native_buffer.h
+++ b/libs/vr/libbufferhub/include/private/dvr/native_buffer.h
@@ -52,8 +52,6 @@
void operator=(NativeBuffer&) = delete;
};
-// NativeBufferProducer is an implementation of ANativeWindowBuffer backed by a
-// BufferProducer.
class NativeBufferProducer : public android::ANativeObjectBase<
ANativeWindowBuffer, NativeBufferProducer,
android::LightRefBase<NativeBufferProducer>> {
@@ -71,20 +69,25 @@
ANativeWindowBuffer::stride = buffer_->stride();
ANativeWindowBuffer::format = buffer_->format();
ANativeWindowBuffer::usage = buffer_->usage();
- handle = buffer_->native_handle();
+ ANativeWindowBuffer::handle = buffer_->native_handle();
+ if (display_) {
+ image_khr_ =
+ eglCreateImageKHR(display_, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID,
+ static_cast<ANativeWindowBuffer*>(this), nullptr);
+ } else {
+ image_khr_ = EGL_NO_IMAGE_KHR;
+ }
}
explicit NativeBufferProducer(const std::shared_ptr<BufferProducer>& buffer)
: NativeBufferProducer(buffer, nullptr, 0) {}
virtual ~NativeBufferProducer() {
- for (EGLImageKHR egl_image : egl_images_) {
- if (egl_image != EGL_NO_IMAGE_KHR)
- eglDestroyImageKHR(display_, egl_image);
- }
+ if (image_khr_ != EGL_NO_IMAGE_KHR)
+ eglDestroyImageKHR(display_, image_khr_);
}
- EGLImageKHR image_khr(int index) const { return egl_images_[index]; }
+ EGLImageKHR image_khr() const { return image_khr_; }
std::shared_ptr<BufferProducer> buffer() const { return buffer_; }
int release_fence() const { return release_fence_.Get(); }
uint32_t surface_buffer_index() const { return surface_buffer_index_; }
@@ -112,7 +115,7 @@
std::shared_ptr<BufferProducer> buffer_;
pdx::LocalHandle release_fence_;
- std::vector<EGLImageKHR> egl_images_;
+ EGLImageKHR image_khr_;
uint32_t surface_buffer_index_;
EGLDisplay display_;
diff --git a/libs/vr/libbufferhubqueue/Android.bp b/libs/vr/libbufferhubqueue/Android.bp
index 0b3b2f0..93ccd0f 100644
--- a/libs/vr/libbufferhubqueue/Android.bp
+++ b/libs/vr/libbufferhubqueue/Android.bp
@@ -48,6 +48,7 @@
cflags: [
"-DLOG_TAG=\"libbufferhubqueue\"",
"-DTRACE=0",
+ "-DATRACE_TAG=ATRACE_TAG_GRAPHICS",
],
srcs: sourceFiles,
export_include_dirs: includeFiles,
diff --git a/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp b/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp
index a53c8b0..8bea0cd 100644
--- a/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp
+++ b/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp
@@ -10,6 +10,7 @@
#include <pdx/default_transport/client_channel.h>
#include <pdx/default_transport/client_channel_factory.h>
#include <pdx/file_handle.h>
+#include <pdx/trace.h>
#define RETRY_EINTR(fnc_call) \
([&]() -> decltype(fnc_call) { \
@@ -44,17 +45,6 @@
}
}
-// Polls a buffer for the given events, taking care to do the proper
-// translation.
-Status<int> PollEvents(const std::shared_ptr<BufferHubBuffer>& buffer,
- short events) {
- auto poll_status = PollEvents(buffer->event_fd(), events);
- if (!poll_status)
- return poll_status;
-
- return buffer->GetEventMask(poll_status.get());
-}
-
std::pair<int32_t, int32_t> Unstuff(uint64_t value) {
return {static_cast<int32_t>(value >> 32),
static_cast<int32_t>(value & ((1ull << 32) - 1))};
@@ -115,27 +105,27 @@
default_width_ = queue_info.producer_config.default_width;
default_height_ = queue_info.producer_config.default_height;
default_format_ = queue_info.producer_config.default_format;
- meta_size_ = queue_info.producer_config.meta_size_bytes;
+ user_metadata_size_ = queue_info.producer_config.user_metadata_size;
id_ = queue_info.id;
}
std::unique_ptr<ConsumerQueue> BufferHubQueue::CreateConsumerQueue() {
- if (auto status = CreateConsumerQueueHandle())
+ if (auto status = CreateConsumerQueueHandle(/*silent*/ false))
return std::unique_ptr<ConsumerQueue>(new ConsumerQueue(status.take()));
else
return nullptr;
}
std::unique_ptr<ConsumerQueue> BufferHubQueue::CreateSilentConsumerQueue() {
- if (auto status = CreateConsumerQueueHandle())
- return std::unique_ptr<ConsumerQueue>(
- new ConsumerQueue(status.take(), true));
+ if (auto status = CreateConsumerQueueHandle(/*silent*/ true))
+ return std::unique_ptr<ConsumerQueue>(new ConsumerQueue(status.take()));
else
return nullptr;
}
-Status<LocalChannelHandle> BufferHubQueue::CreateConsumerQueueHandle() {
- auto status = InvokeRemoteMethod<BufferHubRPC::CreateConsumerQueue>();
+Status<LocalChannelHandle> BufferHubQueue::CreateConsumerQueueHandle(
+ bool silent) {
+ auto status = InvokeRemoteMethod<BufferHubRPC::CreateConsumerQueue>(silent);
if (!status) {
ALOGE(
"BufferHubQueue::CreateConsumerQueue: Failed to create consumer queue: "
@@ -148,6 +138,7 @@
}
bool BufferHubQueue::WaitForBuffers(int timeout) {
+ ATRACE_NAME("BufferHubQueue::WaitForBuffers");
std::array<epoll_event, kMaxEvents> events;
// Loop at least once to check for hangups.
@@ -178,13 +169,18 @@
const int num_events = ret;
// A BufferQueue's epoll fd tracks N+1 events, where there are N events,
- // one for each buffer, in the queue and one extra event for the queue
+ // one for each buffer in the queue, and one extra event for the queue
// client itself.
for (int i = 0; i < num_events; i++) {
int32_t event_fd;
int32_t index;
std::tie(event_fd, index) = Unstuff(events[i].data.u64);
+ PDX_TRACE_FORMAT(
+ "epoll_event|queue_id=%d;num_events=%d;event_index=%d;event_fd=%d;"
+ "slot=%d|",
+ id(), num_events, i, event_fd, index);
+
ALOGD_IF(TRACE,
"BufferHubQueue::WaitForBuffers: event %d: event_fd=%d index=%d",
i, event_fd, index);
@@ -208,6 +204,7 @@
Status<void> BufferHubQueue::HandleBufferEvent(size_t slot, int event_fd,
int poll_events) {
+ ATRACE_NAME("BufferHubQueue::HandleBufferEvent");
if (!buffers_[slot]) {
ALOGW("BufferHubQueue::HandleBufferEvent: Invalid buffer slot: %zu", slot);
return ErrorStatus(ENOENT);
@@ -221,58 +218,19 @@
}
const int events = status.get();
+ PDX_TRACE_FORMAT(
+ "buffer|queue_id=%d;buffer_id=%d;slot=%zu;event_fd=%d;poll_events=%x;"
+ "events=%d|",
+ id(), buffers_[slot]->id(), slot, event_fd, poll_events, events);
+
if (events & EPOLLIN) {
- auto entry_status = OnBufferReady(buffers_[slot], slot);
- if (entry_status.ok() || entry_status.error() == EALREADY) {
- // Only enqueue the buffer if it moves to or is already in the state
- // requested in OnBufferReady().
- return Enqueue(entry_status.take());
- } else if (entry_status.error() == EBUSY) {
- // If the buffer is busy this means that the buffer moved from released to
- // posted when a new consumer was created before the ProducerQueue had a
- // chance to regain it. This is a valid transition that we have to handle
- // because edge triggered poll events latch the ready state even if it is
- // later de-asserted -- don't enqueue or print an error log in this case.
- } else {
- ALOGE(
- "BufferHubQueue::HandleBufferEvent: Failed to set buffer ready, "
- "queue_id=%d buffer_id=%d: %s",
- id(), buffers_[slot]->id(), entry_status.GetErrorMessage().c_str());
- }
+ return Enqueue({buffers_[slot], slot, buffers_[slot]->GetQueueIndex()});
} else if (events & EPOLLHUP) {
- // Check to see if the current buffer in the slot hung up. This is a bit of
- // paranoia to deal with the epoll set getting out of sync with the buffer
- // slots.
- auto poll_status = PollEvents(buffers_[slot], POLLIN);
- if (!poll_status && poll_status.error() != ETIMEDOUT) {
- ALOGE("BufferHubQueue::HandleBufferEvent: Failed to poll buffer: %s",
- poll_status.GetErrorMessage().c_str());
- return poll_status.error_status();
- }
-
- const bool hangup_pending = status.ok() && (poll_status.get() & EPOLLHUP);
-
ALOGW(
"BufferHubQueue::HandleBufferEvent: Received EPOLLHUP event: slot=%zu "
- "event_fd=%d buffer_id=%d hangup_pending=%d poll_status=%x",
- slot, buffers_[slot]->event_fd(), buffers_[slot]->id(), hangup_pending,
- poll_status.get());
-
- if (hangup_pending) {
- return RemoveBuffer(slot);
- } else {
- // Clean up the bookkeeping for the event fd. This is a bit of paranoia to
- // deal with the epoll set getting out of sync with the buffer slots.
- // Hitting this path should be very unusual.
- const int ret = epoll_fd_.Control(EPOLL_CTL_DEL, event_fd, nullptr);
- if (ret < 0) {
- ALOGE(
- "BufferHubQueue::HandleBufferEvent: Failed to remove fd=%d from "
- "epoll set: %s",
- event_fd, strerror(-ret));
- return ErrorStatus(-ret);
- }
- }
+ "event_fd=%d buffer_id=%d",
+ slot, buffers_[slot]->event_fd(), buffers_[slot]->id());
+ return RemoveBuffer(slot);
} else {
ALOGW(
"BufferHubQueue::HandleBufferEvent: Unknown event, slot=%zu, epoll "
@@ -284,6 +242,7 @@
}
Status<void> BufferHubQueue::HandleQueueEvent(int poll_event) {
+ ATRACE_NAME("BufferHubQueue::HandleQueueEvent");
auto status = GetEventMask(poll_event);
if (!status) {
ALOGW("BufferHubQueue::HandleQueueEvent: Failed to get event mask: %s",
@@ -330,13 +289,16 @@
return remove_status.error_status();
}
- epoll_event event = {.events = EPOLLIN | EPOLLET,
- .data = {.u64 = Stuff(buffer->event_fd(), slot)}};
- const int ret = epoll_fd_.Control(EPOLL_CTL_ADD, buffer->event_fd(), &event);
- if (ret < 0) {
- ALOGE("BufferHubQueue::AddBuffer: Failed to add buffer to epoll set: %s",
- strerror(-ret));
- return ErrorStatus(-ret);
+ for (const auto& event_source : buffer->GetEventSources()) {
+ epoll_event event = {.events = event_source.event_mask | EPOLLET,
+ .data = {.u64 = Stuff(buffer->event_fd(), slot)}};
+ const int ret =
+ epoll_fd_.Control(EPOLL_CTL_ADD, event_source.event_fd, &event);
+ if (ret < 0) {
+ ALOGE("BufferHubQueue::AddBuffer: Failed to add buffer to epoll set: %s",
+ strerror(-ret));
+ return ErrorStatus(-ret);
+ }
}
buffers_[slot] = buffer;
@@ -348,15 +310,16 @@
ALOGD_IF(TRACE, "BufferHubQueue::RemoveBuffer: slot=%zu", slot);
if (buffers_[slot]) {
- const int ret =
- epoll_fd_.Control(EPOLL_CTL_DEL, buffers_[slot]->event_fd(), nullptr);
- if (ret < 0) {
- ALOGE(
- "BufferHubQueue::RemoveBuffer: Failed to remove buffer from epoll "
- "set: "
- "%s",
- strerror(-ret));
- return ErrorStatus(-ret);
+ for (const auto& event_source : buffers_[slot]->GetEventSources()) {
+ const int ret =
+ epoll_fd_.Control(EPOLL_CTL_DEL, event_source.event_fd, nullptr);
+ if (ret < 0) {
+ ALOGE(
+ "BufferHubQueue::RemoveBuffer: Failed to remove buffer from epoll "
+ "set: %s",
+ strerror(-ret));
+ return ErrorStatus(-ret);
+ }
}
// Trigger OnBufferRemoved callback if registered.
@@ -372,7 +335,7 @@
Status<void> BufferHubQueue::Enqueue(Entry entry) {
if (!is_full()) {
- available_buffers_.Append(std::move(entry));
+ available_buffers_.push(std::move(entry));
// Trigger OnBufferAvailable callback if registered.
if (on_buffer_available_)
@@ -385,25 +348,26 @@
}
}
-Status<std::shared_ptr<BufferHubBuffer>> BufferHubQueue::Dequeue(
- int timeout, size_t* slot, void* meta, LocalHandle* fence) {
+Status<std::shared_ptr<BufferHubBuffer>> BufferHubQueue::Dequeue(int timeout,
+ size_t* slot) {
ALOGD_IF(TRACE, "BufferHubQueue::Dequeue: count=%zu, timeout=%d", count(),
timeout);
- if (!WaitForBuffers(timeout))
- return ErrorStatus(ETIMEDOUT);
+ PDX_TRACE_FORMAT("BufferHubQueue::Dequeue|count=%zu|", count());
- auto& entry = available_buffers_.Front();
+ if (count() == 0) {
+ if (!WaitForBuffers(timeout))
+ return ErrorStatus(ETIMEDOUT);
+ }
+
+ auto& entry = available_buffers_.top();
+ PDX_TRACE_FORMAT("buffer|buffer_id=%d;slot=%zu|", entry.buffer->id(),
+ entry.slot);
std::shared_ptr<BufferHubBuffer> buffer = std::move(entry.buffer);
*slot = entry.slot;
- *fence = std::move(entry.fence);
- if (meta && entry.metadata) {
- std::copy(entry.metadata.get(), entry.metadata.get() + meta_size_,
- reinterpret_cast<uint8_t*>(meta));
- }
- available_buffers_.PopFront();
+ available_buffers_.pop();
return {std::move(buffer)};
}
@@ -417,6 +381,29 @@
on_buffer_removed_ = callback;
}
+pdx::Status<void> BufferHubQueue::FreeAllBuffers() {
+ // Clear all available buffers.
+ while (!available_buffers_.empty())
+ available_buffers_.pop();
+
+ pdx::Status<void> last_error; // No error.
+ // Clear all buffers this producer queue is tracking.
+ for (size_t slot = 0; slot < BufferHubQueue::kMaxQueueCapacity; slot++) {
+ if (buffers_[slot] != nullptr) {
+ auto status = RemoveBuffer(slot);
+ if (!status) {
+ ALOGE(
+ "ProducerQueue::FreeAllBuffers: Failed to remove buffer at "
+ "slot=%zu.",
+ slot);
+ last_error = status.error_status();
+ }
+ }
+ }
+
+ return last_error;
+}
+
ProducerQueue::ProducerQueue(LocalChannelHandle handle)
: BASE(std::move(handle)) {
auto status = ImportQueue();
@@ -442,46 +429,78 @@
SetupQueue(status.get());
}
-Status<void> ProducerQueue::AllocateBuffer(uint32_t width, uint32_t height,
- uint32_t layer_count,
- uint32_t format, uint64_t usage,
- size_t* out_slot) {
- if (out_slot == nullptr) {
- ALOGE("ProducerQueue::AllocateBuffer: Parameter out_slot cannot be null.");
- return ErrorStatus(EINVAL);
- }
-
- if (is_full()) {
- ALOGE("ProducerQueue::AllocateBuffer queue is at maximum capacity: %zu",
- capacity());
+Status<std::vector<size_t>> ProducerQueue::AllocateBuffers(
+ uint32_t width, uint32_t height, uint32_t layer_count, uint32_t format,
+ uint64_t usage, size_t buffer_count) {
+ if (capacity() + buffer_count > kMaxQueueCapacity) {
+ ALOGE(
+ "ProducerQueue::AllocateBuffers: queue is at capacity: %zu, cannot "
+ "allocate %zu more buffer(s).",
+ capacity(), buffer_count);
return ErrorStatus(E2BIG);
}
- const size_t kBufferCount = 1u;
Status<std::vector<std::pair<LocalChannelHandle, size_t>>> status =
InvokeRemoteMethod<BufferHubRPC::ProducerQueueAllocateBuffers>(
- width, height, layer_count, format, usage, kBufferCount);
+ width, height, layer_count, format, usage, buffer_count);
if (!status) {
- ALOGE("ProducerQueue::AllocateBuffer failed to create producer buffer: %s",
+ ALOGE("ProducerQueue::AllocateBuffers: failed to allocate buffers: %s",
status.GetErrorMessage().c_str());
return status.error_status();
}
auto buffer_handle_slots = status.take();
- LOG_ALWAYS_FATAL_IF(buffer_handle_slots.size() != kBufferCount,
+ LOG_ALWAYS_FATAL_IF(buffer_handle_slots.size() != buffer_count,
"BufferHubRPC::ProducerQueueAllocateBuffers should "
- "return one and only one buffer handle.");
+ "return %zu buffer handle(s), but returned %zu instead.",
+ buffer_count, buffer_handle_slots.size());
+ std::vector<size_t> buffer_slots;
+ buffer_slots.reserve(buffer_count);
+
+ // Bookkeeping for each buffer.
+ for (auto& hs : buffer_handle_slots) {
+ auto& buffer_handle = hs.first;
+ size_t buffer_slot = hs.second;
+
+ // Note that import might (though very unlikely) fail. If so, buffer_handle
+ // will be closed and included in returned buffer_slots.
+ if (AddBuffer(BufferProducer::Import(std::move(buffer_handle)),
+ buffer_slot)) {
+ ALOGD_IF(TRACE, "ProducerQueue::AllocateBuffers: new buffer at slot: %zu",
+ buffer_slot);
+ buffer_slots.push_back(buffer_slot);
+ }
+ }
+
+ if (buffer_slots.size() == 0) {
+ // Error out if no buffer is allocated and improted.
+ ALOGE_IF(TRACE, "ProducerQueue::AllocateBuffers: no buffer allocated.");
+ ErrorStatus(ENOMEM);
+ }
+
+ return {std::move(buffer_slots)};
+}
+
+Status<size_t> ProducerQueue::AllocateBuffer(uint32_t width, uint32_t height,
+ uint32_t layer_count,
+ uint32_t format, uint64_t usage) {
// We only allocate one buffer at a time.
- auto& buffer_handle = buffer_handle_slots[0].first;
- size_t buffer_slot = buffer_handle_slots[0].second;
- ALOGD_IF(TRACE,
- "ProducerQueue::AllocateBuffer, new buffer, channel_handle: %d",
- buffer_handle.value());
+ constexpr size_t buffer_count = 1;
+ auto status =
+ AllocateBuffers(width, height, layer_count, format, usage, buffer_count);
+ if (!status) {
+ ALOGE("ProducerQueue::AllocateBuffer: Failed to allocate buffer: %s",
+ status.GetErrorMessage().c_str());
+ return status.error_status();
+ }
- *out_slot = buffer_slot;
- return AddBuffer(BufferProducer::Import(std::move(buffer_handle)),
- buffer_slot);
+ if (status.get().size() == 0) {
+ ALOGE_IF(TRACE, "ProducerQueue::AllocateBuffer: no buffer allocated.");
+ ErrorStatus(ENOMEM);
+ }
+
+ return {status.get()[0]};
}
Status<void> ProducerQueue::AddBuffer(
@@ -494,7 +513,7 @@
if (!status)
return status;
- return Enqueue(buffer, slot);
+ return BufferHubQueue::Enqueue({buffer, slot, 0ULL});
}
Status<void> ProducerQueue::RemoveBuffer(size_t slot) {
@@ -511,40 +530,33 @@
Status<std::shared_ptr<BufferProducer>> ProducerQueue::Dequeue(
int timeout, size_t* slot, LocalHandle* release_fence) {
- if (slot == nullptr || release_fence == nullptr) {
- ALOGE("ProducerQueue::Dequeue: Invalid parameter: slot=%p release_fence=%p",
- slot, release_fence);
+ DvrNativeBufferMetadata canonical_meta;
+ return Dequeue(timeout, slot, &canonical_meta, release_fence);
+}
+
+pdx::Status<std::shared_ptr<BufferProducer>> ProducerQueue::Dequeue(
+ int timeout, size_t* slot, DvrNativeBufferMetadata* out_meta,
+ pdx::LocalHandle* release_fence) {
+ ATRACE_NAME("ProducerQueue::Dequeue");
+ if (slot == nullptr || out_meta == nullptr || release_fence == nullptr) {
+ ALOGE("ProducerQueue::Dequeue: Invalid parameter.");
return ErrorStatus(EINVAL);
}
- auto buffer_status =
- BufferHubQueue::Dequeue(timeout, slot, nullptr, release_fence);
- if (!buffer_status)
- return buffer_status.error_status();
+ auto status = BufferHubQueue::Dequeue(timeout, slot);
+ if (!status)
+ return status.error_status();
- return {std::static_pointer_cast<BufferProducer>(buffer_status.take())};
-}
-
-Status<BufferHubQueue::Entry> ProducerQueue::OnBufferReady(
- const std::shared_ptr<BufferHubBuffer>& buffer, size_t slot) {
- ALOGD_IF(TRACE,
- "ProducerQueue::OnBufferReady: queue_id=%d buffer_id=%d slot=%zu",
- id(), buffer->id(), slot);
-
- // Avoid taking a transient reference, buffer is valid for the duration of
- // this method call.
- auto* producer_buffer = static_cast<BufferProducer*>(buffer.get());
- LocalHandle release_fence;
-
- const int ret = producer_buffer->Gain(&release_fence);
- if (ret < 0)
+ auto buffer = std::static_pointer_cast<BufferProducer>(status.take());
+ const int ret = buffer->GainAsync(out_meta, release_fence);
+ if (ret < 0 && ret != -EALREADY)
return ErrorStatus(-ret);
- else
- return {{buffer, nullptr, std::move(release_fence), slot}};
+
+ return {std::move(buffer)};
}
-ConsumerQueue::ConsumerQueue(LocalChannelHandle handle, bool ignore_on_import)
- : BufferHubQueue(std::move(handle)), ignore_on_import_(ignore_on_import) {
+ConsumerQueue::ConsumerQueue(LocalChannelHandle handle)
+ : BufferHubQueue(std::move(handle)) {
auto status = ImportQueue();
if (!status) {
ALOGE("ConsumerQueue::ConsumerQueue: Failed to import queue: %s",
@@ -565,9 +577,17 @@
Status<size_t> ConsumerQueue::ImportBuffers() {
auto status = InvokeRemoteMethod<BufferHubRPC::ConsumerQueueImportBuffers>();
if (!status) {
- ALOGE("ConsumerQueue::ImportBuffers: Failed to import consumer buffer: %s",
+ if (status.error() == EBADR) {
+ ALOGI(
+ "ConsumerQueue::ImportBuffers: Queue is silent, no buffers "
+ "imported.");
+ return {0};
+ } else {
+ ALOGE(
+ "ConsumerQueue::ImportBuffers: Failed to import consumer buffer: %s",
status.GetErrorMessage().c_str());
- return status.error_status();
+ return status.error_status();
+ }
}
int ret;
@@ -581,21 +601,11 @@
std::unique_ptr<BufferConsumer> buffer_consumer =
BufferConsumer::Import(std::move(buffer_handle_slot.first));
-
- // Setup ignore state before adding buffer to the queue.
- if (ignore_on_import_) {
- ALOGD_IF(TRACE,
- "ConsumerQueue::ImportBuffers: Setting buffer to ignored state: "
- "buffer_id=%d",
- buffer_consumer->id());
- ret = buffer_consumer->SetIgnore(true);
- if (ret < 0) {
- ALOGE(
- "ConsumerQueue::ImportBuffers: Failed to set ignored state on "
- "imported buffer buffer_id=%d: %s",
- buffer_consumer->id(), strerror(-ret));
- last_error = ErrorStatus(-ret);
- }
+ if (!buffer_consumer) {
+ ALOGE("ConsumerQueue::ImportBuffers: Failed to import buffer: slot=%zu",
+ buffer_handle_slot.second);
+ last_error = ErrorStatus(EPIPE);
+ continue;
}
auto add_status =
@@ -625,7 +635,7 @@
// Check to see if the buffer is already signaled. This is necessary to catch
// cases where buffers are already available; epoll edge triggered mode does
- // not fire until and edge transition when adding new buffers to the epoll
+ // not fire until an edge transition when adding new buffers to the epoll
// set. Note that we only poll the fd events because HandleBufferEvent() takes
// care of checking the translated buffer events.
auto poll_status = PollEvents(buffer->event_fd(), POLLIN);
@@ -643,51 +653,53 @@
}
Status<std::shared_ptr<BufferConsumer>> ConsumerQueue::Dequeue(
- int timeout, size_t* slot, void* meta, size_t meta_size,
+ int timeout, size_t* slot, void* meta, size_t user_metadata_size,
LocalHandle* acquire_fence) {
- if (meta_size != meta_size_) {
+ if (user_metadata_size != user_metadata_size_) {
ALOGE(
"ConsumerQueue::Dequeue: Metadata size (%zu) for the dequeuing buffer "
"does not match metadata size (%zu) for the queue.",
- meta_size, meta_size_);
+ user_metadata_size, user_metadata_size_);
return ErrorStatus(EINVAL);
}
- if (slot == nullptr || acquire_fence == nullptr) {
- ALOGE(
- "ConsumerQueue::Dequeue: Invalid parameter: slot=%p meta=%p "
- "acquire_fence=%p",
- slot, meta, acquire_fence);
- return ErrorStatus(EINVAL);
+ DvrNativeBufferMetadata canonical_meta;
+ auto status = Dequeue(timeout, slot, &canonical_meta, acquire_fence);
+ if (!status)
+ return status.error_status();
+
+ if (meta && user_metadata_size) {
+ void* metadata_src =
+ reinterpret_cast<void*>(canonical_meta.user_metadata_ptr);
+ if (metadata_src) {
+ memcpy(meta, metadata_src, user_metadata_size);
+ } else {
+ ALOGW("ConsumerQueue::Dequeue: no user-defined metadata.");
+ }
}
- auto buffer_status =
- BufferHubQueue::Dequeue(timeout, slot, meta, acquire_fence);
- if (!buffer_status)
- return buffer_status.error_status();
-
- return {std::static_pointer_cast<BufferConsumer>(buffer_status.take())};
+ return status;
}
-Status<BufferHubQueue::Entry> ConsumerQueue::OnBufferReady(
- const std::shared_ptr<BufferHubBuffer>& buffer, size_t slot) {
- ALOGD_IF(TRACE,
- "ConsumerQueue::OnBufferReady: queue_id=%d buffer_id=%d slot=%zu",
- id(), buffer->id(), slot);
+Status<std::shared_ptr<BufferConsumer>> ConsumerQueue::Dequeue(
+ int timeout, size_t* slot, DvrNativeBufferMetadata* out_meta,
+ pdx::LocalHandle* acquire_fence) {
+ ATRACE_NAME("ConsumerQueue::Dequeue");
+ if (slot == nullptr || out_meta == nullptr || acquire_fence == nullptr) {
+ ALOGE("ConsumerQueue::Dequeue: Invalid parameter.");
+ return ErrorStatus(EINVAL);
+ }
- // Avoid taking a transient reference, buffer is valid for the duration of
- // this method call.
- auto* consumer_buffer = static_cast<BufferConsumer*>(buffer.get());
- std::unique_ptr<uint8_t[]> metadata(meta_size_ ? new uint8_t[meta_size_]
- : nullptr);
- LocalHandle acquire_fence;
+ auto status = BufferHubQueue::Dequeue(timeout, slot);
+ if (!status)
+ return status.error_status();
- const int ret =
- consumer_buffer->Acquire(&acquire_fence, metadata.get(), meta_size_);
+ auto buffer = std::static_pointer_cast<BufferConsumer>(status.take());
+ const int ret = buffer->AcquireAsync(out_meta, acquire_fence);
if (ret < 0)
return ErrorStatus(-ret);
- else
- return {{buffer, std::move(metadata), std::move(acquire_fence), slot}};
+
+ return {std::move(buffer)};
}
Status<void> ConsumerQueue::OnBufferAllocated() {
diff --git a/libs/vr/libbufferhubqueue/buffer_hub_queue_producer.cpp b/libs/vr/libbufferhubqueue/buffer_hub_queue_producer.cpp
index 7dd076a..221bc4f 100644
--- a/libs/vr/libbufferhubqueue/buffer_hub_queue_producer.cpp
+++ b/libs/vr/libbufferhubqueue/buffer_hub_queue_producer.cpp
@@ -131,9 +131,9 @@
status_t BufferHubQueueProducer::dequeueBuffer(
int* out_slot, sp<Fence>* out_fence, uint32_t width, uint32_t height,
- PixelFormat format, uint32_t usage,
+ PixelFormat format, uint64_t usage, uint64_t* /*outBufferAge*/,
FrameEventHistoryDelta* /* out_timestamps */) {
- ALOGD_IF(TRACE, "dequeueBuffer: w=%u, h=%u, format=%d, usage=%u", width,
+ ALOGD_IF(TRACE, "dequeueBuffer: w=%u, h=%u, format=%d, usage=%" PRIu64, width,
height, format, usage);
status_t ret;
@@ -206,11 +206,11 @@
// It's either in free state (if the buffer has never been used before) or
// in queued state (if the buffer has been dequeued and queued back to
// BufferHubQueue).
- // TODO(jwcai) Clean this up, make mBufferState compatible with BufferHub's
- // model.
- LOG_ALWAYS_FATAL_IF((!buffers_[slot].mBufferState.isFree() &&
- !buffers_[slot].mBufferState.isQueued()),
- "dequeueBuffer: slot %zu is not free or queued.", slot);
+ LOG_ALWAYS_FATAL_IF(
+ (!buffers_[slot].mBufferState.isFree() &&
+ !buffers_[slot].mBufferState.isQueued()),
+ "dequeueBuffer: slot %zu is not free or queued, actual state: %s.", slot,
+ buffers_[slot].mBufferState.string());
buffers_[slot].mBufferState.freeQueued();
buffers_[slot].mBufferState.dequeue();
@@ -328,7 +328,7 @@
LocalHandle fence_fd(fence->isValid() ? fence->dup() : -1);
- DvrNativeBufferMetadata meta_data = {};
+ DvrNativeBufferMetadata meta_data;
meta_data.timestamp = timestamp;
meta_data.is_auto_timestamp = static_cast<int32_t>(is_auto_timestamp);
meta_data.dataspace = static_cast<int32_t>(dataspace);
@@ -339,7 +339,7 @@
meta_data.scaling_mode = static_cast<int32_t>(scaling_mode);
meta_data.transform = static_cast<int32_t>(transform);
- buffer_producer->Post(fence_fd, &meta_data, sizeof(meta_data));
+ buffer_producer->PostAsync(&meta_data, fence_fd);
buffers_[slot].mBufferState.queue();
output->width = buffer_producer->width();
@@ -384,7 +384,7 @@
}
auto buffer_producer = buffers_[slot].mBufferProducer;
- queue_->Enqueue(buffer_producer, slot);
+ queue_->Enqueue(buffer_producer, slot, 0ULL);
buffers_[slot].mBufferState.cancel();
buffers_[slot].mFence = fence;
ALOGD_IF(TRACE, "cancelBuffer: slot %d", slot);
@@ -514,6 +514,7 @@
return BAD_VALUE;
}
+ FreeAllBuffers();
connected_api_ = kNoConnectedApi;
return NO_ERROR;
}
@@ -532,7 +533,7 @@
void BufferHubQueueProducer::allocateBuffers(uint32_t /* width */,
uint32_t /* height */,
PixelFormat /* format */,
- uint32_t /* usage */) {
+ uint64_t /* usage */) {
// TODO(jwcai) |allocateBuffers| aims to preallocate up to the maximum number
// of buffers permitted by the current BufferQueue configuration (aka
// |max_buffer_count_|).
@@ -608,13 +609,20 @@
return NO_ERROR;
}
+status_t BufferHubQueueProducer::getConsumerUsage(uint64_t* out_usage) const {
+ ALOGD_IF(TRACE, __FUNCTION__);
+
+ // same value as returned by querying NATIVE_WINDOW_CONSUMER_USAGE_BITS
+ *out_usage = 0;
+ return NO_ERROR;
+}
+
status_t BufferHubQueueProducer::AllocateBuffer(uint32_t width, uint32_t height,
uint32_t layer_count,
PixelFormat format,
uint64_t usage) {
- size_t slot;
auto status =
- queue_->AllocateBuffer(width, height, layer_count, format, usage, &slot);
+ queue_->AllocateBuffer(width, height, layer_count, format, usage);
if (!status) {
ALOGE(
"BufferHubQueueProducer::AllocateBuffer: Failed to allocate buffer: %s",
@@ -622,6 +630,7 @@
return NO_MEMORY;
}
+ size_t slot = status.get();
auto buffer_producer = queue_->GetBuffer(slot);
LOG_ALWAYS_FATAL_IF(buffer_producer == nullptr,
@@ -647,5 +656,31 @@
return NO_ERROR;
}
+status_t BufferHubQueueProducer::FreeAllBuffers() {
+ for (size_t slot = 0; slot < BufferHubQueue::kMaxQueueCapacity; slot++) {
+ // Reset in memory objects related the the buffer.
+ buffers_[slot].mGraphicBuffer = nullptr;
+ buffers_[slot].mBufferState.reset();
+ buffers_[slot].mRequestBufferCalled = false;
+ buffers_[slot].mBufferProducer = nullptr;
+ buffers_[slot].mFence = Fence::NO_FENCE;
+ }
+
+ auto status = queue_->FreeAllBuffers();
+ if (!status) {
+ ALOGE(
+ "BufferHubQueueProducer::FreeAllBuffers: Failed to free all buffers on "
+ "the queue: %s",
+ status.GetErrorMessage().c_str());
+ }
+
+ if (queue_->capacity() != 0 || queue_->count() != 0) {
+ LOG_ALWAYS_FATAL(
+ "BufferHubQueueProducer::FreeAllBuffers: Not all buffers are freed.");
+ }
+
+ return NO_ERROR;
+}
+
} // namespace dvr
} // namespace android
diff --git a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h
index 912cee0..6962d6c 100644
--- a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h
+++ b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h
@@ -5,12 +5,13 @@
#include <pdx/client.h>
#include <pdx/status.h>
-#include <private/dvr/bufferhub_rpc.h>
#include <private/dvr/buffer_hub_client.h>
+#include <private/dvr/bufferhub_rpc.h>
#include <private/dvr/epoll_file_descriptor.h>
#include <private/dvr/ring_buffer.h>
#include <memory>
+#include <queue>
#include <vector>
namespace android {
@@ -50,22 +51,30 @@
uint32_t default_format() const { return default_format_; }
// Creates a new consumer in handle form for immediate transport over RPC.
- pdx::Status<pdx::LocalChannelHandle> CreateConsumerQueueHandle();
+ pdx::Status<pdx::LocalChannelHandle> CreateConsumerQueueHandle(
+ bool silent = false);
// Returns the number of buffers avaiable for dequeue.
- size_t count() const { return available_buffers_.GetSize(); }
+ size_t count() const { return available_buffers_.size(); }
// Returns the total number of buffers that the queue is tracking.
size_t capacity() const { return capacity_; }
// Returns the size of metadata structure associated with this queue.
- size_t metadata_size() const { return meta_size_; }
+ size_t metadata_size() const { return user_metadata_size_; }
// Returns whether the buffer queue is full.
- bool is_full() const { return available_buffers_.IsFull(); }
+ bool is_full() const {
+ return available_buffers_.size() >= kMaxQueueCapacity;
+ }
explicit operator bool() const { return epoll_fd_.IsValid(); }
+ int GetBufferId(size_t slot) const {
+ return (slot < buffers_.size() && buffers_[slot]) ? buffers_[slot]->id()
+ : -1;
+ }
+
std::shared_ptr<BufferHubBuffer> GetBuffer(size_t slot) const {
return buffers_[slot];
}
@@ -122,13 +131,17 @@
// to deregister a buffer for epoll and internal bookkeeping.
virtual pdx::Status<void> RemoveBuffer(size_t slot);
+ // Free all buffers that belongs to this queue. Can only be called from
+ // producer side.
+ virtual pdx::Status<void> FreeAllBuffers();
+
// Dequeue a buffer from the free queue, blocking until one is available. The
// timeout argument specifies the number of milliseconds that |Dequeue()| will
// block. Specifying a timeout of -1 causes Dequeue() to block indefinitely,
// while specifying a timeout equal to zero cause Dequeue() to return
// immediately, even if no buffers are available.
- pdx::Status<std::shared_ptr<BufferHubBuffer>> Dequeue(
- int timeout, size_t* slot, void* meta, pdx::LocalHandle* fence);
+ pdx::Status<std::shared_ptr<BufferHubBuffer>> Dequeue(int timeout,
+ size_t* slot);
// Waits for buffers to become available and adds them to the available queue.
bool WaitForBuffers(int timeout);
@@ -141,8 +154,9 @@
// per-buffer data.
struct Entry {
Entry() : slot(0) {}
- Entry(const std::shared_ptr<BufferHubBuffer>& buffer, size_t slot)
- : buffer(buffer), slot(slot) {}
+ Entry(const std::shared_ptr<BufferHubBuffer>& buffer, size_t slot,
+ uint64_t index)
+ : buffer(buffer), slot(slot), index(index) {}
Entry(const std::shared_ptr<BufferHubBuffer>& buffer,
std::unique_ptr<uint8_t[]> metadata, pdx::LocalHandle fence,
size_t slot)
@@ -157,20 +171,24 @@
std::unique_ptr<uint8_t[]> metadata;
pdx::LocalHandle fence;
size_t slot;
+ uint64_t index;
+ };
+
+ struct EntryComparator {
+ bool operator()(const Entry& lhs, const Entry& rhs) {
+ return lhs.index > rhs.index;
+ }
};
// Enqueues a buffer to the available list (Gained for producer or Acquireed
// for consumer).
pdx::Status<void> Enqueue(Entry entry);
- virtual pdx::Status<Entry> OnBufferReady(
- const std::shared_ptr<BufferHubBuffer>& buf, size_t slot) = 0;
-
// Called when a buffer is allocated remotely.
virtual pdx::Status<void> OnBufferAllocated() { return {}; }
// Size of the metadata that buffers in this queue cary.
- size_t meta_size_{0};
+ size_t user_metadata_size_{0};
private:
void Initialize();
@@ -214,10 +232,12 @@
// Tracks the buffers belonging to this queue. Buffers are stored according to
// "slot" in this vector. Each slot is a logical id of the buffer within this
// queue regardless of its queue position or presence in the ring buffer.
- std::vector<std::shared_ptr<BufferHubBuffer>> buffers_{kMaxQueueCapacity};
+ std::array<std::shared_ptr<BufferHubBuffer>, kMaxQueueCapacity> buffers_;
// Buffers and related data that are available for dequeue.
- RingBuffer<Entry> available_buffers_{kMaxQueueCapacity};
+ // RingBuffer<Entry> available_buffers_{kMaxQueueCapacity};
+ std::priority_queue<Entry, std::vector<Entry>, EntryComparator>
+ available_buffers_;
// Keeps track with how many buffers have been added into the queue.
size_t capacity_{0};
@@ -274,12 +294,20 @@
BufferHubQueue::GetBuffer(slot));
}
+ // Batch allocate buffers. Once allocated, producer buffers are automatically
+ // enqueue'd into the ProducerQueue and available to use (i.e. in GAINED
+ // state). Upon success, returns a list of slots for each buffer allocated.
+ pdx::Status<std::vector<size_t>> AllocateBuffers(
+ uint32_t width, uint32_t height, uint32_t layer_count, uint32_t format,
+ uint64_t usage, size_t buffer_count);
+
// Allocate producer buffer to populate the queue. Once allocated, a producer
// buffer is automatically enqueue'd into the ProducerQueue and available to
- // use (i.e. in GAINED state).
- pdx::Status<void> AllocateBuffer(uint32_t width, uint32_t height,
- uint32_t layer_count, uint32_t format,
- uint64_t usage, size_t* out_slot);
+ // use (i.e. in GAINED state). Upon success, returns the slot number for the
+ // buffer allocated.
+ pdx::Status<size_t> AllocateBuffer(uint32_t width, uint32_t height,
+ uint32_t layer_count, uint32_t format,
+ uint64_t usage);
// Add a producer buffer to populate the queue. Once added, a producer buffer
// is available to use (i.e. in GAINED state).
@@ -289,16 +317,24 @@
// Remove producer buffer from the queue.
pdx::Status<void> RemoveBuffer(size_t slot) override;
+ // Free all buffers on this producer queue.
+ pdx::Status<void> FreeAllBuffers() override {
+ return BufferHubQueue::FreeAllBuffers();
+ }
+
// Dequeue a producer buffer to write. The returned buffer in |Gain|'ed mode,
// and caller should call Post() once it's done writing to release the buffer
// to the consumer side.
pdx::Status<std::shared_ptr<BufferProducer>> Dequeue(
int timeout, size_t* slot, pdx::LocalHandle* release_fence);
+ pdx::Status<std::shared_ptr<BufferProducer>> Dequeue(
+ int timeout, size_t* slot, DvrNativeBufferMetadata* out_meta,
+ pdx::LocalHandle* release_fence);
// Enqueues a producer buffer in the queue.
pdx::Status<void> Enqueue(const std::shared_ptr<BufferProducer>& buffer,
- size_t slot) {
- return BufferHubQueue::Enqueue({buffer, slot});
+ size_t slot, uint64_t index) {
+ return BufferHubQueue::Enqueue({buffer, slot, index});
}
private:
@@ -309,9 +345,6 @@
// arguments as the constructors.
explicit ProducerQueue(pdx::LocalChannelHandle handle);
ProducerQueue(const ProducerQueueConfig& config, const UsagePolicy& usage);
-
- pdx::Status<Entry> OnBufferReady(
- const std::shared_ptr<BufferHubBuffer>& buffer, size_t slot) override;
};
class ConsumerQueue : public BufferHubQueue {
@@ -330,10 +363,9 @@
// used to avoid participation in the buffer lifecycle by a consumer queue
// that is only used to spawn other consumer queues, such as in an
// intermediate service.
- static std::unique_ptr<ConsumerQueue> Import(pdx::LocalChannelHandle handle,
- bool ignore_on_import = false) {
+ static std::unique_ptr<ConsumerQueue> Import(pdx::LocalChannelHandle handle) {
return std::unique_ptr<ConsumerQueue>(
- new ConsumerQueue(std::move(handle), ignore_on_import));
+ new ConsumerQueue(std::move(handle)));
}
// Import newly created buffers from the service side.
@@ -357,13 +389,16 @@
}
pdx::Status<std::shared_ptr<BufferConsumer>> Dequeue(
- int timeout, size_t* slot, void* meta, size_t meta_size,
+ int timeout, size_t* slot, void* meta, size_t user_metadata_size,
+ pdx::LocalHandle* acquire_fence);
+ pdx::Status<std::shared_ptr<BufferConsumer>> Dequeue(
+ int timeout, size_t* slot, DvrNativeBufferMetadata* out_meta,
pdx::LocalHandle* acquire_fence);
private:
friend BufferHubQueue;
- ConsumerQueue(pdx::LocalChannelHandle handle, bool ignore_on_import = false);
+ ConsumerQueue(pdx::LocalChannelHandle handle);
// Add a consumer buffer to populate the queue. Once added, a consumer buffer
// is NOT available to use until the producer side |Post| it. |WaitForBuffers|
@@ -372,14 +407,7 @@
pdx::Status<void> AddBuffer(const std::shared_ptr<BufferConsumer>& buffer,
size_t slot);
- pdx::Status<Entry> OnBufferReady(
- const std::shared_ptr<BufferHubBuffer>& buffer, size_t slot) override;
-
pdx::Status<void> OnBufferAllocated() override;
-
- // Flag indicating that imported (consumer) buffers should be ignored when
- // imported to avoid participating in the buffer ownership flow.
- bool ignore_on_import_;
};
} // namespace dvr
diff --git a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_producer.h b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_producer.h
index 7890176..7ed55fb 100644
--- a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_producer.h
+++ b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_producer.h
@@ -42,7 +42,8 @@
// See |IGraphicBufferProducer::dequeueBuffer|
status_t dequeueBuffer(int* out_slot, sp<Fence>* out_fence, uint32_t width,
- uint32_t height, PixelFormat format, uint32_t usage,
+ uint32_t height, PixelFormat format, uint64_t usage,
+ uint64_t* outBufferAge,
FrameEventHistoryDelta* outTimestamps) override;
// See |IGraphicBufferProducer::detachBuffer|
@@ -80,7 +81,7 @@
// See |IGraphicBufferProducer::allocateBuffers|
void allocateBuffers(uint32_t width, uint32_t height, PixelFormat format,
- uint32_t usage) override;
+ uint64_t usage) override;
// See |IGraphicBufferProducer::allowAllocation|
status_t allowAllocation(bool allow) override;
@@ -111,6 +112,9 @@
// See |IGraphicBufferProducer::getUniqueId|
status_t getUniqueId(uint64_t* out_id) const override;
+ // See |IGraphicBufferProducer::getConsumerUsage|
+ status_t getConsumerUsage(uint64_t* out_usage) const override;
+
private:
using LocalHandle = pdx::LocalHandle;
@@ -131,6 +135,10 @@
// Remove a buffer via BufferHubRPC.
status_t RemoveBuffer(size_t slot);
+ // Free all buffers which are owned by the prodcuer. Note that if graphic
+ // buffers are acquired by the consumer, we can't .
+ status_t FreeAllBuffers();
+
// Concreate implementation backed by BufferHubBuffer.
std::shared_ptr<ProducerQueue> queue_;
diff --git a/libs/vr/libbufferhubqueue/tests/Android.bp b/libs/vr/libbufferhubqueue/tests/Android.bp
index 865573c..5e4df84 100644
--- a/libs/vr/libbufferhubqueue/tests/Android.bp
+++ b/libs/vr/libbufferhubqueue/tests/Android.bp
@@ -1,4 +1,7 @@
+header_libraries = [
+ "libdvr_headers",
+]
shared_libraries = [
"libbase",
@@ -9,6 +12,7 @@
"libhardware",
"libui",
"libutils",
+ "libnativewindow",
]
static_libraries = [
@@ -17,10 +21,12 @@
"libchrome",
"libdvrcommon",
"libpdx_default_transport",
+ "libperformance",
]
cc_test {
srcs: ["buffer_hub_queue-test.cpp"],
+ header_libs: header_libraries,
static_libs: static_libraries,
shared_libs: shared_libraries,
cflags: [
@@ -35,6 +41,7 @@
cc_test {
srcs: ["buffer_hub_queue_producer-test.cpp"],
+ header_libs: header_libraries,
static_libs: static_libraries,
shared_libs: shared_libraries,
cflags: [
@@ -46,3 +53,17 @@
name: "buffer_hub_queue_producer-test",
tags: ["optional"],
}
+
+cc_benchmark {
+ srcs: ["buffer_transport_benchmark.cpp"],
+ static_libs: static_libraries,
+ shared_libs: shared_libraries,
+ header_libs: header_libraries,
+ cflags: [
+ "-DLOG_TAG=\"buffer_transport_benchmark\"",
+ "-DTRACE=0",
+ "-O2",
+ ],
+ name: "buffer_transport_benchmark",
+ tags: ["optional"],
+}
diff --git a/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp b/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp
index 228212e..8a72531 100644
--- a/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp
+++ b/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp
@@ -3,6 +3,8 @@
#include <private/dvr/buffer_hub_queue_client.h>
#include <gtest/gtest.h>
+#include <poll.h>
+#include <sys/eventfd.h>
#include <vector>
@@ -46,16 +48,33 @@
void AllocateBuffer(size_t* slot_out = nullptr) {
// Create producer buffer.
- size_t slot;
- auto status = producer_queue_->AllocateBuffer(
- kBufferWidth, kBufferHeight, kBufferLayerCount, kBufferFormat,
- kBufferUsage, &slot);
- ASSERT_TRUE(status.ok());
+ auto status = producer_queue_->AllocateBuffer(kBufferWidth, kBufferHeight,
+ kBufferLayerCount,
+ kBufferFormat, kBufferUsage);
+ ASSERT_TRUE(status.ok());
+ size_t slot = status.take();
if (slot_out)
*slot_out = slot;
}
+ bool WaitAndHandleOnce(BufferHubQueue* queue, int timeout_ms) {
+ pollfd pfd{queue->queue_fd(), POLLIN, 0};
+ int ret;
+ do {
+ ret = poll(&pfd, 1, timeout_ms);
+ } while (ret == -1 && errno == EINTR);
+
+ if (ret < 0) {
+ ALOGW("Failed to poll queue %d's event fd, error: %s.", queue->id(),
+ strerror(errno));
+ return false;
+ } else if (ret == 0) {
+ return false;
+ }
+ return queue->HandleQueueEvents();
+ }
+
protected:
ProducerQueueConfigBuilder config_builder_;
std::unique_ptr<ProducerQueue> producer_queue_;
@@ -75,7 +94,7 @@
for (size_t i = 0; i < nb_dequeue_times; i++) {
size_t slot;
LocalHandle fence;
- auto p1_status = producer_queue_->Dequeue(0, &slot, &fence);
+ auto p1_status = producer_queue_->Dequeue(100, &slot, &fence);
ASSERT_TRUE(p1_status.ok());
auto p1 = p1_status.take();
ASSERT_NE(nullptr, p1);
@@ -113,31 +132,26 @@
// Dequeue returns timeout since no buffer is ready to consumer, but
// this implicitly triggers buffer import and bump up |capacity|.
LocalHandle fence;
- auto status = consumer_queue_->Dequeue(0, &slot, &seq, &fence);
+ auto status = consumer_queue_->Dequeue(100, &slot, &seq, &fence);
ASSERT_FALSE(status.ok());
ASSERT_EQ(ETIMEDOUT, status.error());
ASSERT_EQ(consumer_queue_->capacity(), i + 1);
}
- // Use /dev/zero as a stand-in for a fence. As long as BufferHub does not need
- // to merge fences, which only happens when multiple consumers release the
- // same buffer with release fences, the file object should simply pass
- // through.
- LocalHandle post_fence("/dev/zero", O_RDONLY);
- struct stat post_fence_stat;
- ASSERT_EQ(0, fstat(post_fence.Get(), &post_fence_stat));
+ // Use eventfd as a stand-in for a fence.
+ LocalHandle post_fence(eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK));
for (size_t i = 0; i < kBufferCount; i++) {
LocalHandle fence;
// First time there is no buffer available to dequeue.
- auto consumer_status = consumer_queue_->Dequeue(0, &slot, &seq, &fence);
+ auto consumer_status = consumer_queue_->Dequeue(100, &slot, &seq, &fence);
ASSERT_FALSE(consumer_status.ok());
ASSERT_EQ(ETIMEDOUT, consumer_status.error());
// Make sure Producer buffer is POSTED so that it's ready to Accquire
// in the consumer's Dequeue() function.
- auto producer_status = producer_queue_->Dequeue(0, &slot, &fence);
+ auto producer_status = producer_queue_->Dequeue(100, &slot, &fence);
ASSERT_TRUE(producer_status.ok());
auto producer = producer_status.take();
ASSERT_NE(nullptr, producer);
@@ -147,20 +161,10 @@
// Second time the just the POSTED buffer should be dequeued.
uint64_t seq_out = 0;
- consumer_status = consumer_queue_->Dequeue(0, &slot, &seq_out, &fence);
+ consumer_status = consumer_queue_->Dequeue(100, &slot, &seq_out, &fence);
ASSERT_TRUE(consumer_status.ok());
EXPECT_TRUE(fence.IsValid());
- struct stat acquire_fence_stat;
- ASSERT_EQ(0, fstat(fence.Get(), &acquire_fence_stat));
-
- // The file descriptors should refer to the same file object. Testing the
- // device id and inode is a proxy for testing that the fds refer to the same
- // file object.
- EXPECT_NE(post_fence.Get(), fence.Get());
- EXPECT_EQ(post_fence_stat.st_dev, acquire_fence_stat.st_dev);
- EXPECT_EQ(post_fence_stat.st_ino, acquire_fence_stat.st_ino);
-
auto consumer = consumer_status.take();
ASSERT_NE(nullptr, consumer);
ASSERT_EQ(seq_in, seq_out);
@@ -196,12 +200,11 @@
for (size_t i = 0; i < kBufferCount; i++) {
Entry* entry = &buffers[i];
- auto producer_status =
- producer_queue_->Dequeue(0, &entry->slot, &entry->fence);
+ auto producer_status = producer_queue_->Dequeue(
+ /*timeout_ms=*/100, &entry->slot, &entry->fence);
ASSERT_TRUE(producer_status.ok());
entry->buffer = producer_status.take();
ASSERT_NE(nullptr, entry->buffer);
- EXPECT_EQ(i, entry->slot);
}
// Remove a buffer and make sure both queues reflect the change.
@@ -218,8 +221,8 @@
buffers[0].buffer = nullptr;
// Now the consumer queue should know it's gone.
- EXPECT_FALSE(consumer_queue_->HandleQueueEvents());
- EXPECT_EQ(kBufferCount - 1, consumer_queue_->capacity());
+ EXPECT_FALSE(WaitAndHandleOnce(consumer_queue_.get(), /*timeout_ms=*/100));
+ ASSERT_EQ(kBufferCount - 1, consumer_queue_->capacity());
// Allocate a new buffer. This should take the first empty slot.
size_t slot;
@@ -286,17 +289,20 @@
auto silent_queue = producer_queue_->CreateSilentConsumerQueue();
ASSERT_NE(nullptr, silent_queue);
- // Check that buffers are correctly imported on construction.
- EXPECT_EQ(kBufferCount, silent_queue->capacity());
+ // Check that silent queue doesn't import buffers on creation.
+ EXPECT_EQ(0, silent_queue->capacity());
// Dequeue and post a buffer.
size_t slot;
LocalHandle fence;
- auto producer_status = producer_queue_->Dequeue(0, &slot, &fence);
+ auto producer_status =
+ producer_queue_->Dequeue(/*timeout_ms=*/100, &slot, &fence);
ASSERT_TRUE(producer_status.ok());
auto producer_buffer = producer_status.take();
ASSERT_NE(nullptr, producer_buffer);
ASSERT_EQ(0, producer_buffer->Post<void>({}));
+ // After post, check the number of remaining available buffers.
+ EXPECT_EQ(kBufferCount - 1, producer_queue_->count());
// Currently we expect no buffer to be available prior to calling
// WaitForBuffers/HandleQueueEvents.
@@ -314,23 +320,30 @@
EXPECT_EQ(1u, consumer_queue_->count());
// Reclaim released/ignored buffers.
- producer_queue_->HandleQueueEvents();
+ ASSERT_EQ(kBufferCount - 1, producer_queue_->count());
+
+ usleep(10000);
+ WaitAndHandleOnce(producer_queue_.get(), /*timeout_ms=*/100);
ASSERT_EQ(kBufferCount - 1, producer_queue_->count());
// Post another buffer.
- producer_status = producer_queue_->Dequeue(0, &slot, &fence);
+ producer_status = producer_queue_->Dequeue(/*timeout_ms=*/100, &slot, &fence);
ASSERT_TRUE(producer_status.ok());
producer_buffer = producer_status.take();
ASSERT_NE(nullptr, producer_buffer);
ASSERT_EQ(0, producer_buffer->Post<void>({}));
// Verify that the consumer queue receives it.
- EXPECT_EQ(1u, consumer_queue_->count());
- EXPECT_TRUE(consumer_queue_->HandleQueueEvents());
- EXPECT_EQ(2u, consumer_queue_->count());
+ size_t consumer_queue_count = consumer_queue_->count();
+ WaitAndHandleOnce(consumer_queue_.get(), /*timeout_ms=*/100);
+ EXPECT_LT(consumer_queue_count, consumer_queue_->count());
+
+ // Save the current consumer queue buffer count to compare after the dequeue.
+ consumer_queue_count = consumer_queue_->count();
// Dequeue and acquire/release (discard) buffers on the consumer end.
- auto consumer_status = consumer_queue_->Dequeue(0, &slot, &fence);
+ auto consumer_status =
+ consumer_queue_->Dequeue(/*timeout_ms=*/100, &slot, &fence);
ASSERT_TRUE(consumer_status.ok());
auto consumer_buffer = consumer_status.take();
ASSERT_NE(nullptr, consumer_buffer);
@@ -338,7 +351,7 @@
// Buffer should be returned to the producer queue without being handled by
// the silent consumer queue.
- EXPECT_EQ(1u, consumer_queue_->count());
+ EXPECT_GT(consumer_queue_count, consumer_queue_->count());
EXPECT_EQ(kBufferCount - 2, producer_queue_->count());
EXPECT_TRUE(producer_queue_->HandleQueueEvents());
EXPECT_EQ(kBufferCount - 1, producer_queue_->count());
@@ -362,13 +375,13 @@
for (auto mi : ms) {
size_t slot;
LocalHandle fence;
- auto p1_status = producer_queue_->Dequeue(0, &slot, &fence);
+ auto p1_status = producer_queue_->Dequeue(100, &slot, &fence);
ASSERT_TRUE(p1_status.ok());
auto p1 = p1_status.take();
ASSERT_NE(nullptr, p1);
ASSERT_EQ(p1->Post(LocalHandle(-1), &mi, sizeof(mi)), 0);
TestMetadata mo;
- auto c1_status = consumer_queue_->Dequeue(0, &slot, &mo, &fence);
+ auto c1_status = consumer_queue_->Dequeue(100, &slot, &mo, &fence);
ASSERT_TRUE(c1_status.ok());
auto c1 = c1_status.take();
ASSERT_EQ(mi.a, mo.a);
@@ -387,7 +400,7 @@
int64_t mi = 3;
size_t slot;
LocalHandle fence;
- auto p1_status = producer_queue_->Dequeue(0, &slot, &fence);
+ auto p1_status = producer_queue_->Dequeue(100, &slot, &fence);
ASSERT_TRUE(p1_status.ok());
auto p1 = p1_status.take();
ASSERT_NE(nullptr, p1);
@@ -395,7 +408,7 @@
int32_t mo;
// Acquire a buffer with mismatched metadata is not OK.
- auto c1_status = consumer_queue_->Dequeue(0, &slot, &mo, &fence);
+ auto c1_status = consumer_queue_->Dequeue(100, &slot, &mo, &fence);
ASSERT_FALSE(c1_status.ok());
}
@@ -406,14 +419,14 @@
size_t slot;
LocalHandle fence;
- auto p1_status = producer_queue_->Dequeue(0, &slot, &fence);
+ auto p1_status = producer_queue_->Dequeue(100, &slot, &fence);
ASSERT_TRUE(p1_status.ok());
auto p1 = p1_status.take();
ASSERT_NE(nullptr, p1);
int64_t mo;
- producer_queue_->Enqueue(p1, slot);
- auto c1_status = consumer_queue_->Dequeue(0, &slot, &mo, &fence);
+ producer_queue_->Enqueue(p1, slot, 0ULL);
+ auto c1_status = consumer_queue_->Dequeue(100, &slot, &mo, &fence);
ASSERT_FALSE(c1_status.ok());
}
@@ -424,14 +437,14 @@
size_t s1;
AllocateBuffer();
LocalHandle fence;
- auto p1_status = producer_queue_->Dequeue(0, &s1, &fence);
+ auto p1_status = producer_queue_->Dequeue(100, &s1, &fence);
ASSERT_TRUE(p1_status.ok());
auto p1 = p1_status.take();
ASSERT_NE(nullptr, p1);
// producer queue is exhausted
size_t s2;
- auto p2_status = producer_queue_->Dequeue(0, &s2, &fence);
+ auto p2_status = producer_queue_->Dequeue(100, &s2, &fence);
ASSERT_FALSE(p2_status.ok());
ASSERT_EQ(ETIMEDOUT, p2_status.error());
@@ -441,7 +454,7 @@
ASSERT_EQ(producer_queue_->capacity(), 2U);
// now we can dequeue again
- p2_status = producer_queue_->Dequeue(0, &s2, &fence);
+ p2_status = producer_queue_->Dequeue(100, &s2, &fence);
ASSERT_TRUE(p2_status.ok());
auto p2 = p2_status.take();
ASSERT_NE(nullptr, p2);
@@ -456,7 +469,7 @@
int64_t seq = 1;
ASSERT_EQ(p1->Post(LocalHandle(), seq), 0);
size_t cs1, cs2;
- auto c1_status = consumer_queue_->Dequeue(0, &cs1, &seq, &fence);
+ auto c1_status = consumer_queue_->Dequeue(100, &cs1, &seq, &fence);
ASSERT_TRUE(c1_status.ok());
auto c1 = c1_status.take();
ASSERT_NE(nullptr, c1);
@@ -465,7 +478,7 @@
ASSERT_EQ(cs1, s1);
ASSERT_EQ(p2->Post(LocalHandle(), seq), 0);
- auto c2_status = consumer_queue_->Dequeue(0, &cs2, &seq, &fence);
+ auto c2_status = consumer_queue_->Dequeue(100, &cs2, &seq, &fence);
ASSERT_TRUE(c2_status.ok());
auto c2 = c2_status.take();
ASSERT_NE(nullptr, c2);
@@ -478,14 +491,14 @@
UsagePolicy{set_mask, 0, 0, 0}));
// When allocation, leave out |set_mask| from usage bits on purpose.
- size_t slot;
auto status = producer_queue_->AllocateBuffer(
kBufferWidth, kBufferHeight, kBufferLayerCount, kBufferFormat,
- kBufferUsage & ~set_mask, &slot);
+ kBufferUsage & ~set_mask);
ASSERT_TRUE(status.ok());
LocalHandle fence;
- auto p1_status = producer_queue_->Dequeue(0, &slot, &fence);
+ size_t slot;
+ auto p1_status = producer_queue_->Dequeue(100, &slot, &fence);
ASSERT_TRUE(p1_status.ok());
auto p1 = p1_status.take();
ASSERT_EQ(p1->usage() & set_mask, set_mask);
@@ -497,14 +510,14 @@
UsagePolicy{0, clear_mask, 0, 0}));
// When allocation, add |clear_mask| into usage bits on purpose.
- size_t slot;
auto status = producer_queue_->AllocateBuffer(
kBufferWidth, kBufferHeight, kBufferLayerCount, kBufferFormat,
- kBufferUsage | clear_mask, &slot);
+ kBufferUsage | clear_mask);
ASSERT_TRUE(status.ok());
LocalHandle fence;
- auto p1_status = producer_queue_->Dequeue(0, &slot, &fence);
+ size_t slot;
+ auto p1_status = producer_queue_->Dequeue(100, &slot, &fence);
ASSERT_TRUE(p1_status.ok());
auto p1 = p1_status.take();
ASSERT_EQ(0u, p1->usage() & clear_mask);
@@ -517,16 +530,15 @@
// Now that |deny_set_mask| is illegal, allocation without those bits should
// be able to succeed.
- size_t slot;
auto status = producer_queue_->AllocateBuffer(
kBufferWidth, kBufferHeight, kBufferLayerCount, kBufferFormat,
- kBufferUsage & ~deny_set_mask, &slot);
+ kBufferUsage & ~deny_set_mask);
ASSERT_TRUE(status.ok());
// While allocation with those bits should fail.
status = producer_queue_->AllocateBuffer(kBufferWidth, kBufferHeight,
kBufferLayerCount, kBufferFormat,
- kBufferUsage | deny_set_mask, &slot);
+ kBufferUsage | deny_set_mask);
ASSERT_FALSE(status.ok());
ASSERT_EQ(EINVAL, status.error());
}
@@ -538,16 +550,15 @@
// Now that clearing |deny_clear_mask| is illegal (i.e. setting these bits are
// mandatory), allocation with those bits should be able to succeed.
- size_t slot;
auto status = producer_queue_->AllocateBuffer(
kBufferWidth, kBufferHeight, kBufferLayerCount, kBufferFormat,
- kBufferUsage | deny_clear_mask, &slot);
+ kBufferUsage | deny_clear_mask);
ASSERT_TRUE(status.ok());
// While allocation without those bits should fail.
- status = producer_queue_->AllocateBuffer(
- kBufferWidth, kBufferHeight, kBufferLayerCount, kBufferFormat,
- kBufferUsage & ~deny_clear_mask, &slot);
+ status = producer_queue_->AllocateBuffer(kBufferWidth, kBufferHeight,
+ kBufferLayerCount, kBufferFormat,
+ kBufferUsage & ~deny_clear_mask);
ASSERT_FALSE(status.ok());
ASSERT_EQ(EINVAL, status.error());
}
@@ -572,6 +583,103 @@
EXPECT_EQ(consumer_queue_->is_async(), kIsAsync);
}
+TEST_F(BufferHubQueueTest, TestFreeAllBuffers) {
+ constexpr size_t kBufferCount = 2;
+
+#define CHECK_NO_BUFFER_THEN_ALLOCATE(num_buffers) \
+ EXPECT_EQ(consumer_queue_->count(), 0U); \
+ EXPECT_EQ(consumer_queue_->capacity(), 0U); \
+ EXPECT_EQ(producer_queue_->count(), 0U); \
+ EXPECT_EQ(producer_queue_->capacity(), 0U); \
+ for (size_t i = 0; i < num_buffers; i++) { \
+ AllocateBuffer(); \
+ } \
+ EXPECT_EQ(producer_queue_->count(), num_buffers); \
+ EXPECT_EQ(producer_queue_->capacity(), num_buffers);
+
+ size_t slot;
+ uint64_t seq;
+ LocalHandle fence;
+ pdx::Status<void> status;
+ pdx::Status<std::shared_ptr<BufferConsumer>> consumer_status;
+ pdx::Status<std::shared_ptr<BufferProducer>> producer_status;
+ std::shared_ptr<BufferConsumer> consumer_buffer;
+ std::shared_ptr<BufferProducer> producer_buffer;
+
+ ASSERT_TRUE(CreateQueues(config_builder_.SetMetadata<uint64_t>().Build(),
+ UsagePolicy{}));
+
+ // Free all buffers when buffers are avaible for dequeue.
+ CHECK_NO_BUFFER_THEN_ALLOCATE(kBufferCount);
+ status = producer_queue_->FreeAllBuffers();
+ EXPECT_TRUE(status.ok());
+
+ // Free all buffers when one buffer is dequeued.
+ CHECK_NO_BUFFER_THEN_ALLOCATE(kBufferCount);
+ producer_status = producer_queue_->Dequeue(100, &slot, &fence);
+ ASSERT_TRUE(producer_status.ok());
+ status = producer_queue_->FreeAllBuffers();
+ EXPECT_TRUE(status.ok());
+
+ // Free all buffers when all buffers are dequeued.
+ CHECK_NO_BUFFER_THEN_ALLOCATE(kBufferCount);
+ for (size_t i = 0; i < kBufferCount; i++) {
+ producer_status = producer_queue_->Dequeue(100, &slot, &fence);
+ ASSERT_TRUE(producer_status.ok());
+ }
+ status = producer_queue_->FreeAllBuffers();
+ EXPECT_TRUE(status.ok());
+
+ // Free all buffers when one buffer is posted.
+ CHECK_NO_BUFFER_THEN_ALLOCATE(kBufferCount);
+ producer_status = producer_queue_->Dequeue(100, &slot, &fence);
+ ASSERT_TRUE(producer_status.ok());
+ producer_buffer = producer_status.take();
+ ASSERT_NE(nullptr, producer_buffer);
+ ASSERT_EQ(0, producer_buffer->Post(fence, &seq, sizeof(seq)));
+ status = producer_queue_->FreeAllBuffers();
+ EXPECT_TRUE(status.ok());
+
+ // Free all buffers when all buffers are posted.
+ CHECK_NO_BUFFER_THEN_ALLOCATE(kBufferCount);
+ for (size_t i = 0; i < kBufferCount; i++) {
+ producer_status = producer_queue_->Dequeue(100, &slot, &fence);
+ ASSERT_TRUE(producer_status.ok());
+ producer_buffer = producer_status.take();
+ ASSERT_NE(nullptr, producer_buffer);
+ ASSERT_EQ(0, producer_buffer->Post(fence, &seq, sizeof(seq)));
+ }
+ status = producer_queue_->FreeAllBuffers();
+ EXPECT_TRUE(status.ok());
+
+ // Free all buffers when all buffers are acquired.
+ CHECK_NO_BUFFER_THEN_ALLOCATE(kBufferCount);
+ for (size_t i = 0; i < kBufferCount; i++) {
+ producer_status = producer_queue_->Dequeue(100, &slot, &fence);
+ ASSERT_TRUE(producer_status.ok());
+ producer_buffer = producer_status.take();
+ ASSERT_NE(nullptr, producer_buffer);
+ ASSERT_EQ(0, producer_buffer->Post(fence, &seq, sizeof(seq)));
+ consumer_status = consumer_queue_->Dequeue(100, &slot, &seq, &fence);
+ ASSERT_TRUE(consumer_status.ok());
+ }
+
+ status = producer_queue_->FreeAllBuffers();
+ EXPECT_TRUE(status.ok());
+
+ // In addition to FreeAllBuffers() from the queue, it is also required to
+ // delete all references to the ProducerBuffer (i.e. the PDX client).
+ producer_buffer = nullptr;
+
+ // Crank consumer queue events to pickup EPOLLHUP events on the queue.
+ consumer_queue_->HandleQueueEvents();
+
+ // One last check.
+ CHECK_NO_BUFFER_THEN_ALLOCATE(kBufferCount);
+
+#undef CHECK_NO_BUFFER_THEN_ALLOCATE
+}
+
} // namespace
} // namespace dvr
diff --git a/libs/vr/libbufferhubqueue/tests/buffer_hub_queue_producer-test.cpp b/libs/vr/libbufferhubqueue/tests/buffer_hub_queue_producer-test.cpp
index c7692d0..28cd63a 100644
--- a/libs/vr/libbufferhubqueue/tests/buffer_hub_queue_producer-test.cpp
+++ b/libs/vr/libbufferhubqueue/tests/buffer_hub_queue_producer-test.cpp
@@ -117,9 +117,9 @@
ASSERT_NE(nullptr, outSlot);
ASSERT_NE(nullptr, outFence);
- int ret = mProducer->dequeueBuffer(outSlot, outFence, kDefaultWidth,
- kDefaultHeight, kDefaultFormat,
- kTestProducerUsageBits, nullptr);
+ int ret = mProducer->dequeueBuffer(
+ outSlot, outFence, kDefaultWidth, kDefaultHeight, kDefaultFormat,
+ kTestProducerUsageBits, nullptr, nullptr);
// BUFFER_NEEDS_REALLOCATION can be either on or off.
ASSERT_EQ(0, ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION & ret);
@@ -440,9 +440,10 @@
sp<Fence> fence;
for (int i = 0; i < 2; i++) {
ASSERT_EQ(OK, ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION &
- (mProducer->dequeueBuffer(
- &slot, &fence, kDefaultWidth, kDefaultHeight,
- kDefaultFormat, kTestProducerUsageBits, nullptr)))
+ (mProducer->dequeueBuffer(&slot, &fence, kDefaultWidth,
+ kDefaultHeight, kDefaultFormat,
+ kTestProducerUsageBits,
+ nullptr, nullptr)))
<< "slot: " << slot;
}
@@ -458,7 +459,8 @@
ASSERT_EQ(NO_INIT, mProducer->dequeueBuffer(&slot, &fence, kDefaultWidth,
kDefaultHeight, kDefaultFormat,
- kTestProducerUsageBits, nullptr));
+ kTestProducerUsageBits,
+ nullptr, nullptr));
}
TEST_F(BufferHubQueueProducerTest,
@@ -506,6 +508,44 @@
ASSERT_EQ(NO_INIT, mProducer->cancelBuffer(slot, Fence::NO_FENCE));
}
+TEST_F(BufferHubQueueProducerTest, ConnectDisconnectReconnect) {
+ int slot = -1;
+ sp<GraphicBuffer> buffer;
+ IGraphicBufferProducer::QueueBufferInput input = CreateBufferInput();
+ IGraphicBufferProducer::QueueBufferOutput output;
+
+ EXPECT_NO_FATAL_FAILURE(ConnectProducer());
+
+ constexpr int maxDequeuedBuffers = 1;
+ int minUndequeuedBuffers;
+ EXPECT_EQ(NO_ERROR, mProducer->query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
+ &minUndequeuedBuffers));
+ EXPECT_EQ(NO_ERROR, mProducer->setAsyncMode(false));
+ EXPECT_EQ(NO_ERROR, mProducer->setMaxDequeuedBufferCount(maxDequeuedBuffers));
+
+ int maxCapacity = maxDequeuedBuffers + minUndequeuedBuffers;
+
+ // Dequeue, request, and queue all buffers.
+ for (int i = 0; i < maxCapacity; i++) {
+ EXPECT_NO_FATAL_FAILURE(DequeueBuffer(&slot));
+ EXPECT_EQ(NO_ERROR, mProducer->requestBuffer(slot, &buffer));
+ EXPECT_EQ(NO_ERROR, mProducer->queueBuffer(slot, input, &output));
+ }
+
+ // Disconnect then reconnect.
+ EXPECT_EQ(NO_ERROR, mProducer->disconnect(kTestApi));
+ EXPECT_NO_FATAL_FAILURE(ConnectProducer());
+
+ // Dequeue, request, and queue all buffers.
+ for (int i = 0; i < maxCapacity; i++) {
+ EXPECT_NO_FATAL_FAILURE(DequeueBuffer(&slot));
+ EXPECT_EQ(NO_ERROR, mProducer->requestBuffer(slot, &buffer));
+ EXPECT_EQ(NO_ERROR, mProducer->queueBuffer(slot, input, &output));
+ }
+
+ EXPECT_EQ(NO_ERROR, mProducer->disconnect(kTestApi));
+}
+
} // namespace
} // namespace dvr
diff --git a/libs/vr/libbufferhubqueue/tests/buffer_transport_benchmark.cpp b/libs/vr/libbufferhubqueue/tests/buffer_transport_benchmark.cpp
new file mode 100644
index 0000000..658b496
--- /dev/null
+++ b/libs/vr/libbufferhubqueue/tests/buffer_transport_benchmark.cpp
@@ -0,0 +1,539 @@
+#include <android/native_window.h>
+#include <android-base/logging.h>
+#include <benchmark/benchmark.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <dvr/dvr_api.h>
+#include <dvr/performance_client_api.h>
+#include <gui/BufferItem.h>
+#include <gui/BufferItemConsumer.h>
+#include <gui/Surface.h>
+#include <private/dvr/buffer_hub_queue_producer.h>
+#include <utils/Trace.h>
+
+#include <chrono>
+#include <functional>
+#include <iostream>
+#include <thread>
+#include <vector>
+
+#include <poll.h>
+#include <sys/wait.h>
+
+// Use ALWAYS at the tag level. Control is performed manually during command
+// line processing.
+#ifdef ATRACE_TAG
+#undef ATRACE_TAG
+#endif
+#define ATRACE_TAG ATRACE_TAG_ALWAYS
+
+using namespace android;
+using namespace android::dvr;
+using ::benchmark::State;
+
+static const String16 kBinderService = String16("bufferTransport");
+static const uint32_t kBufferWidth = 100;
+static const uint32_t kBufferHeight = 1;
+static const uint32_t kBufferLayerCount = 1;
+static const uint32_t kBufferFormat = HAL_PIXEL_FORMAT_BLOB;
+static const uint64_t kBufferUsage =
+ GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN;
+static const int kMaxAcquiredImages = 1;
+static const int kQueueDepth = 2; // We are double buffering for this test.
+static const size_t kMaxQueueCounts = 128;
+
+enum BufferTransportServiceCode {
+ CREATE_BUFFER_QUEUE = IBinder::FIRST_CALL_TRANSACTION,
+};
+
+// A binder services that minics a compositor that consumes buffers. It provides
+// one Binder interface to create a new Surface for buffer producer to write
+// into; while itself will carry out no-op buffer consuming by acquiring then
+// releasing the buffer immediately.
+class BufferTransportService : public BBinder {
+ public:
+ BufferTransportService() = default;
+ ~BufferTransportService() = default;
+
+ virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+ uint32_t flags = 0) {
+ (void)flags;
+ (void)data;
+ switch (code) {
+ case CREATE_BUFFER_QUEUE: {
+ auto new_queue = std::make_shared<BufferQueueHolder>(this);
+ reply->writeStrongBinder(
+ IGraphicBufferProducer::asBinder(new_queue->producer_));
+ buffer_queues_.push_back(new_queue);
+ return NO_ERROR;
+ }
+ default:
+ return UNKNOWN_TRANSACTION;
+ };
+ }
+
+ private:
+ struct FrameListener : public ConsumerBase::FrameAvailableListener {
+ public:
+ FrameListener(BufferTransportService* service,
+ sp<BufferItemConsumer> buffer_item_consumer)
+ : service_(service),
+ buffer_item_consumer_(buffer_item_consumer) {}
+
+ void onFrameAvailable(const BufferItem& /*item*/) override {
+ BufferItem buffer;
+ status_t ret = 0;
+ {
+ ATRACE_NAME("AcquireBuffer");
+ ret = buffer_item_consumer_->acquireBuffer(&buffer, /*presentWhen=*/0,
+ /*waitForFence=*/false);
+ }
+
+ if (ret != NO_ERROR) {
+ LOG(ERROR) << "Failed to acquire next buffer.";
+ return;
+ }
+
+ {
+ ATRACE_NAME("ReleaseBuffer");
+ ret = buffer_item_consumer_->releaseBuffer(buffer);
+ }
+
+ if (ret != NO_ERROR) {
+ LOG(ERROR) << "Failed to release buffer.";
+ return;
+ }
+ }
+
+ private:
+ BufferTransportService* service_ = nullptr;
+ sp<BufferItemConsumer> buffer_item_consumer_;
+ };
+
+ struct BufferQueueHolder {
+ explicit BufferQueueHolder(BufferTransportService* service) {
+ BufferQueue::createBufferQueue(&producer_, &consumer_);
+
+ sp<BufferItemConsumer> buffer_item_consumer =
+ new BufferItemConsumer(consumer_, kBufferUsage, kMaxAcquiredImages,
+ /*controlledByApp=*/true);
+ buffer_item_consumer->setName(String8("BinderBufferTransport"));
+ frame_listener_ = new FrameListener(service, buffer_item_consumer);
+ buffer_item_consumer->setFrameAvailableListener(frame_listener_);
+ }
+
+ sp<IGraphicBufferProducer> producer_;
+ sp<IGraphicBufferConsumer> consumer_;
+ sp<FrameListener> frame_listener_;
+ };
+
+ std::vector<std::shared_ptr<BufferQueueHolder>> buffer_queues_;
+};
+
+// A virtual interfaces that abstracts the common BufferQueue operations, so
+// that the test suite can use the same test case to drive different types of
+// transport backends.
+class BufferTransport {
+ public:
+ virtual ~BufferTransport() {}
+
+ virtual int Start() = 0;
+ virtual sp<Surface> CreateSurface() = 0;
+};
+
+// Binder-based buffer transport backend.
+//
+// On Start() a new process will be swapned to run a Binder server that
+// actually consumes the buffer.
+// On CreateSurface() a new Binder BufferQueue will be created, which the
+// service holds the concrete binder node of the IGraphicBufferProducer while
+// sending the binder proxy to the client. In another word, the producer side
+// operations are carried out process while the consumer side operations are
+// carried out within the BufferTransportService's own process.
+class BinderBufferTransport : public BufferTransport {
+ public:
+ BinderBufferTransport() {}
+
+ int Start() override {
+ sp<IServiceManager> sm = defaultServiceManager();
+ service_ = sm->getService(kBinderService);
+ if (service_ == nullptr) {
+ LOG(ERROR) << "Failed to get the benchmark service.";
+ return -EIO;
+ }
+
+ LOG(INFO) << "Binder server is ready for client.";
+ return 0;
+ }
+
+ sp<Surface> CreateSurface() override {
+ Parcel data;
+ Parcel reply;
+ int error = service_->transact(CREATE_BUFFER_QUEUE, data, &reply);
+ if (error != NO_ERROR) {
+ LOG(ERROR) << "Failed to get buffer queue over binder.";
+ return nullptr;
+ }
+
+ sp<IBinder> binder;
+ error = reply.readNullableStrongBinder(&binder);
+ if (error != NO_ERROR) {
+ LOG(ERROR) << "Failed to get IGraphicBufferProducer over binder.";
+ return nullptr;
+ }
+
+ auto producer = interface_cast<IGraphicBufferProducer>(binder);
+ if (producer == nullptr) {
+ LOG(ERROR) << "Failed to get IGraphicBufferProducer over binder.";
+ return nullptr;
+ }
+
+ sp<Surface> surface = new Surface(producer, /*controlledByApp=*/true);
+
+ // Set buffer dimension.
+ ANativeWindow* window = static_cast<ANativeWindow*>(surface.get());
+ ANativeWindow_setBuffersGeometry(window, kBufferWidth, kBufferHeight,
+ kBufferFormat);
+
+ return surface;
+ }
+
+ private:
+ sp<IBinder> service_;
+};
+
+// BufferHub/PDX-based buffer transport.
+//
+// On Start() a new thread will be swapned to run an epoll polling thread which
+// minics the behavior of a compositor. Similar to Binder-based backend, the
+// buffer available handler is also a no-op: Buffer gets acquired and released
+// immediately.
+// On CreateSurface() a pair of dvr::ProducerQueue and dvr::ConsumerQueue will
+// be created. The epoll thread holds on the consumer queue and dequeues buffer
+// from it; while the producer queue will be wrapped in a Surface and returned
+// to test suite.
+class BufferHubTransport : public BufferTransport {
+ public:
+ virtual ~BufferHubTransport() {
+ stopped_.store(true);
+ if (reader_thread_.joinable()) {
+ reader_thread_.join();
+ }
+ }
+
+ int Start() override {
+ int ret = epoll_fd_.Create();
+ if (ret < 0) {
+ LOG(ERROR) << "Failed to create epoll fd: %s", strerror(-ret);
+ return -1;
+ }
+
+ // Create the reader thread.
+ reader_thread_ = std::thread([this]() {
+ int ret = dvrSetSchedulerClass(0, "graphics");
+ if (ret < 0) {
+ LOG(ERROR) << "Failed to set thread priority";
+ return;
+ }
+
+
+ ret = dvrSetCpuPartition(0, "/system/performance");
+ if (ret < 0) {
+ LOG(ERROR) << "Failed to set thread cpu partition";
+ return;
+ }
+
+ stopped_.store(false);
+ LOG(INFO) << "Reader Thread Running...";
+
+ while (!stopped_.load()) {
+ std::array<epoll_event, kMaxQueueCounts> events;
+
+ // Don't sleep forever so that we will have a chance to wake up.
+ const int ret = epoll_fd_.Wait(events.data(), events.size(),
+ /*timeout=*/100);
+ if (ret < 0) {
+ LOG(ERROR) << "Error polling consumer queues.";
+ continue;
+ }
+ if (ret == 0) {
+ continue;
+ }
+
+ const int num_events = ret;
+ for (int i = 0; i < num_events; i++) {
+ uint32_t surface_index = events[i].data.u32;
+ buffer_queues_[surface_index]->consumer_queue_->HandleQueueEvents();
+ }
+ }
+
+ LOG(INFO) << "Reader Thread Exiting...";
+ });
+
+ return 0;
+ }
+
+ sp<Surface> CreateSurface() override {
+ auto new_queue = std::make_shared<BufferQueueHolder>();
+ if (new_queue->producer_ == nullptr) {
+ LOG(ERROR) << "Failed to create buffer producer.";
+ return nullptr;
+ }
+
+ sp<Surface> surface =
+ new Surface(new_queue->producer_, /*controlledByApp=*/true);
+
+ // Set buffer dimension.
+ ANativeWindow* window = static_cast<ANativeWindow*>(surface.get());
+ ANativeWindow_setBuffersGeometry(window, kBufferWidth, kBufferHeight,
+ kBufferFormat);
+
+ // Use the next position as buffer_queue index.
+ uint32_t index = buffer_queues_.size();
+ epoll_event event = {.events = EPOLLIN | EPOLLET, .data = {.u32 = index}};
+ const int ret = epoll_fd_.Control(
+ EPOLL_CTL_ADD, new_queue->consumer_queue_->queue_fd(), &event);
+ if (ret < 0) {
+ LOG(ERROR) << "Failed to track consumer queue: " << strerror(-ret)
+ << ", consumer queue fd: "
+ << new_queue->consumer_queue_->queue_fd();
+ return nullptr;
+ }
+
+ new_queue->queue_index_ = index;
+ buffer_queues_.push_back(new_queue);
+ return surface;
+ }
+
+ private:
+ struct BufferQueueHolder {
+ BufferQueueHolder() {
+ ProducerQueueConfigBuilder config_builder;
+ producer_queue_ =
+ ProducerQueue::Create(config_builder.SetDefaultWidth(kBufferWidth)
+ .SetDefaultHeight(kBufferHeight)
+ .SetDefaultFormat(kBufferFormat)
+ .SetMetadata<DvrNativeBufferMetadata>()
+ .Build(),
+ UsagePolicy{});
+ consumer_queue_ = producer_queue_->CreateConsumerQueue();
+ consumer_queue_->SetBufferAvailableCallback([this]() {
+ size_t index = 0;
+ pdx::LocalHandle fence;
+ DvrNativeBufferMetadata meta;
+ pdx::Status<std::shared_ptr<BufferConsumer>> status;
+
+ {
+ ATRACE_NAME("AcquireBuffer");
+ status = consumer_queue_->Dequeue(0, &index, &meta, &fence);
+ }
+ if (!status.ok()) {
+ LOG(ERROR) << "Failed to dequeue consumer buffer, error: "
+ << status.GetErrorMessage().c_str();
+ return;
+ }
+
+ auto buffer = status.take();
+
+ if (buffer) {
+ ATRACE_NAME("ReleaseBuffer");
+ buffer->ReleaseAsync();
+ }
+ });
+
+ producer_ = BufferHubQueueProducer::Create(producer_queue_);
+ }
+
+ int count_ = 0;
+ int queue_index_;
+ std::shared_ptr<ProducerQueue> producer_queue_;
+ std::shared_ptr<ConsumerQueue> consumer_queue_;
+ sp<IGraphicBufferProducer> producer_;
+ };
+
+ std::atomic<bool> stopped_;
+ std::thread reader_thread_;
+
+ EpollFileDescriptor epoll_fd_;
+ std::vector<std::shared_ptr<BufferQueueHolder>> buffer_queues_;
+};
+
+enum TransportType {
+ kBinderBufferTransport,
+ kBufferHubTransport,
+};
+
+// Main test suite, which supports two transport backend: 1) BinderBufferQueue,
+// 2) BufferHubQueue. The test case drives the producer end of both transport
+// backend by queuing buffers into the buffer queue by using ANativeWindow API.
+class BufferTransportBenchmark : public ::benchmark::Fixture {
+ public:
+ void SetUp(State& state) override {
+ if (state.thread_index == 0) {
+ const int transport = state.range(0);
+ switch (transport) {
+ case kBinderBufferTransport:
+ transport_.reset(new BinderBufferTransport);
+ break;
+ case kBufferHubTransport:
+ transport_.reset(new BufferHubTransport);
+ break;
+ default:
+ CHECK(false) << "Unknown test case.";
+ break;
+ }
+
+ CHECK(transport_);
+ const int ret = transport_->Start();
+ CHECK_EQ(ret, 0);
+
+ LOG(INFO) << "Transport backend running, transport=" << transport << ".";
+
+ // Create surfaces for each thread.
+ surfaces_.resize(state.threads);
+ for (int i = 0; i < state.threads; i++) {
+ // Common setup every thread needs.
+ surfaces_[i] = transport_->CreateSurface();
+ CHECK(surfaces_[i]);
+
+ LOG(INFO) << "Surface initialized on thread " << i << ".";
+ }
+ }
+ }
+
+ void TearDown(State& state) override {
+ if (state.thread_index == 0) {
+ surfaces_.clear();
+ transport_.reset();
+ LOG(INFO) << "Tear down benchmark.";
+ }
+ }
+
+ protected:
+ std::unique_ptr<BufferTransport> transport_;
+ std::vector<sp<Surface>> surfaces_;
+};
+
+BENCHMARK_DEFINE_F(BufferTransportBenchmark, Producers)(State& state) {
+ ANativeWindow* window = nullptr;
+ ANativeWindow_Buffer buffer;
+ int32_t error = 0;
+ double total_gain_buffer_us = 0;
+ double total_post_buffer_us = 0;
+ int iterations = 0;
+
+ while (state.KeepRunning()) {
+ if (window == nullptr) {
+ CHECK(surfaces_[state.thread_index]);
+ window = static_cast<ANativeWindow*>(surfaces_[state.thread_index].get());
+
+ // Lock buffers a couple time from the queue, so that we have the buffer
+ // allocated.
+ for (int i = 0; i < kQueueDepth; i++) {
+ error = ANativeWindow_lock(window, &buffer,
+ /*inOutDirtyBounds=*/nullptr);
+ CHECK_EQ(error, 0);
+ error = ANativeWindow_unlockAndPost(window);
+ CHECK_EQ(error, 0);
+ }
+ }
+
+ {
+ ATRACE_NAME("GainBuffer");
+ auto t1 = std::chrono::high_resolution_clock::now();
+ error = ANativeWindow_lock(window, &buffer,
+ /*inOutDirtyBounds=*/nullptr);
+ auto t2 = std::chrono::high_resolution_clock::now();
+ std::chrono::duration<double, std::micro> delta_us = t2 - t1;
+ total_gain_buffer_us += delta_us.count();
+ }
+ CHECK_EQ(error, 0);
+
+ {
+ ATRACE_NAME("PostBuffer");
+ auto t1 = std::chrono::high_resolution_clock::now();
+ error = ANativeWindow_unlockAndPost(window);
+ auto t2 = std::chrono::high_resolution_clock::now();
+ std::chrono::duration<double, std::micro> delta_us = t2 - t1;
+ total_post_buffer_us += delta_us.count();
+ }
+ CHECK_EQ(error, 0);
+
+ iterations++;
+ }
+
+ state.counters["gain_buffer_us"] = ::benchmark::Counter(
+ total_gain_buffer_us / iterations, ::benchmark::Counter::kAvgThreads);
+ state.counters["post_buffer_us"] = ::benchmark::Counter(
+ total_post_buffer_us / iterations, ::benchmark::Counter::kAvgThreads);
+ state.counters["producer_us"] = ::benchmark::Counter(
+ (total_gain_buffer_us + total_post_buffer_us) / iterations,
+ ::benchmark::Counter::kAvgThreads);
+}
+
+BENCHMARK_REGISTER_F(BufferTransportBenchmark, Producers)
+ ->Unit(::benchmark::kMicrosecond)
+ ->Ranges({{kBinderBufferTransport, kBufferHubTransport}})
+ ->ThreadRange(1, 32);
+
+static void runBinderServer() {
+ ProcessState::self()->setThreadPoolMaxThreadCount(0);
+ ProcessState::self()->startThreadPool();
+
+ sp<IServiceManager> sm = defaultServiceManager();
+ sp<BufferTransportService> service = new BufferTransportService;
+ sm->addService(kBinderService, service, false);
+
+ LOG(INFO) << "Binder server running...";
+
+ while (true) {
+ int stat, retval;
+ retval = wait(&stat);
+ if (retval == -1 && errno == ECHILD) {
+ break;
+ }
+ }
+
+ LOG(INFO) << "Service Exiting...";
+}
+
+// To run binder-based benchmark, use:
+// adb shell buffer_transport_benchmark \
+// --benchmark_filter="BufferTransportBenchmark/ContinuousLoad/0/"
+//
+// To run bufferhub-based benchmark, use:
+// adb shell buffer_transport_benchmark \
+// --benchmark_filter="BufferTransportBenchmark/ContinuousLoad/1/"
+int main(int argc, char** argv) {
+ bool tracing_enabled = false;
+
+ // Parse arguments in addition to "--benchmark_filter" paramters.
+ for (int i = 1; i < argc; i++) {
+ if (std::string(argv[i]) == "--help") {
+ std::cout << "Usage: binderThroughputTest [OPTIONS]" << std::endl;
+ std::cout << "\t--trace: Enable systrace logging."
+ << std::endl;
+ return 0;
+ }
+ if (std::string(argv[i]) == "--trace") {
+ tracing_enabled = true;
+ continue;
+ }
+ }
+
+ // Setup ATRACE/systrace based on command line.
+ atrace_setup();
+ atrace_set_tracing_enabled(tracing_enabled);
+
+ pid_t pid = fork();
+ if (pid == 0) {
+ // parent, i.e. the client side.
+ ProcessState::self()->startThreadPool();
+
+ ::benchmark::Initialize(&argc, argv);
+ ::benchmark::RunSpecifiedBenchmarks();
+ } else {
+ LOG(INFO) << "Benchmark process pid: " << pid;
+ runBinderServer();
+ }
+}
diff --git a/libs/vr/libdisplay/display_client.cpp b/libs/vr/libdisplay/display_client.cpp
index 2db82ed..442c82d 100644
--- a/libs/vr/libdisplay/display_client.cpp
+++ b/libs/vr/libdisplay/display_client.cpp
@@ -104,15 +104,15 @@
return {};
}
-Status<std::unique_ptr<ProducerQueue>> Surface::CreateQueue(uint32_t width,
- uint32_t height,
- uint32_t format) {
+Status<std::unique_ptr<ProducerQueue>> Surface::CreateQueue(
+ uint32_t width, uint32_t height, uint32_t format, size_t metadata_size) {
ALOGD_IF(TRACE, "Surface::CreateQueue: Creating empty queue.");
auto status = InvokeRemoteMethod<DisplayProtocol::CreateQueue>(
ProducerQueueConfigBuilder()
.SetDefaultWidth(width)
.SetDefaultHeight(height)
.SetDefaultFormat(format)
+ .SetMetadataSize(metadata_size)
.Build());
if (!status) {
ALOGE("Surface::CreateQueue: Failed to create queue: %s",
@@ -131,32 +131,24 @@
Status<std::unique_ptr<ProducerQueue>> Surface::CreateQueue(
uint32_t width, uint32_t height, uint32_t layer_count, uint32_t format,
- uint64_t usage, size_t capacity) {
+ uint64_t usage, size_t capacity, size_t metadata_size) {
ALOGD_IF(TRACE,
"Surface::CreateQueue: width=%u height=%u layer_count=%u format=%u "
"usage=%" PRIx64 " capacity=%zu",
width, height, layer_count, format, usage, capacity);
- auto status = CreateQueue(width, height, format);
+ auto status = CreateQueue(width, height, format, metadata_size);
if (!status)
return status.error_status();
auto producer_queue = status.take();
ALOGD_IF(TRACE, "Surface::CreateQueue: Allocating %zu buffers...", capacity);
- for (size_t i = 0; i < capacity; i++) {
- size_t slot;
- auto allocate_status = producer_queue->AllocateBuffer(
- width, height, layer_count, format, usage, &slot);
- if (!allocate_status) {
- ALOGE(
- "Surface::CreateQueue: Failed to allocate buffer on queue_id=%d: %s",
+ auto allocate_status = producer_queue->AllocateBuffers(
+ width, height, layer_count, format, usage, capacity);
+ if (!allocate_status) {
+ ALOGE("Surface::CreateQueue: Failed to allocate buffer on queue_id=%d: %s",
producer_queue->id(), allocate_status.GetErrorMessage().c_str());
- return allocate_status.error_status();
- }
- ALOGD_IF(
- TRACE,
- "Surface::CreateQueue: Allocated buffer at slot=%zu of capacity=%zu",
- slot, capacity);
+ return allocate_status.error_status();
}
return {std::move(producer_queue)};
@@ -196,6 +188,42 @@
return ErrorStatus(error);
}
+pdx::Status<std::unique_ptr<IonBuffer>> DisplayClient::SetupGlobalBuffer(
+ DvrGlobalBufferKey key, size_t size, uint64_t usage) {
+ auto status =
+ InvokeRemoteMethod<DisplayProtocol::SetupGlobalBuffer>(key, size, usage);
+ if (!status) {
+ ALOGE(
+ "DisplayClient::SetupGlobalBuffer: Failed to create the global buffer "
+ "%s",
+ status.GetErrorMessage().c_str());
+ return status.error_status();
+ }
+
+ auto ion_buffer = std::make_unique<IonBuffer>();
+ auto native_buffer_handle = status.take();
+ const int ret = native_buffer_handle.Import(ion_buffer.get());
+ if (ret < 0) {
+ ALOGE(
+ "DisplayClient::GetGlobalBuffer: Failed to import global buffer: "
+ "key=%d; error=%s",
+ key, strerror(-ret));
+ return ErrorStatus(-ret);
+ }
+
+ return {std::move(ion_buffer)};
+}
+
+pdx::Status<void> DisplayClient::DeleteGlobalBuffer(DvrGlobalBufferKey key) {
+ auto status = InvokeRemoteMethod<DisplayProtocol::DeleteGlobalBuffer>(key);
+ if (!status) {
+ ALOGE("DisplayClient::DeleteGlobalBuffer Failed: %s",
+ status.GetErrorMessage().c_str());
+ }
+
+ return status;
+}
+
Status<std::unique_ptr<IonBuffer>> DisplayClient::GetGlobalBuffer(
DvrGlobalBufferKey key) {
auto status = InvokeRemoteMethod<DisplayProtocol::GetGlobalBuffer>(key);
diff --git a/libs/vr/libdisplay/display_manager_client.cpp b/libs/vr/libdisplay/display_manager_client.cpp
index 098b725..974c231 100644
--- a/libs/vr/libdisplay/display_manager_client.cpp
+++ b/libs/vr/libdisplay/display_manager_client.cpp
@@ -32,44 +32,6 @@
return status;
}
-pdx::Status<std::unique_ptr<IonBuffer>> DisplayManagerClient::SetupGlobalBuffer(
- DvrGlobalBufferKey key, size_t size, uint64_t usage) {
- auto status = InvokeRemoteMethod<DisplayManagerProtocol::SetupGlobalBuffer>(
- key, size, usage);
- if (!status) {
- ALOGE(
- "DisplayManagerClient::SetupGlobalBuffer: Failed to create the global "
- "buffer %s",
- status.GetErrorMessage().c_str());
- return status.error_status();
- }
-
- auto ion_buffer = std::make_unique<IonBuffer>();
- auto native_buffer_handle = status.take();
- const int ret = native_buffer_handle.Import(ion_buffer.get());
- if (ret < 0) {
- ALOGE(
- "DisplayManagerClient::GetGlobalBuffer: Failed to import global "
- "buffer: key=%d; error=%s",
- key, strerror(-ret));
- return ErrorStatus(-ret);
- }
-
- return {std::move(ion_buffer)};
-}
-
-pdx::Status<void> DisplayManagerClient::DeleteGlobalBuffer(
- DvrGlobalBufferKey key) {
- auto status =
- InvokeRemoteMethod<DisplayManagerProtocol::DeleteGlobalBuffer>(key);
- if (!status) {
- ALOGE("DisplayManagerClient::DeleteGlobalBuffer Failed: %s",
- status.GetErrorMessage().c_str());
- }
-
- return status;
-}
-
pdx::Status<std::unique_ptr<ConsumerQueue>>
DisplayManagerClient::GetSurfaceQueue(int surface_id, int queue_id) {
auto status = InvokeRemoteMethod<DisplayManagerProtocol::GetSurfaceQueue>(
diff --git a/libs/vr/libdisplay/include/private/dvr/display_client.h b/libs/vr/libdisplay/include/private/dvr/display_client.h
index f66c702..caf3182 100644
--- a/libs/vr/libdisplay/include/private/dvr/display_client.h
+++ b/libs/vr/libdisplay/include/private/dvr/display_client.h
@@ -39,7 +39,8 @@
// Creates an empty queue.
pdx::Status<std::unique_ptr<ProducerQueue>> CreateQueue(uint32_t width,
uint32_t height,
- uint32_t format);
+ uint32_t format,
+ size_t metadata_size);
// Creates a queue and populates it with |capacity| buffers of the specified
// parameters.
@@ -48,7 +49,8 @@
uint32_t layer_count,
uint32_t format,
uint64_t usage,
- size_t capacity);
+ size_t capacity,
+ size_t metadata_size);
private:
friend BASE;
@@ -71,6 +73,9 @@
public:
pdx::Status<Metrics> GetDisplayMetrics();
pdx::Status<std::string> GetConfigurationData(ConfigFileType config_type);
+ pdx::Status<std::unique_ptr<IonBuffer>> SetupGlobalBuffer(
+ DvrGlobalBufferKey key, size_t size, uint64_t usage);
+ pdx::Status<void> DeleteGlobalBuffer(DvrGlobalBufferKey key);
pdx::Status<std::unique_ptr<IonBuffer>> GetGlobalBuffer(
DvrGlobalBufferKey key);
pdx::Status<std::unique_ptr<Surface>> CreateSurface(
diff --git a/libs/vr/libdisplay/include/private/dvr/display_manager_client.h b/libs/vr/libdisplay/include/private/dvr/display_manager_client.h
index 7281b76..45aef51 100644
--- a/libs/vr/libdisplay/include/private/dvr/display_manager_client.h
+++ b/libs/vr/libdisplay/include/private/dvr/display_manager_client.h
@@ -21,9 +21,6 @@
~DisplayManagerClient() override;
pdx::Status<std::vector<SurfaceState>> GetSurfaceState();
- pdx::Status<std::unique_ptr<IonBuffer>> SetupGlobalBuffer(
- DvrGlobalBufferKey key, size_t size, uint64_t usage);
- pdx::Status<void> DeleteGlobalBuffer(DvrGlobalBufferKey key);
pdx::Status<std::unique_ptr<ConsumerQueue>> GetSurfaceQueue(int surface_id,
int queue_id);
diff --git a/libs/vr/libdisplay/include/private/dvr/display_protocol.h b/libs/vr/libdisplay/include/private/dvr/display_protocol.h
index 5b23632..eff50ba 100644
--- a/libs/vr/libdisplay/include/private/dvr/display_protocol.h
+++ b/libs/vr/libdisplay/include/private/dvr/display_protocol.h
@@ -200,6 +200,8 @@
enum {
kOpGetMetrics = 0,
kOpGetConfigurationData,
+ kOpSetupGlobalBuffer,
+ kOpDeleteGlobalBuffer,
kOpGetGlobalBuffer,
kOpIsVrAppRunning,
kOpCreateSurface,
@@ -216,6 +218,11 @@
PDX_REMOTE_METHOD(GetMetrics, kOpGetMetrics, Metrics(Void));
PDX_REMOTE_METHOD(GetConfigurationData, kOpGetConfigurationData,
std::string(ConfigFileType config_type));
+ PDX_REMOTE_METHOD(SetupGlobalBuffer, kOpSetupGlobalBuffer,
+ LocalNativeBufferHandle(DvrGlobalBufferKey key, size_t size,
+ uint64_t usage));
+ PDX_REMOTE_METHOD(DeleteGlobalBuffer, kOpDeleteGlobalBuffer,
+ void(DvrGlobalBufferKey key));
PDX_REMOTE_METHOD(GetGlobalBuffer, kOpGetGlobalBuffer,
LocalNativeBufferHandle(DvrGlobalBufferKey key));
PDX_REMOTE_METHOD(IsVrAppRunning, kOpIsVrAppRunning, bool(Void));
@@ -237,8 +244,6 @@
enum {
kOpGetSurfaceState = 0,
kOpGetSurfaceQueue,
- kOpSetupGlobalBuffer,
- kOpDeleteGlobalBuffer,
};
// Aliases.
@@ -250,11 +255,6 @@
std::vector<SurfaceState>(Void));
PDX_REMOTE_METHOD(GetSurfaceQueue, kOpGetSurfaceQueue,
LocalChannelHandle(int surface_id, int queue_id));
- PDX_REMOTE_METHOD(SetupGlobalBuffer, kOpSetupGlobalBuffer,
- LocalNativeBufferHandle(DvrGlobalBufferKey key, size_t size,
- uint64_t usage));
- PDX_REMOTE_METHOD(DeleteGlobalBuffer, kOpDeleteGlobalBuffer,
- void(DvrGlobalBufferKey key));
};
struct VSyncSchedInfo {
diff --git a/libs/vr/libdisplay/include/private/dvr/shared_buffer_helpers.h b/libs/vr/libdisplay/include/private/dvr/shared_buffer_helpers.h
index ed06515..20541a6 100644
--- a/libs/vr/libdisplay/include/private/dvr/shared_buffer_helpers.h
+++ b/libs/vr/libdisplay/include/private/dvr/shared_buffer_helpers.h
@@ -103,9 +103,14 @@
// Try obtaining the ring. If the named buffer has not been created yet, it
// will return nullptr.
RingType* Ring() {
- if (IsMapped() == false) {
- TryMapping();
+ // No ring created yet?
+ if (ring_ == nullptr) {
+ // Not mapped the memory yet?
+ if (IsMapped() == false) {
+ TryMapping();
+ }
+ // If have the memory mapped, allocate the ring.
if (IsMapped()) {
switch (usage_mode_) {
case CPUUsageMode::READ_OFTEN:
diff --git a/libs/vr/libdvr/Android.bp b/libs/vr/libdvr/Android.bp
index 4041d6b..9fe161d 100644
--- a/libs/vr/libdvr/Android.bp
+++ b/libs/vr/libdvr/Android.bp
@@ -31,6 +31,8 @@
"dvr_configuration_data.cpp",
"dvr_display_manager.cpp",
"dvr_hardware_composer_client.cpp",
+ "dvr_performance.cpp",
+ "dvr_pose.cpp",
"dvr_surface.cpp",
"dvr_vsync.cpp",
]
@@ -45,6 +47,7 @@
"libvr_hwc-impl",
"libvr_hwc-binder",
"libgrallocusage",
+ "libperformance",
"libpdx_default_transport",
]
diff --git a/libs/vr/libdvr/dvr_api.cpp b/libs/vr/libdvr/dvr_api.cpp
index 5f35dcf..7d4e2d1 100644
--- a/libs/vr/libdvr/dvr_api.cpp
+++ b/libs/vr/libdvr/dvr_api.cpp
@@ -3,11 +3,14 @@
#include <errno.h>
#include <utils/Log.h>
+#include <algorithm>
+
// Headers from libdvr
#include <dvr/dvr_buffer.h>
#include <dvr/dvr_buffer_queue.h>
#include <dvr/dvr_configuration_data.h>
#include <dvr/dvr_display_manager.h>
+#include <dvr/dvr_performance.h>
#include <dvr/dvr_surface.h>
#include <dvr/dvr_vsync.h>
@@ -23,15 +26,20 @@
ALOGI("dvrGetApi: api=%p struct_size=%zu version=%d", api, struct_size,
version);
if (version == 1) {
- if (struct_size != sizeof(DvrApi_v1)) {
- ALOGE("dvrGetApi: Size mismatch: expected %zu; actual %zu",
- sizeof(DvrApi_v1), struct_size);
- return -EINVAL;
- }
+ // New entry points are added at the end. If the caller's struct and
+ // this library have different sizes, we define the entry points in common.
+ // The caller is expected to handle unset entry points if necessary.
+ size_t clamped_struct_size = std::min(struct_size, sizeof(DvrApi_v1));
DvrApi_v1* dvr_api = static_cast<DvrApi_v1*>(api);
// Defines an API entry for V1 (no version suffix).
-#define DVR_V1_API_ENTRY(name) dvr_api->name = dvr##name
+#define DVR_V1_API_ENTRY(name) \
+ do { \
+ if ((offsetof(DvrApi_v1, name) + sizeof(dvr_api->name)) <= \
+ clamped_struct_size) { \
+ dvr_api->name = dvr##name; \
+ } \
+ } while (0)
#include "include/dvr/dvr_api_entries.h"
diff --git a/libs/vr/libdvr/dvr_buffer.cpp b/libs/vr/libdvr/dvr_buffer.cpp
index 82469b8..1a99234 100644
--- a/libs/vr/libdvr/dvr_buffer.cpp
+++ b/libs/vr/libdvr/dvr_buffer.cpp
@@ -1,6 +1,7 @@
#include "include/dvr/dvr_buffer.h"
#include <android/hardware_buffer.h>
+#include <dvr/dvr_shared_buffers.h>
#include <private/dvr/buffer_hub_client.h>
#include <ui/GraphicBuffer.h>
@@ -43,7 +44,13 @@
}
void dvrWriteBufferDestroy(DvrWriteBuffer* write_buffer) {
- delete write_buffer;
+ if (write_buffer != nullptr) {
+ ALOGW_IF(
+ write_buffer->slot != -1,
+ "dvrWriteBufferDestroy: Destroying a buffer associated with a valid "
+ "buffer queue slot. This may indicate possible leaks.");
+ delete write_buffer;
+ }
}
int dvrWriteBufferIsValid(DvrWriteBuffer* write_buffer) {
@@ -106,7 +113,15 @@
*read_buffer = new DvrReadBuffer;
}
-void dvrReadBufferDestroy(DvrReadBuffer* read_buffer) { delete read_buffer; }
+void dvrReadBufferDestroy(DvrReadBuffer* read_buffer) {
+ if (read_buffer != nullptr) {
+ ALOGW_IF(
+ read_buffer->slot != -1,
+ "dvrReadBufferDestroy: Destroying a buffer associated with a valid "
+ "buffer queue slot. This may indicate possible leaks.");
+ delete read_buffer;
+ }
+}
int dvrReadBufferIsValid(DvrReadBuffer* read_buffer) {
return read_buffer && read_buffer->read_buffer;
@@ -176,6 +191,11 @@
hardware_buffer);
}
+// Retrieve the shared buffer layout version defined in dvr_shared_buffers.h.
+int dvrBufferGlobalLayoutVersionGet() {
+ return android::dvr::kSharedBufferLayoutVersion;
+}
+
const struct native_handle* dvrWriteBufferGetNativeHandle(
DvrWriteBuffer* write_buffer) {
if (!write_buffer || !write_buffer->write_buffer)
diff --git a/libs/vr/libdvr/dvr_buffer_queue.cpp b/libs/vr/libdvr/dvr_buffer_queue.cpp
index 5d01c8f..09a49dd 100644
--- a/libs/vr/libdvr/dvr_buffer_queue.cpp
+++ b/libs/vr/libdvr/dvr_buffer_queue.cpp
@@ -14,6 +14,8 @@
using android::dvr::BufferProducer;
using android::dvr::ConsumerQueue;
using android::dvr::ProducerQueue;
+using android::dvr::ProducerQueueConfigBuilder;
+using android::dvr::UsagePolicy;
extern "C" {
@@ -25,15 +27,6 @@
format_(producer_queue->default_format()) {}
int DvrWriteBufferQueue::GetNativeWindow(ANativeWindow** out_window) {
- if (producer_queue_->metadata_size() != sizeof(DvrNativeBufferMetadata)) {
- ALOGE(
- "DvrWriteBufferQueue::GetNativeWindow: The size of buffer metadata "
- "(%zu) of the write queue does not match of size of "
- "DvrNativeBufferMetadata (%zu).",
- producer_queue_->metadata_size(), sizeof(DvrNativeBufferMetadata));
- return -EINVAL;
- }
-
if (native_window_ == nullptr) {
// Lazy creation of |native_window|, as not everyone is using
// DvrWriteBufferQueue as an external surface.
@@ -62,9 +55,26 @@
int DvrWriteBufferQueue::Dequeue(int timeout, DvrWriteBuffer* write_buffer,
int* out_fence_fd) {
+ DvrNativeBufferMetadata meta;
+ DvrWriteBuffer* buffer = nullptr;
+ int fence_fd = -1;
+ if (const int ret = GainBuffer(timeout, &buffer, &meta, &fence_fd))
+ return ret;
+ if (!buffer)
+ return -ENOMEM;
+
+ write_buffers_[buffer->slot].reset(buffer);
+ write_buffer->write_buffer = std::move(buffer->write_buffer);
+ *out_fence_fd = fence_fd;
+ return 0;
+}
+
+int DvrWriteBufferQueue::GainBuffer(int timeout,
+ DvrWriteBuffer** out_write_buffer,
+ DvrNativeBufferMetadata* out_meta,
+ int* out_fence_fd) {
size_t slot;
- pdx::LocalHandle fence;
- std::shared_ptr<BufferProducer> buffer_producer;
+ pdx::LocalHandle release_fence;
// Need to retry N+1 times, where N is total number of buffers in the queue.
// As in the worst case, we will dequeue all N buffers and reallocate them, on
@@ -73,15 +83,29 @@
size_t retry = 0;
for (; retry < max_retries; retry++) {
- auto buffer_status = producer_queue_->Dequeue(timeout, &slot, &fence);
+ auto buffer_status =
+ producer_queue_->Dequeue(timeout, &slot, out_meta, &release_fence);
if (!buffer_status) {
ALOGE_IF(buffer_status.error() != ETIMEDOUT,
- "DvrWriteBufferQueue::Dequeue: Failed to dequeue buffer: %s",
+ "DvrWriteBufferQueue::GainBuffer: Failed to dequeue buffer: %s",
buffer_status.GetErrorMessage().c_str());
return -buffer_status.error();
}
- buffer_producer = buffer_status.take();
+ if (write_buffers_[slot] == nullptr) {
+ // Lazy initialization of a write_buffers_ slot. Note that a slot will
+ // only be dynamically allocated once during the entire cycle life of a
+ // queue.
+ write_buffers_[slot] = std::make_unique<DvrWriteBuffer>();
+ write_buffers_[slot]->slot = slot;
+ }
+
+ LOG_ALWAYS_FATAL_IF(
+ write_buffers_[slot]->write_buffer,
+ "DvrWriteBufferQueue::GainBuffer: Buffer slot is not empty: %zu", slot);
+ write_buffers_[slot]->write_buffer = std::move(buffer_status.take());
+
+ const auto& buffer_producer = write_buffers_[slot]->write_buffer;
if (!buffer_producer)
return -ENOMEM;
@@ -120,9 +144,12 @@
remove_status.GetErrorMessage().c_str());
return -remove_status.error();
}
+ // Make sure that the previously allocated buffer is dereferenced from
+ // write_buffers_ array.
+ write_buffers_[slot]->write_buffer = nullptr;
auto allocate_status = producer_queue_->AllocateBuffer(
- width_, height_, old_layer_count, format_, old_usage, &slot);
+ width_, height_, old_layer_count, format_, old_usage);
if (!allocate_status) {
ALOGE("DvrWriteBufferQueue::Dequeue: Failed to allocate buffer: %s",
allocate_status.GetErrorMessage().c_str());
@@ -137,8 +164,52 @@
return -ENOMEM;
}
- write_buffer->write_buffer = std::move(buffer_producer);
- *out_fence_fd = fence.Release();
+ *out_write_buffer = write_buffers_[slot].release();
+ *out_fence_fd = release_fence.Release();
+
+ return 0;
+}
+
+int DvrWriteBufferQueue::PostBuffer(DvrWriteBuffer* write_buffer,
+ const DvrNativeBufferMetadata* meta,
+ int ready_fence_fd) {
+ LOG_FATAL_IF(
+ (write_buffers->slot < 0 || write_buffers->slot >= write_buffers_.size()),
+ "DvrWriteBufferQueue::ReleaseBuffer: Invalid slot: %zu", slot);
+
+ // Some basic sanity checks before we put the buffer back into a slot.
+ size_t slot = static_cast<size_t>(write_buffer->slot);
+ if (write_buffers_[slot] != nullptr) {
+ ALOGE("DvrWriteBufferQueue::PostBuffer: Slot is not empty: %zu", slot);
+ return -EINVAL;
+ }
+ if (write_buffer->write_buffer == nullptr) {
+ ALOGE("DvrWriteBufferQueue::PostBuffer: Invalid write buffer.");
+ return -EINVAL;
+ }
+ if (write_buffer->write_buffer->id() != producer_queue_->GetBufferId(slot)) {
+ ALOGE(
+ "DvrWriteBufferQueue::PostBuffer: Buffer to be posted does not "
+ "belong to this buffer queue. Posting buffer: id=%d, buffer in "
+ "queue: id=%d",
+ write_buffer->write_buffer->id(), producer_queue_->GetBufferId(slot));
+ return -EINVAL;
+ }
+
+ write_buffer->write_buffer->SetQueueIndex(next_post_index_++);
+ pdx::LocalHandle fence(ready_fence_fd);
+ const int ret = write_buffer->write_buffer->PostAsync(meta, fence);
+ if (ret < 0) {
+ ALOGE("DvrWriteBufferQueue::PostBuffer: Failed to post buffer, ret=%d",
+ ret);
+ return ret;
+ }
+
+ // Put the DvrWriteBuffer pointer back into its slot for reuse.
+ write_buffers_[slot].reset(write_buffer);
+ // It's import to reset the write buffer client now. It should stay invalid
+ // until next GainBuffer on the same slot.
+ write_buffers_[slot]->write_buffer = nullptr;
return 0;
}
@@ -156,6 +227,36 @@
return 0;
}
+int dvrWriteBufferQueueCreate(uint32_t width, uint32_t height, uint32_t format,
+ uint32_t layer_count, uint64_t usage,
+ size_t capacity, size_t metadata_size,
+ DvrWriteBufferQueue** out_write_queue) {
+ if (!out_write_queue)
+ return -EINVAL;
+
+ auto config_builder = ProducerQueueConfigBuilder()
+ .SetDefaultWidth(width)
+ .SetDefaultHeight(height)
+ .SetDefaultFormat(format)
+ .SetMetadataSize(metadata_size);
+ std::unique_ptr<ProducerQueue> producer_queue =
+ ProducerQueue::Create(config_builder.Build(), UsagePolicy{});
+ if (!producer_queue) {
+ ALOGE("dvrWriteBufferQueueCreate: Failed to create producer queue.");
+ return -ENOMEM;
+ }
+
+ auto status = producer_queue->AllocateBuffers(width, height, layer_count,
+ format, usage, capacity);
+ if (!status.ok()) {
+ ALOGE("dvrWriteBufferQueueCreate: Failed to allocate buffers.");
+ return -ENOMEM;
+ }
+
+ *out_write_queue = new DvrWriteBufferQueue(std::move(producer_queue));
+ return 0;
+}
+
void dvrWriteBufferQueueDestroy(DvrWriteBufferQueue* write_queue) {
delete write_queue;
}
@@ -176,6 +277,14 @@
int dvrWriteBufferQueueGetExternalSurface(DvrWriteBufferQueue* write_queue,
ANativeWindow** out_window) {
+ ALOGW(
+ "dvrWriteBufferQueueGetExternalSurface: This API has been deprecated and "
+ "renamed to dvrWriteBufferQueueGetANativeWindow.");
+ return dvrWriteBufferQueueGetANativeWindow(write_queue, out_window);
+}
+
+int dvrWriteBufferQueueGetANativeWindow(DvrWriteBufferQueue* write_queue,
+ ANativeWindow** out_window) {
if (!write_queue || !out_window)
return -EINVAL;
@@ -199,6 +308,27 @@
return write_queue->Dequeue(timeout, write_buffer, out_fence_fd);
}
+int dvrWriteBufferQueueGainBuffer(DvrWriteBufferQueue* write_queue, int timeout,
+ DvrWriteBuffer** out_write_buffer,
+ DvrNativeBufferMetadata* out_meta,
+ int* out_fence_fd) {
+ if (!write_queue || !out_write_buffer || !out_meta || !out_fence_fd)
+ return -EINVAL;
+
+ return write_queue->GainBuffer(timeout, out_write_buffer, out_meta,
+ out_fence_fd);
+}
+
+int dvrWriteBufferQueuePostBuffer(DvrWriteBufferQueue* write_queue,
+ DvrWriteBuffer* write_buffer,
+ const DvrNativeBufferMetadata* meta,
+ int ready_fence_fd) {
+ if (!write_queue || !write_buffer || !write_buffer->write_buffer || !meta)
+ return -EINVAL;
+
+ return write_queue->PostBuffer(write_buffer, meta, ready_fence_fd);
+}
+
int dvrWriteBufferQueueResizeBuffer(DvrWriteBufferQueue* write_queue,
uint32_t width, uint32_t height) {
if (!write_queue)
@@ -251,6 +381,82 @@
read_buffer->read_buffer = buffer_status.take();
*out_fence_fd = acquire_fence.Release();
+
+ return 0;
+}
+
+int DvrReadBufferQueue::AcquireBuffer(int timeout,
+ DvrReadBuffer** out_read_buffer,
+ DvrNativeBufferMetadata* out_meta,
+ int* out_fence_fd) {
+ size_t slot;
+ pdx::LocalHandle acquire_fence;
+ auto buffer_status =
+ consumer_queue_->Dequeue(timeout, &slot, out_meta, &acquire_fence);
+ if (!buffer_status) {
+ ALOGE_IF(buffer_status.error() != ETIMEDOUT,
+ "DvrReadBufferQueue::AcquireBuffer: Failed to dequeue buffer: %s",
+ buffer_status.GetErrorMessage().c_str());
+ return -buffer_status.error();
+ }
+
+ if (read_buffers_[slot] == nullptr) {
+ // Lazy initialization of a read_buffers_ slot. Note that a slot will only
+ // be dynamically allocated once during the entire cycle life of a queue.
+ read_buffers_[slot] = std::make_unique<DvrReadBuffer>();
+ read_buffers_[slot]->slot = slot;
+ }
+
+ LOG_FATAL_IF(
+ read_buffers_[slot]->read_buffer,
+ "DvrReadBufferQueue::AcquireBuffer: Buffer slot is not empty: %zu", slot);
+ read_buffers_[slot]->read_buffer = std::move(buffer_status.take());
+
+ *out_read_buffer = read_buffers_[slot].release();
+ *out_fence_fd = acquire_fence.Release();
+
+ return 0;
+}
+
+int DvrReadBufferQueue::ReleaseBuffer(DvrReadBuffer* read_buffer,
+ const DvrNativeBufferMetadata* meta,
+ int release_fence_fd) {
+ LOG_FATAL_IF(
+ (read_buffers->slot < 0 || read_buffers->slot >= read_buffers_size()),
+ "DvrReadBufferQueue::ReleaseBuffer: Invalid slot: %zu", slot);
+
+ // Some basic sanity checks before we put the buffer back into a slot.
+ size_t slot = static_cast<size_t>(read_buffer->slot);
+ if (read_buffers_[slot] != nullptr) {
+ ALOGE("DvrReadBufferQueue::ReleaseBuffer: Slot is not empty: %zu", slot);
+ return -EINVAL;
+ }
+ if (read_buffer->read_buffer == nullptr) {
+ ALOGE("DvrReadBufferQueue::ReleaseBuffer: Invalid read buffer.");
+ return -EINVAL;
+ }
+ if (read_buffer->read_buffer->id() != consumer_queue_->GetBufferId(slot)) {
+ ALOGE(
+ "DvrReadBufferQueue::ReleaseBuffer: Buffer to be released does not "
+ "belong to this buffer queue. Releasing buffer: id=%d, buffer in "
+ "queue: id=%d",
+ read_buffer->read_buffer->id(), consumer_queue_->GetBufferId(slot));
+ return -EINVAL;
+ }
+
+ pdx::LocalHandle fence(release_fence_fd);
+ int ret = read_buffer->read_buffer->ReleaseAsync(meta, fence);
+ if (ret < 0) {
+ ALOGE("DvrReadBufferQueue::ReleaseBuffer: Failed to release buffer, ret=%d",
+ ret);
+ return ret;
+ }
+
+ // Put the DvrReadBuffer pointer back into its slot for reuse.
+ read_buffers_[slot].reset(read_buffer);
+ // It's import to reset the read buffer client now. It should stay invalid
+ // until next AcquireBuffer on the same slot.
+ read_buffers_[slot]->read_buffer = nullptr;
return 0;
}
@@ -271,9 +477,11 @@
} else {
consumer_queue_->SetBufferRemovedCallback(
[callback, context](const std::shared_ptr<BufferHubBuffer>& buffer) {
- DvrReadBuffer read_buffer{
- std::static_pointer_cast<BufferConsumer>(buffer)};
- callback(&read_buffer, context);
+ // When buffer is removed from the queue, the slot is already invalid.
+ auto read_buffer = std::make_unique<DvrReadBuffer>();
+ read_buffer->read_buffer =
+ std::static_pointer_cast<BufferConsumer>(buffer);
+ callback(read_buffer.release(), context);
});
}
}
@@ -302,6 +510,13 @@
return read_queue->id();
}
+int dvrReadBufferQueueGetEventFd(DvrReadBufferQueue* read_queue) {
+ if (!read_queue)
+ return -EINVAL;
+
+ return read_queue->event_fd();
+}
+
int dvrReadBufferQueueCreateReadQueue(DvrReadBufferQueue* read_queue,
DvrReadBufferQueue** out_read_queue) {
if (!read_queue || !out_read_queue)
@@ -313,13 +528,37 @@
int dvrReadBufferQueueDequeue(DvrReadBufferQueue* read_queue, int timeout,
DvrReadBuffer* read_buffer, int* out_fence_fd,
void* out_meta, size_t meta_size_bytes) {
- if (!read_queue || !read_buffer || !out_fence_fd || !out_meta)
+ if (!read_queue || !read_buffer || !out_fence_fd)
+ return -EINVAL;
+
+ if (meta_size_bytes != 0 && !out_meta)
return -EINVAL;
return read_queue->Dequeue(timeout, read_buffer, out_fence_fd, out_meta,
meta_size_bytes);
}
+int dvrReadBufferQueueAcquireBuffer(DvrReadBufferQueue* read_queue, int timeout,
+ DvrReadBuffer** out_read_buffer,
+ DvrNativeBufferMetadata* out_meta,
+ int* out_fence_fd) {
+ if (!read_queue || !out_read_buffer || !out_meta || !out_fence_fd)
+ return -EINVAL;
+
+ return read_queue->AcquireBuffer(timeout, out_read_buffer, out_meta,
+ out_fence_fd);
+}
+
+int dvrReadBufferQueueReleaseBuffer(DvrReadBufferQueue* read_queue,
+ DvrReadBuffer* read_buffer,
+ const DvrNativeBufferMetadata* meta,
+ int release_fence_fd) {
+ if (!read_queue || !read_buffer || !read_buffer->read_buffer || !meta)
+ return -EINVAL;
+
+ return read_queue->ReleaseBuffer(read_buffer, meta, release_fence_fd);
+}
+
int dvrReadBufferQueueSetBufferAvailableCallback(
DvrReadBufferQueue* read_queue,
DvrReadBufferQueueBufferAvailableCallback callback, void* context) {
diff --git a/libs/vr/libdvr/dvr_buffer_queue_internal.h b/libs/vr/libdvr/dvr_buffer_queue_internal.h
index 133bf98..e53a686 100644
--- a/libs/vr/libdvr/dvr_buffer_queue_internal.h
+++ b/libs/vr/libdvr/dvr_buffer_queue_internal.h
@@ -5,11 +5,23 @@
#include <private/dvr/buffer_hub_queue_client.h>
#include <sys/cdefs.h>
+#include <array>
#include <memory>
+#include "dvr_internal.h"
+
struct ANativeWindow;
+typedef struct DvrNativeBufferMetadata DvrNativeBufferMetadata;
+typedef struct DvrReadBuffer DvrReadBuffer;
+typedef struct DvrReadBufferQueue DvrReadBufferQueue;
+typedef struct DvrWriteBuffer DvrWriteBuffer;
+typedef void (*DvrReadBufferQueueBufferAvailableCallback)(void* context);
+typedef void (*DvrReadBufferQueueBufferRemovedCallback)(DvrReadBuffer* buffer,
+ void* context);
+
struct DvrWriteBufferQueue {
+ using BufferHubQueue = android::dvr::BufferHubQueue;
using ProducerQueue = android::dvr::ProducerQueue;
// Create a concrete object for DvrWriteBufferQueue.
@@ -31,29 +43,43 @@
int GetNativeWindow(ANativeWindow** out_window);
int CreateReadQueue(DvrReadBufferQueue** out_read_queue);
int Dequeue(int timeout, DvrWriteBuffer* write_buffer, int* out_fence_fd);
+ int GainBuffer(int timeout, DvrWriteBuffer** out_write_buffer,
+ DvrNativeBufferMetadata* out_meta, int* out_fence_fd);
+ int PostBuffer(DvrWriteBuffer* write_buffer,
+ const DvrNativeBufferMetadata* meta, int ready_fence_fd);
int ResizeBuffer(uint32_t width, uint32_t height);
private:
std::shared_ptr<ProducerQueue> producer_queue_;
+ std::array<std::unique_ptr<DvrWriteBuffer>, BufferHubQueue::kMaxQueueCapacity>
+ write_buffers_;
+ int64_t next_post_index_ = 0;
uint32_t width_;
uint32_t height_;
uint32_t format_;
+
android::sp<android::Surface> native_window_;
};
struct DvrReadBufferQueue {
+ using BufferHubQueue = android::dvr::BufferHubQueue;
using ConsumerQueue = android::dvr::ConsumerQueue;
explicit DvrReadBufferQueue(
const std::shared_ptr<ConsumerQueue>& consumer_queue);
int id() const { return consumer_queue_->id(); }
+ int event_fd() const { return consumer_queue_->queue_fd(); }
size_t capacity() const { return consumer_queue_->capacity(); }
int CreateReadQueue(DvrReadBufferQueue** out_read_queue);
int Dequeue(int timeout, DvrReadBuffer* read_buffer, int* out_fence_fd,
- void* out_meta, size_t meta_size_bytes);
+ void* out_meta, size_t user_metadata_size);
+ int AcquireBuffer(int timeout, DvrReadBuffer** out_read_buffer,
+ DvrNativeBufferMetadata* out_meta, int* out_fence_fd);
+ int ReleaseBuffer(DvrReadBuffer* read_buffer,
+ const DvrNativeBufferMetadata* meta, int release_fence_fd);
void SetBufferAvailableCallback(
DvrReadBufferQueueBufferAvailableCallback callback, void* context);
void SetBufferRemovedCallback(
@@ -62,6 +88,8 @@
private:
std::shared_ptr<ConsumerQueue> consumer_queue_;
+ std::array<std::unique_ptr<DvrReadBuffer>, BufferHubQueue::kMaxQueueCapacity>
+ read_buffers_;
};
#endif // ANDROID_DVR_BUFFER_QUEUE_INTERNAL_H_
diff --git a/libs/vr/libdvr/dvr_display_manager.cpp b/libs/vr/libdvr/dvr_display_manager.cpp
index 26973f9..852f9a4 100644
--- a/libs/vr/libdvr/dvr_display_manager.cpp
+++ b/libs/vr/libdvr/dvr_display_manager.cpp
@@ -2,7 +2,6 @@
#include <dvr/dvr_buffer.h>
#include <pdx/rpc/variant.h>
-#include <private/android/AHardwareBufferHelpers.h>
#include <private/dvr/buffer_hub_client.h>
#include <private/dvr/buffer_hub_queue_client.h>
#include <private/dvr/display_client.h>
@@ -11,7 +10,6 @@
#include "dvr_internal.h"
#include "dvr_buffer_queue_internal.h"
-using android::AHardwareBuffer_convertToGrallocUsageBits;
using android::dvr::BufferConsumer;
using android::dvr::display::DisplayManagerClient;
using android::dvr::display::SurfaceAttributes;
@@ -112,44 +110,6 @@
void dvrDisplayManagerDestroy(DvrDisplayManager* client) { delete client; }
-int dvrDisplayManagerSetupGlobalBuffer(DvrDisplayManager* client,
- DvrGlobalBufferKey key, size_t size,
- uint64_t usage, DvrBuffer** buffer_out) {
- if (!client || !buffer_out)
- return -EINVAL;
-
- uint64_t gralloc_usage = AHardwareBuffer_convertToGrallocUsageBits(usage);
-
- auto buffer_status =
- client->client->SetupGlobalBuffer(key, size, gralloc_usage);
- if (!buffer_status) {
- ALOGE(
- "dvrDisplayManagerSetupGlobalBuffer: Failed to setup global buffer: %s",
- buffer_status.GetErrorMessage().c_str());
- return -buffer_status.error();
- }
-
- *buffer_out = CreateDvrBufferFromIonBuffer(buffer_status.take());
- return 0;
-}
-
-int dvrDisplayManagerDeleteGlobalBuffer(DvrDisplayManager* client,
- DvrGlobalBufferKey key) {
- if (!client)
- return -EINVAL;
-
- auto buffer_status = client->client->DeleteGlobalBuffer(key);
- if (!buffer_status) {
- ALOGE(
- "dvrDisplayManagerDeleteGlobalBuffer: Failed to delete named buffer: "
- "%s",
- buffer_status.GetErrorMessage().c_str());
- return -buffer_status.error();
- }
-
- return 0;
-}
-
int dvrDisplayManagerGetEventFd(DvrDisplayManager* client) {
if (!client)
return -EINVAL;
diff --git a/libs/vr/libdvr/dvr_hardware_composer_client.cpp b/libs/vr/libdvr/dvr_hardware_composer_client.cpp
index d3ae299..4e87cf6 100644
--- a/libs/vr/libdvr/dvr_hardware_composer_client.cpp
+++ b/libs/vr/libdvr/dvr_hardware_composer_client.cpp
@@ -6,7 +6,9 @@
#include <binder/IServiceManager.h>
#include <private/android/AHardwareBufferHelpers.h>
+#include <functional>
#include <memory>
+#include <mutex>
struct DvrHwcFrame {
android::dvr::ComposerView::Frame frame;
@@ -16,10 +18,15 @@
class HwcCallback : public android::dvr::BnVrComposerCallback {
public:
- explicit HwcCallback(DvrHwcOnFrameCallback callback,
- void* client_state);
+ using CallbackFunction = std::function<int(DvrHwcFrame*)>;
+
+ explicit HwcCallback(const CallbackFunction& callback);
~HwcCallback() override;
+ // Reset the callback. This needs to be done early to avoid use after free
+ // accesses from binder thread callbacks.
+ void Shutdown();
+
std::unique_ptr<DvrHwcFrame> DequeueFrame();
private:
@@ -28,26 +35,41 @@
const android::dvr::ParcelableComposerFrame& frame,
android::dvr::ParcelableUniqueFd* fence) override;
- DvrHwcOnFrameCallback callback_;
- void* client_state_;
+ // Protects the |callback_| from uses from multiple threads. During shutdown
+ // there may be in-flight frame update events. In those cases the callback
+ // access needs to be protected otherwise binder threads may access an invalid
+ // callback.
+ std::mutex mutex_;
+ CallbackFunction callback_;
HwcCallback(const HwcCallback&) = delete;
void operator=(const HwcCallback&) = delete;
};
-HwcCallback::HwcCallback(DvrHwcOnFrameCallback callback, void* client_state)
- : callback_(callback), client_state_(client_state) {}
+HwcCallback::HwcCallback(const CallbackFunction& callback)
+ : callback_(callback) {}
HwcCallback::~HwcCallback() {}
+void HwcCallback::Shutdown() {
+ std::lock_guard<std::mutex> guard(mutex_);
+ callback_ = nullptr;
+}
+
android::binder::Status HwcCallback::onNewFrame(
const android::dvr::ParcelableComposerFrame& frame,
android::dvr::ParcelableUniqueFd* fence) {
+ std::lock_guard<std::mutex> guard(mutex_);
+
+ if (!callback_) {
+ fence->set_fence(android::base::unique_fd());
+ return android::binder::Status::ok();
+ }
+
std::unique_ptr<DvrHwcFrame> dvr_frame(new DvrHwcFrame());
dvr_frame->frame = frame.frame();
- fence->set_fence(android::base::unique_fd(callback_(client_state_,
- dvr_frame.release())));
+ fence->set_fence(android::base::unique_fd(callback_(dvr_frame.release())));
return android::binder::Status::ok();
}
@@ -67,7 +89,8 @@
if (!client->composer.get())
return nullptr;
- client->callback = new HwcCallback(callback, data);
+ client->callback = new HwcCallback(std::bind(callback, data,
+ std::placeholders::_1));
android::binder::Status status = client->composer->registerObserver(
client->callback);
if (!status.isOk())
@@ -77,6 +100,13 @@
}
void dvrHwcClientDestroy(DvrHwcClient* client) {
+ client->composer->clearObserver();
+
+ // NOTE: Deleting DvrHwcClient* isn't enough since DvrHwcClient::callback is a
+ // shared pointer that could be referenced from a binder thread. But the
+ // client callback isn't valid past this calls so that needs to be reset.
+ client->callback->Shutdown();
+
delete client;
}
diff --git a/libs/vr/libdvr/dvr_internal.h b/libs/vr/libdvr/dvr_internal.h
index 28b6c28..de8bb96 100644
--- a/libs/vr/libdvr/dvr_internal.h
+++ b/libs/vr/libdvr/dvr_internal.h
@@ -34,10 +34,20 @@
extern "C" {
struct DvrWriteBuffer {
+ // The slot nubmer of the buffer, a valid slot number must be in the range of
+ // [0, android::BufferQueueDefs::NUM_BUFFER_SLOTS). This is only valid for
+ // DvrWriteBuffer acquired from a DvrWriteBufferQueue.
+ int32_t slot = -1;
+
std::shared_ptr<android::dvr::BufferProducer> write_buffer;
};
struct DvrReadBuffer {
+ // The slot nubmer of the buffer, a valid slot number must be in the range of
+ // [0, android::BufferQueueDefs::NUM_BUFFER_SLOTS). This is only valid for
+ // DvrReadBuffer acquired from a DvrReadBufferQueue.
+ int32_t slot = -1;
+
std::shared_ptr<android::dvr::BufferConsumer> read_buffer;
};
diff --git a/libs/vr/libdvr/dvr_performance.cpp b/libs/vr/libdvr/dvr_performance.cpp
new file mode 100644
index 0000000..599101f
--- /dev/null
+++ b/libs/vr/libdvr/dvr_performance.cpp
@@ -0,0 +1,18 @@
+#include "include/dvr/dvr_performance.h"
+
+#include <private/dvr/performance_client.h>
+
+using android::dvr::PerformanceClient;
+
+extern "C" {
+
+int dvrPerformanceSetSchedulerPolicy(pid_t task_id,
+ const char* scheduler_policy) {
+ int error;
+ if (auto client = PerformanceClient::Create(&error))
+ return client->SetSchedulerPolicy(task_id, scheduler_policy);
+ else
+ return error;
+}
+
+} // extern "C"
diff --git a/libs/vr/libdvr/dvr_pose.cpp b/libs/vr/libdvr/dvr_pose.cpp
new file mode 100644
index 0000000..c379ef5
--- /dev/null
+++ b/libs/vr/libdvr/dvr_pose.cpp
@@ -0,0 +1,29 @@
+#include "include/dvr/dvr_pose.h"
+
+#include <memory>
+
+#include <private/dvr/buffer_hub_queue_client.h>
+#include <private/dvr/pose_client_internal.h>
+
+#include "dvr_buffer_queue_internal.h"
+
+using android::dvr::ConsumerQueue;
+
+int dvrPoseClientGetDataReader(DvrPoseClient* client, uint64_t data_type,
+ DvrReadBufferQueue** queue_out) {
+ if (!client || !queue_out)
+ return -EINVAL;
+
+ ConsumerQueue* consumer_queue;
+ int status = android::dvr::dvrPoseClientGetDataReaderHandle(client,
+ data_type,
+ &consumer_queue);
+ if (status != 0) {
+ ALOGE("dvrPoseClientGetDataReader: Failed to get queue: %d", status);
+ return status;
+ }
+
+ std::shared_ptr<ConsumerQueue> consumer_queue_ptr{consumer_queue};
+ *queue_out = new DvrReadBufferQueue(consumer_queue_ptr);
+ return 0;
+}
diff --git a/libs/vr/libdvr/dvr_surface.cpp b/libs/vr/libdvr/dvr_surface.cpp
index 2affacd..a3a47f1 100644
--- a/libs/vr/libdvr/dvr_surface.cpp
+++ b/libs/vr/libdvr/dvr_surface.cpp
@@ -2,19 +2,33 @@
#include <inttypes.h>
+#include <pdx/rpc/variant.h>
+#include <private/android/AHardwareBufferHelpers.h>
#include <private/dvr/display_client.h>
-#include "dvr_internal.h"
#include "dvr_buffer_queue_internal.h"
+#include "dvr_internal.h"
+using android::AHardwareBuffer_convertToGrallocUsageBits;
using android::dvr::display::DisplayClient;
using android::dvr::display::Surface;
using android::dvr::display::SurfaceAttributes;
using android::dvr::display::SurfaceAttributeValue;
using android::dvr::CreateDvrReadBufferFromBufferConsumer;
+using android::pdx::rpc::EmptyVariant;
namespace {
+// Sets the Variant |destination| to the target std::array type and copies the C
+// array into it. Unsupported std::array configurations will fail to compile.
+template <typename T, std::size_t N>
+void ArrayCopy(SurfaceAttributeValue* destination, const T (&source)[N]) {
+ using ArrayType = std::array<T, N>;
+ *destination = ArrayType{};
+ std::copy(std::begin(source), std::end(source),
+ std::get<ArrayType>(*destination).begin());
+}
+
bool ConvertSurfaceAttributes(const DvrSurfaceAttribute* attributes,
size_t attribute_count,
SurfaceAttributes* surface_attributes,
@@ -29,25 +43,31 @@
value = attributes[i].value.int64_value;
break;
case DVR_SURFACE_ATTRIBUTE_TYPE_BOOL:
- value = attributes[i].value.bool_value;
+ // bool_value is defined in an extern "C" block, which makes it look
+ // like an int to C++. Use a cast to assign the correct type to the
+ // Variant type SurfaceAttributeValue.
+ value = static_cast<bool>(attributes[i].value.bool_value);
break;
case DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT:
value = attributes[i].value.float_value;
break;
case DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT2:
- value = attributes[i].value.float2_value;
+ ArrayCopy(&value, attributes[i].value.float2_value);
break;
case DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT3:
- value = attributes[i].value.float3_value;
+ ArrayCopy(&value, attributes[i].value.float3_value);
break;
case DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT4:
- value = attributes[i].value.float4_value;
+ ArrayCopy(&value, attributes[i].value.float4_value);
break;
case DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT8:
- value = attributes[i].value.float8_value;
+ ArrayCopy(&value, attributes[i].value.float8_value);
break;
case DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT16:
- value = attributes[i].value.float16_value;
+ ArrayCopy(&value, attributes[i].value.float16_value);
+ break;
+ case DVR_SURFACE_ATTRIBUTE_TYPE_NONE:
+ value = EmptyVariant{};
break;
default:
*error_index = i;
@@ -134,7 +154,7 @@
int dvrSurfaceCreateWriteBufferQueue(DvrSurface* surface, uint32_t width,
uint32_t height, uint32_t format,
uint32_t layer_count, uint64_t usage,
- size_t capacity,
+ size_t capacity, size_t metadata_size,
DvrWriteBufferQueue** out_writer) {
if (surface == nullptr || out_writer == nullptr) {
ALOGE(
@@ -144,8 +164,8 @@
return -EINVAL;
}
- auto status = surface->surface->CreateQueue(width, height, layer_count,
- format, usage, capacity);
+ auto status = surface->surface->CreateQueue(
+ width, height, layer_count, format, usage, capacity, metadata_size);
if (!status) {
ALOGE("dvrSurfaceCreateWriteBufferQueue: Failed to create queue: %s",
status.GetErrorMessage().c_str());
@@ -156,27 +176,103 @@
return 0;
}
-int dvrGetGlobalBuffer(DvrGlobalBufferKey key, DvrBuffer** out_buffer) {
- auto client = DisplayClient::Create();
+int dvrSetupGlobalBuffer(DvrGlobalBufferKey key, size_t size, uint64_t usage,
+ DvrBuffer** buffer_out) {
+ if (!buffer_out)
+ return -EINVAL;
+
+ int error;
+ auto client = DisplayClient::Create(&error);
if (!client) {
- ALOGE("dvrGetGlobalBuffer: Failed to create display client!");
- return -ECOMM;
+ ALOGE("dvrSetupGlobalBuffer: Failed to create display client: %s",
+ strerror(-error));
+ return error;
}
- if (out_buffer == nullptr) {
- ALOGE("dvrGetGlobalBuffer: Invalid inputs: key=%d, out_buffer=%p.", key,
- out_buffer);
+ uint64_t gralloc_usage = AHardwareBuffer_convertToGrallocUsageBits(usage);
+
+ auto buffer_status = client->SetupGlobalBuffer(key, size, gralloc_usage);
+ if (!buffer_status) {
+ ALOGE("dvrSetupGlobalBuffer: Failed to setup global buffer: %s",
+ buffer_status.GetErrorMessage().c_str());
+ return -buffer_status.error();
+ }
+
+ *buffer_out = CreateDvrBufferFromIonBuffer(buffer_status.take());
+ return 0;
+}
+
+int dvrDeleteGlobalBuffer(DvrGlobalBufferKey key) {
+ int error;
+ auto client = DisplayClient::Create(&error);
+ if (!client) {
+ ALOGE("dvrDeleteGlobalBuffer: Failed to create display client: %s",
+ strerror(-error));
+ return error;
+ }
+
+ auto buffer_status = client->DeleteGlobalBuffer(key);
+ if (!buffer_status) {
+ ALOGE("dvrDeleteGlobalBuffer: Failed to delete named buffer: %s",
+ buffer_status.GetErrorMessage().c_str());
+ return -buffer_status.error();
+ }
+
+ return 0;
+}
+
+int dvrGetGlobalBuffer(DvrGlobalBufferKey key, DvrBuffer** out_buffer) {
+ if (!out_buffer)
return -EINVAL;
+
+ int error;
+ auto client = DisplayClient::Create(&error);
+ if (!client) {
+ ALOGE("dvrGetGlobalBuffer: Failed to create display client: %s",
+ strerror(-error));
+ return error;
}
auto status = client->GetGlobalBuffer(key);
if (!status) {
- ALOGE("dvrGetGlobalBuffer: Failed to find named buffer key=%d: %s", key,
- status.GetErrorMessage().c_str());
return -status.error();
}
*out_buffer = CreateDvrBufferFromIonBuffer(status.take());
return 0;
}
+int dvrGetNativeDisplayMetrics(size_t sizeof_metrics,
+ DvrNativeDisplayMetrics* metrics) {
+ ALOGE_IF(sizeof_metrics != sizeof(DvrNativeDisplayMetrics),
+ "dvrGetNativeDisplayMetrics: metrics struct mismatch, your dvr api "
+ "header is out of date.");
+
+ auto client = DisplayClient::Create();
+ if (!client) {
+ ALOGE("dvrGetNativeDisplayMetrics: Failed to create display client!");
+ return -ECOMM;
+ }
+
+ if (metrics == nullptr) {
+ ALOGE("dvrGetNativeDisplayMetrics: output metrics buffer must be non-null");
+ return -EINVAL;
+ }
+
+ auto status = client->GetDisplayMetrics();
+
+ if (!status) {
+ return -status.error();
+ }
+
+ if (sizeof_metrics >= 20) {
+ metrics->display_width = status.get().display_width;
+ metrics->display_height = status.get().display_height;
+ metrics->display_x_dpi = status.get().display_x_dpi;
+ metrics->display_y_dpi = status.get().display_y_dpi;
+ metrics->vsync_period_ns = status.get().vsync_period_ns;
+ }
+
+ return 0;
+}
+
} // extern "C"
diff --git a/libs/vr/libdvr/include/dvr/dvr_api.h b/libs/vr/libdvr/include/dvr/dvr_api.h
index f05a6fd..499b7c1 100644
--- a/libs/vr/libdvr/include/dvr/dvr_api.h
+++ b/libs/vr/libdvr/include/dvr/dvr_api.h
@@ -4,6 +4,7 @@
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
+#include <unistd.h>
#include <cstdio>
#include <dvr/dvr_display_types.h>
@@ -14,6 +15,12 @@
extern "C" {
#endif
+#ifdef __GNUC__
+#define ALIGNED_DVR_STRUCT(x) __attribute__((packed, aligned(x)))
+#else
+#define ALIGNED_DVR_STRUCT(x)
+#endif
+
typedef struct ANativeWindow ANativeWindow;
typedef struct DvrPoseAsync DvrPoseAsync;
@@ -22,6 +29,7 @@
typedef struct DvrDisplayManager DvrDisplayManager;
typedef struct DvrSurfaceState DvrSurfaceState;
typedef struct DvrPoseClient DvrPoseClient;
+typedef struct DvrPoseDataCaptureRequest DvrPoseDataCaptureRequest;
typedef struct DvrVSyncClient DvrVSyncClient;
typedef struct DvrVirtualTouchpad DvrVirtualTouchpad;
@@ -32,6 +40,7 @@
typedef struct DvrReadBufferQueue DvrReadBufferQueue;
typedef struct DvrWriteBufferQueue DvrWriteBufferQueue;
+typedef struct DvrNativeBufferMetadata DvrNativeBufferMetadata;
typedef struct DvrSurface DvrSurface;
typedef uint64_t DvrSurfaceAttributeType;
@@ -41,6 +50,19 @@
typedef struct DvrSurfaceAttributeValue DvrSurfaceAttributeValue;
typedef struct DvrSurfaceAttribute DvrSurfaceAttribute;
+// Note: To avoid breaking others during active development, only modify this
+// struct by appending elements to the end.
+// If you do feel we should to re-arrange or remove elements, please make a
+// note of it, and wait until we're about to finalize for an API release to do
+// so.
+typedef struct DvrNativeDisplayMetrics {
+ uint32_t display_width;
+ uint32_t display_height;
+ uint32_t display_x_dpi;
+ uint32_t display_y_dpi;
+ uint32_t vsync_period_ns;
+} DvrNativeDisplayMetrics;
+
// native_handle contains the fds for the underlying ION allocations inside
// the gralloc buffer. This is needed temporarily while GPU vendors work on
// better support for AHardwareBuffer via glBindSharedBuffer APIs. See
@@ -61,11 +83,6 @@
// dvr_display_manager.h
typedef int (*DvrDisplayManagerCreatePtr)(DvrDisplayManager** client_out);
typedef void (*DvrDisplayManagerDestroyPtr)(DvrDisplayManager* client);
-typedef int (*DvrDisplayManagerSetupGlobalBufferPtr)(DvrDisplayManager* client,
- DvrGlobalBufferKey key,
- size_t size,
- uint64_t usage,
- DvrBuffer** buffer_out);
typedef int (*DvrDisplayManagerGetEventFdPtr)(DvrDisplayManager* client);
typedef int (*DvrDisplayManagerTranslateEpollEventMaskPtr)(
DvrDisplayManager* client, int in_events, int* out_events);
@@ -145,28 +162,45 @@
typedef void (*DvrBufferDestroyPtr)(DvrBuffer* buffer);
typedef int (*DvrBufferGetAHardwareBufferPtr)(
DvrBuffer* buffer, AHardwareBuffer** hardware_buffer);
+typedef int (*DvrBufferGlobalLayoutVersionGetPtr)();
typedef const struct native_handle* (*DvrBufferGetNativeHandlePtr)(
DvrBuffer* buffer);
// dvr_buffer_queue.h
+typedef int (*DvrWriteBufferQueueCreatePtr)(uint32_t width, uint32_t height,
+ uint32_t format,
+ uint32_t layer_count,
+ uint64_t usage, size_t capacity,
+ size_t metadata_size,
+ DvrWriteBufferQueue** queue_out);
typedef void (*DvrWriteBufferQueueDestroyPtr)(DvrWriteBufferQueue* write_queue);
typedef ssize_t (*DvrWriteBufferQueueGetCapacityPtr)(
DvrWriteBufferQueue* write_queue);
typedef int (*DvrWriteBufferQueueGetIdPtr)(DvrWriteBufferQueue* write_queue);
typedef int (*DvrWriteBufferQueueGetExternalSurfacePtr)(
DvrWriteBufferQueue* write_queue, ANativeWindow** out_window);
+typedef int (*DvrWriteBufferQueueGetANativeWindowPtr)(
+ DvrWriteBufferQueue* write_queue, ANativeWindow** out_window);
typedef int (*DvrWriteBufferQueueCreateReadQueuePtr)(
DvrWriteBufferQueue* write_queue, DvrReadBufferQueue** out_read_queue);
typedef int (*DvrWriteBufferQueueDequeuePtr)(DvrWriteBufferQueue* write_queue,
int timeout,
DvrWriteBuffer* out_buffer,
int* out_fence_fd);
+typedef int (*DvrWriteBufferQueueGainBufferPtr)(
+ DvrWriteBufferQueue* write_queue, int timeout,
+ DvrWriteBuffer** out_write_buffer, DvrNativeBufferMetadata* out_meta,
+ int* out_fence_fd);
+typedef int (*DvrWriteBufferQueuePostBufferPtr)(
+ DvrWriteBufferQueue* write_queue, DvrWriteBuffer* write_buffer,
+ const DvrNativeBufferMetadata* meta, int ready_fence_fd);
typedef int (*DvrWriteBufferQueueResizeBufferPtr)(
DvrWriteBufferQueue* write_queue, uint32_t width, uint32_t height);
typedef void (*DvrReadBufferQueueDestroyPtr)(DvrReadBufferQueue* read_queue);
typedef ssize_t (*DvrReadBufferQueueGetCapacityPtr)(
DvrReadBufferQueue* read_queue);
typedef int (*DvrReadBufferQueueGetIdPtr)(DvrReadBufferQueue* read_queue);
+typedef int (*DvrReadBufferQueueGetEventFdPtr)(DvrReadBufferQueue* read_queue);
typedef int (*DvrReadBufferQueueCreateReadQueuePtr)(
DvrReadBufferQueue* read_queue, DvrReadBufferQueue** out_read_queue);
typedef int (*DvrReadBufferQueueDequeuePtr)(DvrReadBufferQueue* read_queue,
@@ -174,6 +208,13 @@
DvrReadBuffer* out_buffer,
int* out_fence_fd, void* out_meta,
size_t meta_size_bytes);
+typedef int (*DvrReadBufferQueueAcquireBufferPtr)(
+ DvrReadBufferQueue* read_queue, int timeout,
+ DvrReadBuffer** out_read_buffer, DvrNativeBufferMetadata* out_meta,
+ int* out_fence_fd);
+typedef int (*DvrReadBufferQueueReleaseBufferPtr)(
+ DvrReadBufferQueue* read_queue, DvrReadBuffer* read_buffer,
+ const DvrNativeBufferMetadata* meta, int release_fence_fd);
typedef void (*DvrReadBufferQueueBufferAvailableCallback)(void* context);
typedef int (*DvrReadBufferQueueSetBufferAvailableCallbackPtr)(
DvrReadBufferQueue* read_queue,
@@ -187,6 +228,9 @@
DvrReadBufferQueue* read_queue);
// dvr_surface.h
+typedef int (*DvrSetupGlobalBufferPtr)(DvrGlobalBufferKey key, size_t size,
+ uint64_t usage, DvrBuffer** buffer_out);
+typedef int (*DvrDeleteGlobalBufferPtr)(DvrGlobalBufferKey key);
typedef int (*DvrGetGlobalBufferPtr)(DvrGlobalBufferKey key,
DvrBuffer** out_buffer);
typedef int (*DvrSurfaceCreatePtr)(const DvrSurfaceAttribute* attributes,
@@ -199,8 +243,10 @@
size_t attribute_count);
typedef int (*DvrSurfaceCreateWriteBufferQueuePtr)(
DvrSurface* surface, uint32_t width, uint32_t height, uint32_t format,
- uint32_t layer_count, uint64_t usage, size_t capacity,
+ uint32_t layer_count, uint64_t usage, size_t capacity, size_t metadata_size,
DvrWriteBufferQueue** queue_out);
+typedef int (*DvrGetNativeDisplayMetricsPtr)(size_t sizeof_metrics,
+ DvrNativeDisplayMetrics* metrics);
// dvr_vsync.h
typedef int (*DvrVSyncClientCreatePtr)(DvrVSyncClient** client_out);
@@ -220,6 +266,17 @@
int32_t controller_id,
uint32_t vsync_count,
DvrPoseAsync* out_pose);
+typedef int (*DvrPoseClientSensorsEnablePtr)(DvrPoseClient* client,
+ bool enabled);
+typedef int (*DvrPoseClientDataCapturePtr)(DvrPoseClient* client,
+ const DvrPoseDataCaptureRequest* request);
+typedef int (*DvrPoseClientDataReaderDestroyPtr)(DvrPoseClient* client,
+ uint64_t data_type);
+
+// dvr_pose.h
+typedef int (*DvrPoseClientGetDataReaderPtr)(DvrPoseClient* client,
+ uint64_t data_type,
+ DvrReadBufferQueue** read_queue);
// services/vr/virtual_touchpad/include/dvr/virtual_touchpad_client.h
@@ -237,6 +294,8 @@
float pressure);
typedef int (*DvrVirtualTouchpadButtonStatePtr)(DvrVirtualTouchpad* client,
int touchpad, int buttons);
+typedef int (*DvrVirtualTouchpadScrollPtr)(DvrVirtualTouchpad* client,
+ int touchpad, float x, float y);
// dvr_hardware_composer_client.h
typedef struct DvrHwcClient DvrHwcClient;
@@ -304,13 +363,34 @@
size_t layer_index,
size_t index);
+// dvr_performance.h
+typedef int (*DvrPerformanceSetSchedulerPolicyPtr)(
+ pid_t task_id, const char* scheduler_policy);
+
// The buffer metadata that an Android Surface (a.k.a. ANativeWindow)
// will populate. A DvrWriteBufferQueue must be created with this metadata iff
// ANativeWindow access is needed. Please do not remove, modify, or reorder
// existing data members. If new fields need to be added, please take extra care
// to make sure that new data field is padded properly the size of the struct
// stays same.
-struct DvrNativeBufferMetadata {
+struct ALIGNED_DVR_STRUCT(8) DvrNativeBufferMetadata {
+#ifdef __cplusplus
+ DvrNativeBufferMetadata()
+ : timestamp(0),
+ is_auto_timestamp(0),
+ dataspace(0),
+ crop_left(0),
+ crop_top(0),
+ crop_right(0),
+ crop_bottom(0),
+ scaling_mode(0),
+ transform(0),
+ index(0),
+ user_metadata_size(0),
+ user_metadata_ptr(0),
+ release_fence_mask(0),
+ reserved{0} {}
+#endif
// Timestamp of the frame.
int64_t timestamp;
@@ -334,10 +414,32 @@
// android/native_window.h
int32_t transform;
- // Reserved bytes for so that the struct is forward compatible.
- int32_t reserved[16];
+ // The index of the frame.
+ int64_t index;
+
+ // Size of additional metadata requested by user.
+ uint64_t user_metadata_size;
+
+ // Raw memory address of the additional user defined metadata. Only valid when
+ // user_metadata_size is non-zero.
+ uint64_t user_metadata_ptr;
+
+ // Only applicable for metadata retrieved from GainAsync. This indicates which
+ // consumer has pending fence that producer should epoll on.
+ uint64_t release_fence_mask;
+
+ // Reserved bytes for so that the struct is forward compatible and padding to
+ // 104 bytes so the size is a multiple of 8.
+ int32_t reserved[8];
};
+#ifdef __cplusplus
+// Warning: DvrNativeBufferMetadata is part of the DVR API and changing its size
+// will cause compatiblity issues between different DVR API releases.
+static_assert(sizeof(DvrNativeBufferMetadata) == 104,
+ "Unexpected size for DvrNativeBufferMetadata");
+#endif
+
struct DvrApi_v1 {
// Defines an API entry for V1 (no version suffix).
#define DVR_V1_API_ENTRY(name) Dvr##name##Ptr name
diff --git a/libs/vr/libdvr/include/dvr/dvr_api_entries.h b/libs/vr/libdvr/include/dvr/dvr_api_entries.h
index 8cdad7d..cce8c7e 100644
--- a/libs/vr/libdvr/include/dvr/dvr_api_entries.h
+++ b/libs/vr/libdvr/include/dvr/dvr_api_entries.h
@@ -12,7 +12,6 @@
// Display manager client
DVR_V1_API_ENTRY(DisplayManagerCreate);
DVR_V1_API_ENTRY(DisplayManagerDestroy);
-DVR_V1_API_ENTRY(DisplayManagerSetupGlobalBuffer);
DVR_V1_API_ENTRY(DisplayManagerGetEventFd);
DVR_V1_API_ENTRY(DisplayManagerTranslateEpollEventMask);
DVR_V1_API_ENTRY(DisplayManagerGetSurfaceState);
@@ -60,12 +59,13 @@
DVR_V1_API_ENTRY(BufferDestroy);
DVR_V1_API_ENTRY(BufferGetAHardwareBuffer);
DVR_V1_API_ENTRY(BufferGetNativeHandle);
+DVR_V1_API_ENTRY(BufferGlobalLayoutVersionGet);
// Write buffer queue
DVR_V1_API_ENTRY(WriteBufferQueueDestroy);
DVR_V1_API_ENTRY(WriteBufferQueueGetCapacity);
DVR_V1_API_ENTRY(WriteBufferQueueGetId);
-DVR_V1_API_ENTRY(WriteBufferQueueGetExternalSurface);
+DVR_V1_API_ENTRY(WriteBufferQueueGetExternalSurface); // deprecated
DVR_V1_API_ENTRY(WriteBufferQueueCreateReadQueue);
DVR_V1_API_ENTRY(WriteBufferQueueDequeue);
DVR_V1_API_ENTRY(WriteBufferQueueResizeBuffer);
@@ -91,6 +91,8 @@
DVR_V1_API_ENTRY(SurfaceGetId);
DVR_V1_API_ENTRY(SurfaceSetAttributes);
DVR_V1_API_ENTRY(SurfaceCreateWriteBufferQueue);
+DVR_V1_API_ENTRY(SetupGlobalBuffer);
+DVR_V1_API_ENTRY(DeleteGlobalBuffer);
DVR_V1_API_ENTRY(GetGlobalBuffer);
// Pose client
@@ -140,3 +142,38 @@
DVR_V1_API_ENTRY(HwcFrameGetLayerVisibleRegion);
DVR_V1_API_ENTRY(HwcFrameGetLayerNumDamagedRegions);
DVR_V1_API_ENTRY(HwcFrameGetLayerDamagedRegion);
+
+// New entries added at the end to allow the DVR platform library API
+// to be updated before updating VrCore.
+
+// Virtual touchpad client
+DVR_V1_API_ENTRY(VirtualTouchpadScroll);
+
+// Read the native display metrics from the hardware composer
+DVR_V1_API_ENTRY(GetNativeDisplayMetrics);
+
+// Performance
+DVR_V1_API_ENTRY(PerformanceSetSchedulerPolicy);
+
+// Pose client
+DVR_V1_API_ENTRY(PoseClientSensorsEnable);
+
+// Read buffer queue
+DVR_V1_API_ENTRY(ReadBufferQueueGetEventFd);
+
+// Create write buffer queue locally
+DVR_V1_API_ENTRY(WriteBufferQueueCreate);
+
+// Gets an ANativeWindow from DvrWriteBufferQueue.
+DVR_V1_API_ENTRY(WriteBufferQueueGetANativeWindow);
+
+// Dvr{Read,Write}BufferQueue API for asynchronous IPC.
+DVR_V1_API_ENTRY(WriteBufferQueueGainBuffer);
+DVR_V1_API_ENTRY(WriteBufferQueuePostBuffer);
+DVR_V1_API_ENTRY(ReadBufferQueueAcquireBuffer);
+DVR_V1_API_ENTRY(ReadBufferQueueReleaseBuffer);
+
+// Pose client
+DVR_V1_API_ENTRY(PoseClientGetDataReader);
+DVR_V1_API_ENTRY(PoseClientDataCapture);
+DVR_V1_API_ENTRY(PoseClientDataReaderDestroy);
diff --git a/libs/vr/libdvr/include/dvr/dvr_buffer.h b/libs/vr/libdvr/include/dvr/dvr_buffer.h
index af55698..935a7b2 100644
--- a/libs/vr/libdvr/include/dvr/dvr_buffer.h
+++ b/libs/vr/libdvr/include/dvr/dvr_buffer.h
@@ -95,6 +95,9 @@
int dvrBufferGetAHardwareBuffer(DvrBuffer* buffer,
AHardwareBuffer** hardware_buffer);
+// Retrieve the shared buffer layout version defined in dvr_shared_buffers.h.
+int dvrBufferGlobalLayoutVersionGet();
+
// TODO(eieio): Switch to return int and take an out parameter for the native
// handle.
const struct native_handle* dvrBufferGetNativeHandle(DvrBuffer* buffer);
diff --git a/libs/vr/libdvr/include/dvr/dvr_buffer_queue.h b/libs/vr/libdvr/include/dvr/dvr_buffer_queue.h
index caf208d..bf695c7 100644
--- a/libs/vr/libdvr/include/dvr/dvr_buffer_queue.h
+++ b/libs/vr/libdvr/include/dvr/dvr_buffer_queue.h
@@ -12,6 +12,36 @@
typedef struct DvrWriteBufferQueue DvrWriteBufferQueue;
typedef struct DvrReadBufferQueue DvrReadBufferQueue;
+// Creates a write buffer queue to be used locally.
+//
+// Note that this API is mostly for testing purpose. For now there is no
+// mechanism to send a DvrWriteBufferQueue cross process. Use
+// dvrSurfaceCreateWriteBufferQueue if cross-process buffer transport is
+// intended.
+//
+// @param width The width of the buffers that this queue will produce.
+// @param height The height of buffers that this queue will produce.
+// @param format The format of the buffers that this queue will produce. This
+// must be one of the AHARDWAREBUFFER_FORMAT_XXX enums.
+// @param layer_count The number of layers of the buffers that this queue will
+// produce.
+// @param usage The usage of the buffers that this queue will produce. This
+// must a combination of the AHARDWAREBUFFER_USAGE_XXX flags.
+// @param capacity The number of buffer that this queue will allocate. Note that
+// all buffers will be allocated on create. Currently, the number of buffers
+// is the queue cannot be changed after creation though DVR API. However,
+// ANativeWindow can choose to reallocate, attach, or detach buffers from
+// a DvrWriteBufferQueue through Android platform logic.
+// @param metadata_size The size of metadata in bytes.
+// @param out_write_queue The pointer of a DvrWriteBufferQueue will be filled
+// here if the method call succeeds. The metadata size must match
+// the metadata size in dvrWriteBufferPost/dvrReadBufferAcquire.
+// @return Zero on success, or negative error code.
+int dvrWriteBufferQueueCreate(uint32_t width, uint32_t height, uint32_t format,
+ uint32_t layer_count, uint64_t usage,
+ size_t capacity, size_t metadata_size,
+ DvrWriteBufferQueue** out_write_queue);
+
// Destroy a write buffer queue.
//
// @param write_queue The DvrWriteBufferQueue of interest.
@@ -43,6 +73,10 @@
// the method call succeeds.
// @return Zero on success; or -EINVAL if this DvrWriteBufferQueue does not
// support being used as an android Surface.
+int dvrWriteBufferQueueGetANativeWindow(DvrWriteBufferQueue* write_queue,
+ ANativeWindow** out_window);
+
+// @deprecated Please use dvrWriteBufferQueueGetANativeWindow instead.
int dvrWriteBufferQueueGetExternalSurface(DvrWriteBufferQueue* write_queue,
ANativeWindow** out_window);
@@ -55,21 +89,44 @@
int dvrWriteBufferQueueCreateReadQueue(DvrWriteBufferQueue* write_queue,
DvrReadBufferQueue** out_read_queue);
-// Dequeue a buffer to write into.
+// @deprecated Please use dvrWriteBufferQueueGainBuffer instead.
+int dvrWriteBufferQueueDequeue(DvrWriteBufferQueue* write_queue, int timeout,
+ DvrWriteBuffer* out_buffer, int* out_fence_fd);
+
+// Gains a buffer to write into.
//
-// @param write_queue The DvrWriteBufferQueue of interest.
+// @param write_queue The DvrWriteBufferQueue to gain buffer from.
// @param timeout Specifies the number of milliseconds that the method will
// block. Specifying a timeout of -1 causes it to block indefinitely,
// while specifying a timeout equal to zero cause it to return immediately,
// even if no buffers are available.
// @param out_buffer A targeting DvrWriteBuffer object to hold the output of the
-// dequeue operation. Must be created by |dvrWriteBufferCreateEmpty|.
+// dequeue operation.
+// @param out_meta A DvrNativeBufferMetadata object populated by the
+// corresponding dvrReadBufferQueueReleaseBuffer API.
// @param out_fence_fd A sync fence fd defined in NDK's sync.h API, which
// signals the release of underlying buffer. The producer should wait until
// this fence clears before writing data into it.
// @return Zero on success, or negative error code.
-int dvrWriteBufferQueueDequeue(DvrWriteBufferQueue* write_queue, int timeout,
- DvrWriteBuffer* out_buffer, int* out_fence_fd);
+int dvrWriteBufferQueueGainBuffer(DvrWriteBufferQueue* write_queue, int timeout,
+ DvrWriteBuffer** out_write_buffer,
+ DvrNativeBufferMetadata* out_meta,
+ int* out_fence_fd);
+
+// Posts a buffer and signals its readiness to be read from.
+//
+// @param write_queue The DvrWriteBufferQueue to post buffer into.
+// @param write_buffer The buffer to be posted.
+// @param meta The buffer metadata describing the buffer.
+// @param ready_fence_fd A sync fence fd defined in NDK's sync.h API, which
+// signals the readdiness of underlying buffer. When a valid fence gets
+// passed in, the consumer will wait the fence to be ready before it starts
+// to ready from the buffer.
+// @return Zero on success, or negative error code.
+int dvrWriteBufferQueuePostBuffer(DvrWriteBufferQueue* write_queue,
+ DvrWriteBuffer* write_buffer,
+ const DvrNativeBufferMetadata* meta,
+ int ready_fence_fd);
// Overrides buffer dimension with new width and height.
//
@@ -102,6 +159,14 @@
// @return Queue id on success; or negative error code.
int dvrReadBufferQueueGetId(DvrReadBufferQueue* read_queue);
+// Get the event fd that signals when queue updates occur.
+//
+// Use ReadBufferQueueHandleEvents to trigger registered event callbacks.
+//
+// @param read_queue The DvrReadBufferQueue of interest.
+// @return Fd on success; or negative error code.
+int dvrReadBufferQueueGetEventFd(DvrReadBufferQueue* read_queue);
+
// Create a read buffer queue from an existing read buffer queue.
//
// @param read_queue The DvrReadBufferQueue of interest.
@@ -111,26 +176,45 @@
int dvrReadBufferQueueCreateReadQueue(DvrReadBufferQueue* read_queue,
DvrReadBufferQueue** out_read_queue);
-// Dequeue a buffer to read from.
+// @deprecated Please use dvrReadBufferQueueAcquireBuffer instead.
+int dvrReadBufferQueueDequeue(DvrReadBufferQueue* read_queue, int timeout,
+ DvrReadBuffer* out_buffer, int* out_fence_fd,
+ void* out_meta, size_t meta_size_bytes);
+
+// Dequeues a buffer to read from.
//
-// @param read_queue The DvrReadBufferQueue of interest.
+// @param read_queue The DvrReadBufferQueue to acquire buffer from.
// @param timeout Specifies the number of milliseconds that the method will
// block. Specifying a timeout of -1 causes it to block indefinitely,
// while specifying a timeout equal to zero cause it to return immediately,
// even if no buffers are available.
// @param out_buffer A targeting DvrReadBuffer object to hold the output of the
// dequeue operation. Must be created by |dvrReadBufferCreateEmpty|.
+// @param out_meta A DvrNativeBufferMetadata object populated by the
+// corresponding dvrWriteBufferQueuePostBuffer API.
// @param out_fence_fd A sync fence fd defined in NDK's sync.h API, which
// signals the release of underlying buffer. The consumer should wait until
// this fence clears before reading data from it.
-// @param out_meta The memory area where a metadata object will be filled.
-// @param meta_size_bytes Size of the metadata object caller expects. If it
-// doesn't match the size of actually metadata transported by the buffer
-// queue, the method returns -EINVAL.
// @return Zero on success, or negative error code.
-int dvrReadBufferQueueDequeue(DvrReadBufferQueue* read_queue, int timeout,
- DvrReadBuffer* out_buffer, int* out_fence_fd,
- void* out_meta, size_t meta_size_bytes);
+int dvrReadBufferQueueAcquireBuffer(DvrReadBufferQueue* read_queue, int timeout,
+ DvrReadBuffer** out_read_buffer,
+ DvrNativeBufferMetadata* out_meta,
+ int* out_fence_fd);
+
+// Releases a buffer and signals its readiness to be written into.
+//
+// @param read_queue The DvrReadBufferQueue to release buffer into.
+// @param read_buffer The buffer to be released.
+// @param meta The buffer metadata describing the buffer.
+// @param release_fence_fd A sync fence fd defined in NDK's sync.h API, which
+// signals the readdiness of underlying buffer. When a valid fence gets
+// passed in, the producer will wait the fence to be ready before it starts
+// to write into the buffer again.
+// @return Zero on success, or negative error code.
+int dvrReadBufferQueueReleaseBuffer(DvrReadBufferQueue* read_queue,
+ DvrReadBuffer* read_buffer,
+ const DvrNativeBufferMetadata* meta,
+ int release_fence_fd);
// Callback function which will be called when a buffer is avaiable.
//
diff --git a/libs/vr/libdvr/include/dvr/dvr_vrflinger_config.h b/libs/vr/libdvr/include/dvr/dvr_config.h
similarity index 74%
rename from libs/vr/libdvr/include/dvr/dvr_vrflinger_config.h
rename to libs/vr/libdvr/include/dvr/dvr_config.h
index cfe9d62..3d2c066 100644
--- a/libs/vr/libdvr/include/dvr/dvr_vrflinger_config.h
+++ b/libs/vr/libdvr/include/dvr/dvr_config.h
@@ -1,17 +1,18 @@
-#ifndef ANDROID_DVR_VRFLINGER_CONFIG_H
-#define ANDROID_DVR_VRFLINGER_CONFIG_H
+#ifndef ANDROID_DVR_CONFIG_H
+#define ANDROID_DVR_CONFIG_H
// This header is shared by VrCore and Android and must be kept in sync.
+#include <stdint.h>
#include <sys/cdefs.h>
__BEGIN_DECLS
// This is a shared memory buffer for passing config data from VrCore to
// libvrflinger in SurfaceFlinger.
-struct DvrVrFlingerConfig {
+struct __attribute__((packed, aligned(16))) DvrConfig {
// Offset before vsync to submit frames to hardware composer.
- int frame_post_offset_ns{4000000};
+ int32_t frame_post_offset_ns{4000000};
// If the number of pending fences goes over this count at the point when we
// are about to submit a new frame to HWC, we will drop the frame. This
@@ -20,11 +21,14 @@
// the next vsync, at the point when the DMA to the display completes.
// Currently we use a smart display and the EDS timing coincides with zero
// pending fences, so this is 0.
- size_t allowed_pending_fence_count{0};
+ int32_t allowed_pending_fence_count{0};
// New fields should always be added to the end for backwards compat.
+
+ // Reserved padding to 16 bytes.
+ uint8_t pad[8];
};
__END_DECLS
-#endif // ANDROID_DVR_VRFLINGER_CONFIG_H
+#endif // ANDROID_DVR_CONFIG_H
diff --git a/libs/vr/libdvr/include/dvr/dvr_display_manager.h b/libs/vr/libdvr/include/dvr/dvr_display_manager.h
index 26f85a0..f910d61 100644
--- a/libs/vr/libdvr/include/dvr/dvr_display_manager.h
+++ b/libs/vr/libdvr/include/dvr/dvr_display_manager.h
@@ -25,21 +25,6 @@
// Destroys the display manager client object.
void dvrDisplayManagerDestroy(DvrDisplayManager* client);
-// Sets up a named buffer for shared memory data transfer between display
-// clients and the display manager.
-// @return 0 on success. Otherwise returns a negative error value.
-int dvrDisplayManagerSetupGlobalBuffer(DvrDisplayManager* client,
- DvrGlobalBufferKey key, size_t size,
- uint64_t usage, DvrBuffer** buffer_out);
-
-// Deletes a named buffer. WARNING: This is dangerous because any existing
-// clients of this buffer will not be notified and will remain attached to
-// the old buffer. This is useful for tests, but probably not for production
-// code.
-// @return 0 on success. Otherwise returns a negative error value.
-int dvrDisplayManagerDeleteGlobalBuffer(DvrDisplayManager* client,
- DvrGlobalBufferKey key);
-
// Returns an fd used to signal when surface updates occur. Note that depending
// on the underlying transport, only a subset of the real event bits may be
// supported. Use dvrDisplayManagerClientTranslateEpollEventMask to get the real
diff --git a/libs/vr/libdvr/include/dvr/dvr_display_types.h b/libs/vr/libdvr/include/dvr/dvr_display_types.h
index 25364d8..fd69843 100644
--- a/libs/vr/libdvr/include/dvr/dvr_display_types.h
+++ b/libs/vr/libdvr/include/dvr/dvr_display_types.h
@@ -13,7 +13,7 @@
#ifndef __FLOAT32X4T_86
#define __FLOAT32X4T_86
typedef float float32x4_t __attribute__((__vector_size__(16)));
-typedef struct float32x4x4_t { float32x4_t val[4]; };
+typedef struct float32x4x4_t { float32x4_t val[4]; } float32x4x4_t;
#endif
#endif
diff --git a/libs/vr/libdvr/include/dvr/dvr_hardware_composer_client.h b/libs/vr/libdvr/include/dvr/dvr_hardware_composer_client.h
index 60e22de..0ba76e2 100644
--- a/libs/vr/libdvr/include/dvr/dvr_hardware_composer_client.h
+++ b/libs/vr/libdvr/include/dvr/dvr_hardware_composer_client.h
@@ -24,37 +24,73 @@
DvrHwcClient* dvrHwcClientCreate(DvrHwcOnFrameCallback callback,
void* client_state);
+// Called to free the DvrHwcClient pointer.
void dvrHwcClientDestroy(DvrHwcClient* client);
// Called to free the frame information.
+// @param frame Pointer for the valid frame used for the query.
void dvrHwcFrameDestroy(DvrHwcFrame* frame);
+// @param frame Pointer for the valid frame used for the query.
+// @return Identifier for the display associated by the frame.
DvrHwcDisplay dvrHwcFrameGetDisplayId(DvrHwcFrame* frame);
+// @param frame Pointer for the valid frame used for the query.
+// @return width of the physical display associated with |frame|. This does not
+// take into account any orientation changes.
int32_t dvrHwcFrameGetDisplayWidth(DvrHwcFrame* frame);
+// @param frame Pointer for the valid frame used for the query.
+// @return height of the physical display associated with |frame|. This does not
+// take into account any orientation changes.
int32_t dvrHwcFrameGetDisplayHeight(DvrHwcFrame* frame);
+// @param frame Pointer for the valid frame used for the query.
// @return True if the display has been removed. In this case the current frame
// does not contain any valid layers to display. It is a signal to clean up any
// display related state.
bool dvrHwcFrameGetDisplayRemoved(DvrHwcFrame* frame);
+// @param frame Pointer for the valid frame used for the query.
// @return Number of layers in the frame.
size_t dvrHwcFrameGetLayerCount(DvrHwcFrame* frame);
+// @param frame Pointer for the valid frame used for the query.
+// @return The ID of the currently active display configuration.
uint32_t dvrHwcFrameGetActiveConfig(DvrHwcFrame* frame);
+
+// @param frame Pointer for the valid frame used for the query.
+// @return The ID of the current color mode. See HAL_COLOR_MODE_* for valid
+// values.
uint32_t dvrHwcFrameGetColorMode(DvrHwcFrame* frame);
+
+// @param frame Pointer for the valid frame used for the query.
+// @param out_matrix Output parameter for a float[16] array which will be filled
+// with the color transform matrix.
+// @param out_hint Output parameter which will contain the color transform hint.
+// See HAL_COLOR_TRANSFORM_* for valid values.
void dvrHwcFrameGetColorTransform(DvrHwcFrame* frame, float* out_matrix,
int32_t* out_hint);
+
+// @param frame Pointer for the valid frame used for the query.
+// @return The current power mode for the display. See HWC2_POWER_MODE_* for
+// valid values.
uint32_t dvrHwcFrameGetPowerMode(DvrHwcFrame* frame);
+
+// @param frame Pointer for the valid frame used for the query.
+// @return The current state of vsync. See HWC2_VSYNC_* for valid values.
uint32_t dvrHwcFrameGetVsyncEnabled(DvrHwcFrame* frame);
+// @param frame Pointer for the valid frame used for the query.
+// @param layer_index The index of the layer in the frame.
+// @return A unique ID for the layer.
DvrHwcLayer dvrHwcFrameGetLayerId(DvrHwcFrame* frame, size_t layer_index);
// Return the graphic buffer associated with the layer at |layer_index| in
// |frame|.
//
+// @param frame Pointer for the valid frame used for the query.
+// @param layer_index The index of the layer in the frame.
// @return Graphic buffer. Caller owns the buffer and is responsible for freeing
// it. (see AHardwareBuffer_release())
AHardwareBuffer* dvrHwcFrameGetLayerBuffer(DvrHwcFrame* frame,
@@ -62,42 +98,98 @@
// Returns the fence FD for the layer at index |layer_index| in |frame|.
//
+// @param frame Pointer for the valid frame used for the query.
+// @param layer_index The index of the layer in the frame.
// @return Fence FD. Caller owns the FD and is responsible for closing it.
int dvrHwcFrameGetLayerFence(DvrHwcFrame* frame, size_t layer_index);
+// @param frame Pointer for the valid frame used for the query.
+// @param layer_index The index of the layer in the frame.
+// @return describing the portion of the display covered by the layer. Will
+// not exceed the display dimensions.
DvrHwcRecti dvrHwcFrameGetLayerDisplayFrame(DvrHwcFrame* frame,
size_t layer_index);
+// @param frame Pointer for the valid frame used for the query.
+// @param layer_index The index of the layer in the frame.
+// @return describing the portion of the layer that will fill the display
+// frame. Will not exceed the layer dimensions.
DvrHwcRectf dvrHwcFrameGetLayerCrop(DvrHwcFrame* frame, size_t layer_index);
+// @param frame Pointer for the valid frame used for the query.
+// @param layer_index The index of the layer in the frame.
+// @return The blend mode of the layer.
DvrHwcBlendMode dvrHwcFrameGetLayerBlendMode(DvrHwcFrame* frame,
size_t layer_index);
+// @param frame Pointer for the valid frame used for the query.
+// @param layer_index The index of the layer in the frame.
+// @return The alpha value to be applied to the whole layer. Will be in the
+// [0.0, 1.0] range.
float dvrHwcFrameGetLayerAlpha(DvrHwcFrame* frame, size_t layer_index);
+// @param frame Pointer for the valid frame used for the query.
+// @param layer_index The index of the layer in the frame.
+// @return The type of the layer assigned by the window manager.
uint32_t dvrHwcFrameGetLayerType(DvrHwcFrame* frame, size_t layer_index);
+// @param frame Pointer for the valid frame used for the query.
+// @param layer_index The index of the layer in the frame.
+// @return The application id the layer belongs to.
uint32_t dvrHwcFrameGetLayerApplicationId(DvrHwcFrame* frame,
size_t layer_index);
+// @param frame Pointer for the valid frame used for the query.
+// @param layer_index The index of the layer in the frame.
+// @return The z-order for the layer.
uint32_t dvrHwcFrameGetLayerZOrder(DvrHwcFrame* frame, size_t layer_index);
+// @param frame Pointer for the valid frame used for the query.
+// @param layer_index The index of the layer in the frame.
+// @param out_x Output parameter for the x coordinate of the cursor location.
+// @param out_y Output parameter for the y coordinate of the cursor location.
void dvrHwcFrameGetLayerCursor(DvrHwcFrame* frame, size_t layer_index,
int32_t* out_x, int32_t* out_y);
+// @param frame Pointer for the valid frame used for the query.
+// @param layer_index The index of the layer in the frame.
+// @return The transformation that needs to be applied to the layer before
+// presenting it. See DVR_HWC_TRANSFORM_* for valid values.
uint32_t dvrHwcFrameGetLayerTransform(DvrHwcFrame* frame, size_t layer_index);
+// @param frame Pointer for the valid frame used for the query.
+// @param layer_index The index of the layer in the frame.
+// @return The dataspace which represents how the pixel values should be
+// interpreted. See HAL_DATASPACE_* for valid values.
uint32_t dvrHwcFrameGetLayerDataspace(DvrHwcFrame* frame, size_t layer_index);
+// @param frame Pointer for the valid frame used for the query.
+// @param layer_index The index of the layer in the frame.
+// @return The color of the layer if layer composition is SOLID_COLOR.
uint32_t dvrHwcFrameGetLayerColor(DvrHwcFrame* frame, size_t layer_index);
+// @param frame Pointer for the valid frame used for the query.
+// @param layer_index The index of the layer in the frame.
+// @return The number of visible regions.
uint32_t dvrHwcFrameGetLayerNumVisibleRegions(DvrHwcFrame* frame,
size_t layer_index);
+// @param frame Pointer for the valid frame used for the query.
+// @param layer_index The index of the layer in the frame.
+// @param index The index of the visible region for the layer.
+// @return The rectangle describing the visible region.
DvrHwcRecti dvrHwcFrameGetLayerVisibleRegion(DvrHwcFrame* frame,
size_t layer_index, size_t index);
+// @param frame Pointer for the valid frame used for the query.
+// @param layer_index The index of the layer in the frame.
+// @return The number of damanged regions.
uint32_t dvrHwcFrameGetLayerNumDamagedRegions(DvrHwcFrame* frame,
size_t layer_index);
+
+// @param frame Pointer for the valid frame used for the query.
+// @param layer_index The index of the layer in the frame.
+// @param index The index of the damanged region for the layer.
+// @return The rectangle describing the damaged region.
DvrHwcRecti dvrHwcFrameGetLayerDamagedRegion(DvrHwcFrame* frame,
size_t layer_index, size_t index);
#ifdef __cplusplus
diff --git a/libs/vr/libdvr/include/dvr/dvr_hardware_composer_types.h b/libs/vr/libdvr/include/dvr/dvr_hardware_composer_types.h
index 36c30f9..1d5eda6 100644
--- a/libs/vr/libdvr/include/dvr/dvr_hardware_composer_types.h
+++ b/libs/vr/libdvr/include/dvr/dvr_hardware_composer_types.h
@@ -26,6 +26,15 @@
DVR_HWC_COMPOSITION_SIDEBAND = 5,
};
+enum DvrHwcTransform {
+ DVR_HWC_TRANSFORM_NONE = 0,
+ DVR_HWC_TRANSFORM_FLIP_H = 1,
+ DVR_HWC_TRANSFORM_FLIP_V = 2,
+ DVR_HWC_TRANSFORM_ROT_90 = 4,
+ DVR_HWC_TRANSFORM_ROT_180 = 3,
+ DVR_HWC_TRANSFORM_ROT_270 = 7,
+};
+
typedef uint64_t DvrHwcDisplay;
typedef uint64_t DvrHwcLayer;
diff --git a/libs/vr/libdvr/include/dvr/dvr_performance.h b/libs/vr/libdvr/include/dvr/dvr_performance.h
new file mode 100644
index 0000000..5df35ad
--- /dev/null
+++ b/libs/vr/libdvr/include/dvr/dvr_performance.h
@@ -0,0 +1,26 @@
+#ifndef ANDROID_DVR_PERFORMANCE_H_
+#define ANDROID_DVR_PERFORMANCE_H_
+
+#include <stddef.h>
+#include <unistd.h>
+
+__BEGIN_DECLS
+
+/// Sets the scheduler policy for a task.
+///
+/// Sets the scheduler policy for a task to the class described by a semantic
+/// string.
+///
+/// Supported policies are device-specific.
+///
+/// @param task_id The task id of task to set the policy for. When task_id is 0
+/// the current task id is substituted.
+/// @param scheduler_policy NULL-terminated ASCII string containing the desired
+/// scheduler policy.
+/// @returns Returns 0 on success or a negative errno error code on error.
+int dvrPerformanceSetSchedulerPolicy(pid_t task_id, const char* scheduler_policy);
+
+__END_DECLS
+
+#endif // ANDROID_DVR_PERFORMANCE_H_
+
diff --git a/libs/vr/libdvr/include/dvr/dvr_pose.h b/libs/vr/libdvr/include/dvr/dvr_pose.h
index a7e83c9..8752751 100644
--- a/libs/vr/libdvr/include/dvr/dvr_pose.h
+++ b/libs/vr/libdvr/include/dvr/dvr_pose.h
@@ -15,6 +15,9 @@
#endif
#endif
+typedef struct DvrPoseClient DvrPoseClient;
+typedef struct DvrReadBufferQueue DvrReadBufferQueue;
+
// Represents an estimated pose, accessed asynchronously through a shared ring
// buffer. No assumptions should be made about the data in padding space.
// The size of this struct is 128 bytes.
@@ -36,16 +39,31 @@
int64_t timestamp_ns;
// Bitmask of DVR_POSE_FLAG_* constants that apply to this pose.
//
- // If DVR_POSE_FLAG_VALID is not set, the pose is indeterminate.
+ // If DVR_POSE_FLAG_INVALID is set, the pose is indeterminate.
uint64_t flags;
// Reserved padding to 128 bytes.
uint8_t pad[16];
} DvrPoseAsync;
enum {
- DVR_POSE_FLAG_VALID = (1UL << 0), // This pose is valid.
- DVR_POSE_FLAG_HEAD = (1UL << 1), // This pose is the head.
- DVR_POSE_FLAG_CONTROLLER = (1UL << 2), // This pose is a controller.
+ DVR_POSE_FLAG_INVALID = (1ULL << 0), // This pose is invalid.
+ DVR_POSE_FLAG_INITIALIZING = (1ULL << 1), // The pose delivered during
+ // initialization and it may not be
+ // correct.
+ DVR_POSE_FLAG_3DOF =
+ (1ULL << 2), // This pose is derived from 3Dof sensors. If
+ // this is not set, pose is derived using
+ // 3Dof and 6Dof sensors.
+ DVR_POSE_FLAG_FLOOR_HEIGHT_INVALID =
+ (1ULL << 3), // If set the floor height is invalid.
+
+ // Bits that indicate the tracking system state.
+ DVR_POSE_FLAG_SERVICE_EXCEPTION = (1ULL << 32),
+ DVR_POSE_FLAG_FISHEYE_OVER_EXPOSED = (1ULL << 33),
+ DVR_POSE_FLAG_FISHEYE_UNDER_EXPOSED = (1ULL << 34),
+ DVR_POSE_FLAG_COLOR_OVER_EXPOSED = (1ULL << 35),
+ DVR_POSE_FLAG_COLOR_UNDER_EXPOSED = (1ULL << 36),
+ DVR_POSE_FLAG_TOO_FEW_FEATURES_TRACKED = (1ULL << 37)
};
// Represents a sensor pose sample.
@@ -70,10 +88,67 @@
// Timestamp for the measurement in nanoseconds.
int64_t timestamp_ns;
- // Padding to 96 bytes so the size is a multiple of 16.
- uint8_t padding[8];
+ // The combination of flags above.
+ uint64_t flags;
+
+ // The current floor height. May be updated at a lower cadence than pose.
+ float floor_height;
+
+ // Padding to 112 bytes so the size is a multiple of 16.
+ uint8_t padding[12];
} DvrPose;
+// Represents a data type that can be streamed from pose service.
+enum {
+ DVR_POSE_RAW_DATA_STEREO_IMAGE = (1ULL << 0),
+ DVR_POSE_RAW_DATA_POINT_CLOUD = (1ULL << 1),
+ DVR_POSE_RAW_DATA_FEATURES = (1ULL << 2),
+
+ // Always last.
+ DVR_POSE_RAW_DATA_COUNT = (1ULL << 3),
+};
+
+// A request to retrieve data from the pose service. Expects that a buffer
+// queue has been initialized through dvrPoseClientGetDataReader().
+typedef struct DvrPoseDataCaptureRequest {
+ // The type of data to capture. Refer to enum DVR_POSE_RAW_DATA_* for types.
+ uint64_t data_type;
+ // The sample interval. This can be used to skip samples. For example, a
+ // value of 5 will capture every fifth frame and discard the 4 frames in
+ // between. Set to 1 to capture all frames.
+ uint32_t sample_interval;
+ // The length of time to capture samples in milliseconds. Set to 0 to capture
+ // indefinitely.
+ uint32_t capture_time_ms;
+ // Reserved fields.
+ uint32_t reserved0;
+ uint32_t reserved1;
+ uint32_t reserved2;
+ uint32_t reserved3;
+ uint32_t reserved4;
+} DvrPoseDataCaptureRequest;
+
+// Gets a read buffer queue for the data type |data_type|. Each call returns a
+// different read buffer queue connected to the same write buffer queue. A
+// separate write buffer queue exists for each |data_type|.
+//
+// PoseService supports a single consumer per write buffer queue. The consumer
+// is expected to hold a single DvrReadBufferQueue at a time. Callers should
+// cache these instead of requesting new ones when possible. If the consumer
+// disconnects from the queue, it can regain a read buffer queue for the same
+// producer by calling this function.
+//
+// For data_type DVR_POSE_RAW_DATA_STEREO_IMAGE, each buffer consists of two
+// images formatted as a AHARDWAREBUFFER_FORMAT_BLOB, where height is 1 and
+// width is the total size of both images. The size of an individual image can
+// be found in the metadata struct DvrNativeBufferMetadata, where width is
+// |crop_right| and height is |crop_bottom|/2. Each image is contiguous in
+// memory with stride equal to width.
+int dvrPoseClientGetDataReader(DvrPoseClient* client, uint64_t data_type,
+ DvrReadBufferQueue** queue_out);
+
+// TODO(b/65067592): Move pose api's from pose_client.h to here.
+
__END_DECLS
#endif // ANDROID_DVR_PUBLIC_POSE_H_
diff --git a/libs/vr/libdvr/include/dvr/dvr_shared_buffers.h b/libs/vr/libdvr/include/dvr/dvr_shared_buffers.h
index ce17f0c..63c7385 100644
--- a/libs/vr/libdvr/include/dvr/dvr_shared_buffers.h
+++ b/libs/vr/libdvr/include/dvr/dvr_shared_buffers.h
@@ -1,8 +1,8 @@
#ifndef ANDROID_DVR_SHARED_BUFFERS_H_
#define ANDROID_DVR_SHARED_BUFFERS_H_
+#include <dvr/dvr_config.h>
#include <dvr/dvr_pose.h>
-#include <dvr/dvr_vrflinger_config.h>
#include <dvr/dvr_vsync.h>
#include <libbroadcastring/broadcast_ring.h>
@@ -11,7 +11,7 @@
namespace dvr {
// Increment when the layout for the buffers change.
-constexpr uint32_t kSharedBufferLayoutVersion = 1;
+enum : uint32_t { kSharedBufferLayoutVersion = 2 };
// Note: These buffers will be mapped from various system processes as well
// as VrCore and the application processes in a r/w manner.
@@ -24,8 +24,9 @@
// Sanity check for basic type sizes.
static_assert(sizeof(DvrPoseAsync) == 128, "Unexpected size for DvrPoseAsync");
-static_assert(sizeof(DvrPose) == 96, "Unexpected size for DvrPose");
+static_assert(sizeof(DvrPose) == 112, "Unexpected size for DvrPose");
static_assert(sizeof(DvrVsync) == 32, "Unexpected size for DvrVsync");
+static_assert(sizeof(DvrConfig) == 16, "Unexpected size for DvrConfig");
// A helper class that provides compile time sized traits for the BroadcastRing.
template <class DvrType, size_t StaticCount>
@@ -41,13 +42,12 @@
// Traits classes.
using DvrPoseTraits = DvrRingBufferTraits<DvrPose, 0>;
using DvrVsyncTraits = DvrRingBufferTraits<DvrVsync, 2>;
-using DvrVrFlingerConfigTraits = DvrRingBufferTraits<DvrVrFlingerConfig, 2>;
+using DvrConfigTraits = DvrRingBufferTraits<DvrConfig, 2>;
// The broadcast ring classes that will expose the data.
using DvrPoseRing = BroadcastRing<DvrPose, DvrPoseTraits>;
using DvrVsyncRing = BroadcastRing<DvrVsync, DvrVsyncTraits>;
-using DvrVrFlingerConfigRing =
- BroadcastRing<DvrVrFlingerConfig, DvrVrFlingerConfigTraits>;
+using DvrConfigRing = BroadcastRing<DvrConfig, DvrConfigTraits>;
// This is a shared memory buffer for passing pose data estimated at vsyncs.
//
@@ -85,7 +85,7 @@
uint8_t padding[12];
};
-static_assert(sizeof(DvrVsyncPoseBuffer) == 1136,
+static_assert(sizeof(DvrVsyncPoseBuffer) == 1152,
"Unexpected size for DvrVsyncPoseBuffer");
// The keys for the dvr global buffers.
diff --git a/libs/vr/libdvr/include/dvr/dvr_surface.h b/libs/vr/libdvr/include/dvr/dvr_surface.h
index e3ab41b..74a68a1 100644
--- a/libs/vr/libdvr/include/dvr/dvr_surface.h
+++ b/libs/vr/libdvr/include/dvr/dvr_surface.h
@@ -76,13 +76,38 @@
int dvrSurfaceCreateWriteBufferQueue(DvrSurface* surface, uint32_t width,
uint32_t height, uint32_t format,
uint32_t layer_count, uint64_t usage,
- size_t capacity,
+ size_t capacity, size_t metadata_size,
DvrWriteBufferQueue** queue_out);
+// Sets up a named buffer for shared memory data transfer between display
+// clients and the system. Protected API that may only be called with sufficient
+// privilege.
+// @return 0 on success. Otherwise returns a negative error value.
+int dvrSetupGlobalBuffer(DvrGlobalBufferKey key, size_t size, uint64_t usage,
+ DvrBuffer** buffer_out);
+
+// Deletes a named buffer. WARNING: This is dangerous because any existing
+// clients of this buffer will not be notified and will remain attached to
+// the old buffer. This is useful for tests, but probably not for production
+// code.
+// @return 0 on success. Otherwise returns a negative error value.
+int dvrDeleteGlobalBuffer(DvrGlobalBufferKey key);
+
// Get a global buffer from the display service.
// @return 0 on success. Otherwise returns a negative error value.
int dvrGetGlobalBuffer(DvrGlobalBufferKey key, DvrBuffer** out_buffer);
+// Read the native device display metrics as reported by the hardware composer.
+// This is useful as otherwise the device metrics are only reported as
+// relative to the current device orientation.
+// @param sizeof_metrics the size of the passed in metrics struct. This is used
+// to ensure we don't break each other during active development.
+// @param metrics on success holds the retrieved device metrics.
+// @return 0 on success. Otherwise returns a negative error value (typically
+// this means the display service is not available).
+int dvrGetNativeDisplayMetrics(size_t metrics_struct_size,
+ DvrNativeDisplayMetrics* metrics);
+
__END_DECLS
#endif // ANDROID_DVR_SURFACE_H_
diff --git a/libs/vr/libdvr/tests/Android.bp b/libs/vr/libdvr/tests/Android.bp
index ab2ee75..887766a 100644
--- a/libs/vr/libdvr/tests/Android.bp
+++ b/libs/vr/libdvr/tests/Android.bp
@@ -42,11 +42,13 @@
"dvr_named_buffer-test.cpp",
],
+ header_libs: ["libdvr_headers"],
static_libs: static_libraries,
shared_libs: shared_libraries,
cflags: [
"-DLOG_TAG=\"dvr_api-test\"",
"-DTRACE=0",
+ "-Wno-missing-field-initializers",
"-O0",
"-g",
],
diff --git a/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp b/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp
index f2ae09e..62cd8d4 100644
--- a/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp
+++ b/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp
@@ -1,28 +1,32 @@
+#include <android/log.h>
+#include <android/native_window.h>
+#include <android-base/unique_fd.h>
#include <dvr/dvr_api.h>
#include <dvr/dvr_buffer_queue.h>
-#include <gui/Surface.h>
-#include <private/dvr/buffer_hub_queue_client.h>
-#include <base/logging.h>
#include <gtest/gtest.h>
-#include "../dvr_internal.h"
-#include "../dvr_buffer_queue_internal.h"
+#include <array>
+#include <unordered_map>
-namespace android {
-namespace dvr {
+#ifndef ALOGD
+#define ALOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
+#endif
+
+#ifndef ALOGD_IF
+#define ALOGD_IF(cond, ...) \
+ ((__predict_false(cond)) ? ((void)ALOGD(__VA_ARGS__)) : (void)0)
+#endif
namespace {
static constexpr uint32_t kBufferWidth = 100;
static constexpr uint32_t kBufferHeight = 1;
static constexpr uint32_t kLayerCount = 1;
-static constexpr uint32_t kBufferFormat = HAL_PIXEL_FORMAT_BLOB;
-static constexpr uint64_t kBufferUsage = GRALLOC_USAGE_SW_READ_RARELY;
+static constexpr uint32_t kBufferFormat = AHARDWAREBUFFER_FORMAT_BLOB;
+static constexpr uint64_t kBufferUsage = AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN;
static constexpr size_t kQueueCapacity = 3;
-typedef uint64_t TestMeta;
-
class DvrBufferQueueTest : public ::testing::Test {
public:
static void BufferAvailableCallback(void* context) {
@@ -36,18 +40,6 @@
}
protected:
- void SetUp() override {
- auto config = ProducerQueueConfigBuilder()
- .SetDefaultWidth(kBufferWidth)
- .SetDefaultHeight(kBufferHeight)
- .SetDefaultFormat(kBufferFormat)
- .SetMetadata<TestMeta>()
- .Build();
- write_queue_ =
- new DvrWriteBufferQueue(ProducerQueue::Create(config, UsagePolicy{}));
- ASSERT_NE(nullptr, write_queue_);
- }
-
void TearDown() override {
if (write_queue_ != nullptr) {
dvrWriteBufferQueueDestroy(write_queue_);
@@ -55,16 +47,6 @@
}
}
- void AllocateBuffers(size_t buffer_count) {
- size_t out_slot;
- for (size_t i = 0; i < buffer_count; i++) {
- auto status = write_queue_->producer_queue()->AllocateBuffer(
- kBufferWidth, kBufferHeight, kLayerCount, kBufferFormat, kBufferUsage,
- &out_slot);
- ASSERT_TRUE(status.ok());
- }
- }
-
void HandleBufferAvailable() {
buffer_available_count_ += 1;
ALOGD_IF(TRACE, "Buffer avaiable, count=%d", buffer_available_count_);
@@ -81,22 +63,36 @@
int buffer_removed_count_{0};
};
-TEST_F(DvrBufferQueueTest, TestWrite_QueueDestroy) {
+TEST_F(DvrBufferQueueTest, WriteQueueCreateDestroy) {
+ int ret = dvrWriteBufferQueueCreate(
+ kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
+ /*capacity=*/0, sizeof(DvrNativeBufferMetadata), &write_queue_);
+ ASSERT_EQ(0, ret);
+
dvrWriteBufferQueueDestroy(write_queue_);
write_queue_ = nullptr;
}
-TEST_F(DvrBufferQueueTest, TestWrite_QueueGetCapacity) {
- AllocateBuffers(kQueueCapacity);
+TEST_F(DvrBufferQueueTest, WriteQueueGetCapacity) {
+ int ret = dvrWriteBufferQueueCreate(
+ kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
+ kQueueCapacity, sizeof(DvrNativeBufferMetadata), &write_queue_);
+ ASSERT_EQ(0, ret);
+
size_t capacity = dvrWriteBufferQueueGetCapacity(write_queue_);
ALOGD_IF(TRACE, "TestWrite_QueueGetCapacity, capacity=%zu", capacity);
ASSERT_EQ(kQueueCapacity, capacity);
}
-TEST_F(DvrBufferQueueTest, TestCreateReadQueueFromWriteQueue) {
+TEST_F(DvrBufferQueueTest, CreateReadQueueFromWriteQueue) {
+ int ret = dvrWriteBufferQueueCreate(
+ kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
+ /*capacity=*/0, sizeof(DvrNativeBufferMetadata), &write_queue_);
+ ASSERT_EQ(0, ret);
+
DvrReadBufferQueue* read_queue = nullptr;
- int ret = dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue);
+ ret = dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue);
ASSERT_EQ(0, ret);
ASSERT_NE(nullptr, read_queue);
@@ -104,10 +100,15 @@
dvrReadBufferQueueDestroy(read_queue);
}
-TEST_F(DvrBufferQueueTest, TestCreateReadQueueFromReadQueue) {
+TEST_F(DvrBufferQueueTest, CreateReadQueueFromReadQueue) {
+ int ret = dvrWriteBufferQueueCreate(
+ kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
+ /*capacity=*/0, sizeof(DvrNativeBufferMetadata), &write_queue_);
+ ASSERT_EQ(0, ret);
+
DvrReadBufferQueue* read_queue1 = nullptr;
DvrReadBufferQueue* read_queue2 = nullptr;
- int ret = dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue1);
+ ret = dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue1);
ASSERT_EQ(0, ret);
ASSERT_NE(nullptr, read_queue1);
@@ -121,96 +122,86 @@
dvrReadBufferQueueDestroy(read_queue2);
}
-TEST_F(DvrBufferQueueTest, CreateEmptyBuffer) {
- AllocateBuffers(3);
+TEST_F(DvrBufferQueueTest, GainBuffer) {
+ int ret = dvrWriteBufferQueueCreate(
+ kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
+ kQueueCapacity, sizeof(DvrNativeBufferMetadata), &write_queue_);
+ ASSERT_EQ(ret, 0);
- DvrReadBuffer* read_buffer = nullptr;
- DvrWriteBuffer* write_buffer = nullptr;
+ DvrWriteBuffer* wb = nullptr;
+ EXPECT_FALSE(dvrWriteBufferIsValid(wb));
- EXPECT_FALSE(dvrReadBufferIsValid(read_buffer));
- EXPECT_FALSE(dvrWriteBufferIsValid(write_buffer));
-
- dvrReadBufferCreateEmpty(&read_buffer);
- ASSERT_NE(nullptr, read_buffer);
-
- dvrWriteBufferCreateEmpty(&write_buffer);
- ASSERT_NE(nullptr, write_buffer);
-
- EXPECT_FALSE(dvrReadBufferIsValid(read_buffer));
- EXPECT_FALSE(dvrWriteBufferIsValid(write_buffer));
-
- DvrReadBufferQueue* read_queue = nullptr;
-
- ASSERT_EQ(0, dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue));
-
- const int kTimeoutMs = 0;
+ DvrNativeBufferMetadata meta;
int fence_fd = -1;
- ASSERT_EQ(0, dvrWriteBufferQueueDequeue(write_queue_, kTimeoutMs,
- write_buffer, &fence_fd));
- EXPECT_EQ(-1, fence_fd);
- EXPECT_TRUE(dvrWriteBufferIsValid(write_buffer));
-
- ASSERT_EQ(0, dvrWriteBufferClear(write_buffer));
- EXPECT_FALSE(dvrWriteBufferIsValid(write_buffer));
+ ret = dvrWriteBufferQueueGainBuffer(write_queue_, /*timeout=*/0, &wb, &meta,
+ &fence_fd);
+ ASSERT_EQ(ret, 0);
+ EXPECT_EQ(fence_fd, -1);
+ EXPECT_NE(wb, nullptr);
+ EXPECT_TRUE(dvrWriteBufferIsValid(wb));
}
-TEST_F(DvrBufferQueueTest, TestDequeuePostDequeueRelease) {
- static constexpr int kTimeout = 0;
+TEST_F(DvrBufferQueueTest, AcquirePostGainRelease) {
+ int ret = dvrWriteBufferQueueCreate(
+ kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
+ kQueueCapacity, sizeof(DvrNativeBufferMetadata), &write_queue_);
+ ASSERT_EQ(ret, 0);
+
DvrReadBufferQueue* read_queue = nullptr;
DvrReadBuffer* rb = nullptr;
DvrWriteBuffer* wb = nullptr;
+ DvrNativeBufferMetadata meta1;
+ DvrNativeBufferMetadata meta2;
int fence_fd = -1;
- int ret = dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue);
+ ret = dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue);
- ASSERT_EQ(0, ret);
- ASSERT_NE(nullptr, read_queue);
+ ASSERT_EQ(ret, 0);
+ ASSERT_NE(read_queue, nullptr);
dvrReadBufferQueueSetBufferAvailableCallback(read_queue,
&BufferAvailableCallback, this);
- dvrWriteBufferCreateEmpty(&wb);
- ASSERT_NE(nullptr, wb);
-
- dvrReadBufferCreateEmpty(&rb);
- ASSERT_NE(nullptr, rb);
-
- AllocateBuffers(kQueueCapacity);
-
// Gain buffer for writing.
- ret = dvrWriteBufferQueueDequeue(write_queue_, kTimeout, wb, &fence_fd);
- ASSERT_EQ(0, ret);
+ ret = dvrWriteBufferQueueGainBuffer(write_queue_, /*timeout=*/0, &wb, &meta1,
+ &fence_fd);
+ ASSERT_EQ(ret, 0);
+ ASSERT_NE(wb, nullptr);
ASSERT_TRUE(dvrWriteBufferIsValid(wb));
ALOGD_IF(TRACE, "TestDequeuePostDequeueRelease, gain buffer %p, fence_fd=%d",
wb, fence_fd);
- pdx::LocalHandle release_fence(fence_fd);
+ android::base::unique_fd release_fence(fence_fd);
// Post buffer to the read_queue.
- TestMeta seq = 42U;
- ret = dvrWriteBufferPost(wb, /* fence */ -1, &seq, sizeof(seq));
- ASSERT_EQ(0, ret);
- dvrWriteBufferDestroy(wb);
+ meta1.timestamp = 42;
+ ret = dvrWriteBufferQueuePostBuffer(write_queue_, wb, &meta1, /*fence=*/-1);
+ ASSERT_EQ(ret, 0);
+ ASSERT_FALSE(dvrWriteBufferIsValid(wb));
wb = nullptr;
// Acquire buffer for reading.
- TestMeta acquired_seq = 0U;
- ret = dvrReadBufferQueueDequeue(read_queue, kTimeout, rb, &fence_fd,
- &acquired_seq, sizeof(acquired_seq));
- ASSERT_EQ(0, ret);
+ ret = dvrReadBufferQueueAcquireBuffer(read_queue, /*timeout=*/10, &rb, &meta2,
+ &fence_fd);
+ ASSERT_EQ(ret, 0);
+ ASSERT_NE(rb, nullptr);
// Dequeue is successfully, BufferAvailableCallback should be fired once.
- ASSERT_EQ(1, buffer_available_count_);
+ ASSERT_EQ(buffer_available_count_, 1);
ASSERT_TRUE(dvrReadBufferIsValid(rb));
- ASSERT_EQ(seq, acquired_seq);
+
+ // Metadata should be passed along from producer to consumer properly.
+ ASSERT_EQ(meta1.timestamp, meta2.timestamp);
+
ALOGD_IF(TRACE,
"TestDequeuePostDequeueRelease, acquire buffer %p, fence_fd=%d", rb,
fence_fd);
- pdx::LocalHandle acquire_fence(fence_fd);
+ android::base::unique_fd acquire_fence(fence_fd);
// Release buffer to the write_queue.
- ret = dvrReadBufferRelease(rb, -1);
- ASSERT_EQ(0, ret);
- dvrReadBufferDestroy(rb);
+ ret = dvrReadBufferQueueReleaseBuffer(read_queue, rb, &meta2,
+ /*release_fence_fd=*/-1);
+ ASSERT_EQ(ret, 0);
+ ASSERT_FALSE(dvrReadBufferIsValid(rb));
rb = nullptr;
// TODO(b/34387835) Currently buffer allocation has to happen after all queues
@@ -223,40 +214,38 @@
dvrReadBufferQueueDestroy(read_queue);
}
-TEST_F(DvrBufferQueueTest, TestGetExternalSurface) {
+TEST_F(DvrBufferQueueTest, GetANativeWindow) {
+ int ret = dvrWriteBufferQueueCreate(
+ kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
+ /*capacity=*/0, sizeof(DvrNativeBufferMetadata), &write_queue_);
+ ASSERT_EQ(0, ret);
+ ASSERT_NE(nullptr, write_queue_);
+
ANativeWindow* window = nullptr;
-
- // The |write_queue_| doesn't have proper metadata (must be
- // DvrNativeBufferMetadata) configured during creation.
- int ret = dvrWriteBufferQueueGetExternalSurface(write_queue_, &window);
- ASSERT_EQ(-EINVAL, ret);
- ASSERT_EQ(nullptr, window);
-
- // A write queue with DvrNativeBufferMetadata should work fine.
- auto config = ProducerQueueConfigBuilder()
- .SetMetadata<DvrNativeBufferMetadata>()
- .Build();
- std::unique_ptr<DvrWriteBufferQueue, decltype(&dvrWriteBufferQueueDestroy)>
- write_queue(
- new DvrWriteBufferQueue(ProducerQueue::Create(config, UsagePolicy{})),
- dvrWriteBufferQueueDestroy);
- ASSERT_NE(nullptr, write_queue.get());
-
- ret = dvrWriteBufferQueueGetExternalSurface(write_queue.get(), &window);
+ ret = dvrWriteBufferQueueGetANativeWindow(write_queue_, &window);
ASSERT_EQ(0, ret);
ASSERT_NE(nullptr, window);
- sp<Surface> surface = static_cast<Surface*>(window);
- ASSERT_TRUE(Surface::isValid(surface));
+ uint32_t width = ANativeWindow_getWidth(window);
+ uint32_t height = ANativeWindow_getHeight(window);
+ uint32_t format = ANativeWindow_getFormat(window);
+ ASSERT_EQ(kBufferWidth, width);
+ ASSERT_EQ(kBufferHeight, height);
+ ASSERT_EQ(kBufferFormat, format);
}
// Create buffer queue of three buffers and dequeue three buffers out of it.
// Before each dequeue operation, we resize the buffer queue and expect the
// queue always return buffer with desired dimension.
-TEST_F(DvrBufferQueueTest, TestResizeBuffer) {
- static constexpr int kTimeout = 0;
+TEST_F(DvrBufferQueueTest, ResizeBuffer) {
+ int ret = dvrWriteBufferQueueCreate(
+ kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
+ kQueueCapacity, sizeof(DvrNativeBufferMetadata), &write_queue_);
+ ASSERT_EQ(0, ret);
+
int fence_fd = -1;
+ DvrNativeBufferMetadata meta;
DvrReadBufferQueue* read_queue = nullptr;
DvrWriteBuffer* wb1 = nullptr;
DvrWriteBuffer* wb2 = nullptr;
@@ -266,7 +255,7 @@
AHardwareBuffer* ahb3 = nullptr;
AHardwareBuffer_Desc buffer_desc;
- int ret = dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue);
+ ret = dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue);
ASSERT_EQ(0, ret);
ASSERT_NE(nullptr, read_queue);
@@ -274,15 +263,6 @@
dvrReadBufferQueueSetBufferRemovedCallback(read_queue, &BufferRemovedCallback,
this);
- dvrWriteBufferCreateEmpty(&wb1);
- ASSERT_NE(nullptr, wb1);
- dvrWriteBufferCreateEmpty(&wb2);
- ASSERT_NE(nullptr, wb2);
- dvrWriteBufferCreateEmpty(&wb3);
- ASSERT_NE(nullptr, wb3);
-
- AllocateBuffers(kQueueCapacity);
-
// Handle all pending events on the read queue.
ret = dvrReadBufferQueueHandleEvents(read_queue);
ASSERT_EQ(0, ret);
@@ -297,11 +277,12 @@
ASSERT_EQ(0, ret);
// Gain first buffer for writing. All buffers will be resized.
- ret = dvrWriteBufferQueueDequeue(write_queue_, kTimeout, wb1, &fence_fd);
+ ret = dvrWriteBufferQueueGainBuffer(write_queue_, /*timeout=*/0, &wb1, &meta,
+ &fence_fd);
ASSERT_EQ(0, ret);
ASSERT_TRUE(dvrWriteBufferIsValid(wb1));
ALOGD_IF(TRACE, "TestResizeBuffer, gain buffer %p", wb1);
- pdx::LocalHandle release_fence1(fence_fd);
+ android::base::unique_fd release_fence1(fence_fd);
// Check the buffer dimension.
ret = dvrWriteBufferGetAHardwareBuffer(wb1, &ahb1);
@@ -323,12 +304,13 @@
ASSERT_EQ(0, ret);
// The next buffer we dequeued should have new width.
- ret = dvrWriteBufferQueueDequeue(write_queue_, kTimeout, wb2, &fence_fd);
+ ret = dvrWriteBufferQueueGainBuffer(write_queue_, /*timeout=*/0, &wb2, &meta,
+ &fence_fd);
ASSERT_EQ(0, ret);
ASSERT_TRUE(dvrWriteBufferIsValid(wb2));
ALOGD_IF(TRACE, "TestResizeBuffer, gain buffer %p, fence_fd=%d", wb2,
fence_fd);
- pdx::LocalHandle release_fence2(fence_fd);
+ android::base::unique_fd release_fence2(fence_fd);
// Check the buffer dimension, should be new width
ret = dvrWriteBufferGetAHardwareBuffer(wb2, &ahb2);
@@ -349,12 +331,13 @@
ASSERT_EQ(0, ret);
// The next buffer we dequeued should have new width.
- ret = dvrWriteBufferQueueDequeue(write_queue_, kTimeout, wb3, &fence_fd);
+ ret = dvrWriteBufferQueueGainBuffer(write_queue_, /*timeout=*/0, &wb3, &meta,
+ &fence_fd);
ASSERT_EQ(0, ret);
ASSERT_TRUE(dvrWriteBufferIsValid(wb3));
ALOGD_IF(TRACE, "TestResizeBuffer, gain buffer %p, fence_fd=%d", wb3,
fence_fd);
- pdx::LocalHandle release_fence3(fence_fd);
+ android::base::unique_fd release_fence3(fence_fd);
// Check the buffer dimension, should be new width
ret = dvrWriteBufferGetAHardwareBuffer(wb3, &ahb3);
@@ -372,7 +355,170 @@
dvrReadBufferQueueDestroy(read_queue);
}
-} // namespace
+TEST_F(DvrBufferQueueTest, ReadQueueEventFd) {
+ int ret = dvrWriteBufferQueueCreate(
+ kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
+ kQueueCapacity, sizeof(DvrNativeBufferMetadata), &write_queue_);
+ ASSERT_EQ(0, ret);
-} // namespace dvr
-} // namespace android
+ DvrReadBufferQueue* read_queue = nullptr;
+ ret = dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue);
+
+ ASSERT_EQ(0, ret);
+ ASSERT_NE(nullptr, read_queue);
+
+ int event_fd = dvrReadBufferQueueGetEventFd(read_queue);
+ ASSERT_GT(event_fd, 0);
+}
+
+// Verifies a Dvr{Read,Write}BufferQueue contains the same set of
+// Dvr{Read,Write}Buffer(s) during their lifecycles. And for the same buffer_id,
+// the corresponding AHardwareBuffer handle stays the same.
+TEST_F(DvrBufferQueueTest, StableBufferIdAndHardwareBuffer) {
+ int ret = dvrWriteBufferQueueCreate(
+ kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
+ kQueueCapacity, sizeof(DvrNativeBufferMetadata), &write_queue_);
+ ASSERT_EQ(0, ret);
+
+ int fence_fd = -1;
+ DvrReadBufferQueue* read_queue = nullptr;
+ EXPECT_EQ(0, dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue));
+
+ // Read buffers.
+ std::array<DvrReadBuffer*, kQueueCapacity> rbs;
+ // Write buffers.
+ std::array<DvrWriteBuffer*, kQueueCapacity> wbs;
+ // Buffer metadata.
+ std::array<DvrNativeBufferMetadata, kQueueCapacity> metas;
+ // Hardware buffers for Read buffers.
+ std::unordered_map<int, AHardwareBuffer*> rhbs;
+ // Hardware buffers for Write buffers.
+ std::unordered_map<int, AHardwareBuffer*> whbs;
+
+ constexpr int kNumTests = 100;
+
+ // This test runs the following operations many many times. Thus we prefer to
+ // use ASSERT_XXX rather than EXPECT_XXX to avoid spamming the output.
+ std::function<void(size_t i)> Gain = [&](size_t i) {
+ int ret = dvrWriteBufferQueueGainBuffer(write_queue_, /*timeout=*/10,
+ &wbs[i], &metas[i], &fence_fd);
+ ASSERT_EQ(ret, 0);
+ ASSERT_LT(fence_fd, 0); // expect invalid fence.
+ ASSERT_TRUE(dvrWriteBufferIsValid(wbs[i]));
+ int buffer_id = dvrWriteBufferGetId(wbs[i]);
+ ASSERT_GT(buffer_id, 0);
+
+ AHardwareBuffer* hb = nullptr;
+ ASSERT_EQ(0, dvrWriteBufferGetAHardwareBuffer(wbs[i], &hb));
+
+ auto whb_it = whbs.find(buffer_id);
+ if (whb_it == whbs.end()) {
+ // If this is a new buffer id, check that total number of unique
+ // hardware buffers won't exceed queue capacity.
+ ASSERT_LT(whbs.size(), kQueueCapacity);
+ whbs.emplace(buffer_id, hb);
+ } else {
+ // If this is a buffer id we have seen before, check that the
+ // buffer_id maps to the same AHardwareBuffer handle.
+ ASSERT_EQ(hb, whb_it->second);
+ }
+ };
+
+ std::function<void(size_t i)> Post = [&](size_t i) {
+ ASSERT_TRUE(dvrWriteBufferIsValid(wbs[i]));
+
+ metas[i].timestamp++;
+ int ret = dvrWriteBufferQueuePostBuffer(write_queue_, wbs[i], &metas[i],
+ /*fence=*/-1);
+ ASSERT_EQ(ret, 0);
+ };
+
+ std::function<void(size_t i)> Acquire = [&](size_t i) {
+ int ret = dvrReadBufferQueueAcquireBuffer(read_queue, /*timeout=*/10,
+ &rbs[i], &metas[i], &fence_fd);
+ ASSERT_EQ(ret, 0);
+ ASSERT_LT(fence_fd, 0); // expect invalid fence.
+ ASSERT_TRUE(dvrReadBufferIsValid(rbs[i]));
+
+ int buffer_id = dvrReadBufferGetId(rbs[i]);
+ ASSERT_GT(buffer_id, 0);
+
+ AHardwareBuffer* hb = nullptr;
+ ASSERT_EQ(0, dvrReadBufferGetAHardwareBuffer(rbs[i], &hb));
+
+ auto rhb_it = rhbs.find(buffer_id);
+ if (rhb_it == rhbs.end()) {
+ // If this is a new buffer id, check that total number of unique hardware
+ // buffers won't exceed queue capacity.
+ ASSERT_LT(rhbs.size(), kQueueCapacity);
+ rhbs.emplace(buffer_id, hb);
+ } else {
+ // If this is a buffer id we have seen before, check that the buffer_id
+ // maps to the same AHardwareBuffer handle.
+ ASSERT_EQ(hb, rhb_it->second);
+ }
+ };
+
+ std::function<void(size_t i)> Release = [&](size_t i) {
+ ASSERT_TRUE(dvrReadBufferIsValid(rbs[i]));
+
+ int ret = dvrReadBufferQueueReleaseBuffer(read_queue, rbs[i], &metas[i],
+ /*release_fence_fd=*/-1);
+ ASSERT_EQ(ret, 0);
+ };
+
+ // Scenario one:
+ for (int i = 0; i < kNumTests; i++) {
+ // Gain all write buffers.
+ for (size_t i = 0; i < kQueueCapacity; i++) {
+ ASSERT_NO_FATAL_FAILURE(Gain(i));
+ }
+ // Post all write buffers.
+ for (size_t i = 0; i < kQueueCapacity; i++) {
+ ASSERT_NO_FATAL_FAILURE(Post(i));
+ }
+ // Acquire all read buffers.
+ for (size_t i = 0; i < kQueueCapacity; i++) {
+ ASSERT_NO_FATAL_FAILURE(Acquire(i));
+ }
+ // Release all read buffers.
+ for (size_t i = 0; i < kQueueCapacity; i++) {
+ ASSERT_NO_FATAL_FAILURE(Release(i));
+ }
+ }
+
+ // Scenario two:
+ for (int i = 0; i < kNumTests; i++) {
+ // Gain and post all write buffers.
+ for (size_t i = 0; i < kQueueCapacity; i++) {
+ ASSERT_NO_FATAL_FAILURE(Gain(i));
+ ASSERT_NO_FATAL_FAILURE(Post(i));
+ }
+ // Acquire and release all read buffers.
+ for (size_t i = 0; i < kQueueCapacity; i++) {
+ ASSERT_NO_FATAL_FAILURE(Acquire(i));
+ ASSERT_NO_FATAL_FAILURE(Release(i));
+ }
+ }
+
+ // Scenario three:
+ for (int i = 0; i < kNumTests; i++) {
+ // Gain all write buffers then post them in reversed order.
+ for (size_t i = 0; i < kQueueCapacity; i++) {
+ ASSERT_NO_FATAL_FAILURE(Gain(i));
+ }
+ for (size_t i = 0; i < kQueueCapacity; i++) {
+ ASSERT_NO_FATAL_FAILURE(Post(kQueueCapacity - 1 - i));
+ }
+
+ // Acquire all write buffers then release them in reversed order.
+ for (size_t i = 0; i < kQueueCapacity; i++) {
+ ASSERT_NO_FATAL_FAILURE(Acquire(i));
+ }
+ for (size_t i = 0; i < kQueueCapacity; i++) {
+ ASSERT_NO_FATAL_FAILURE(Release(kQueueCapacity - 1 - i));
+ }
+ }
+}
+
+} // namespace
diff --git a/libs/vr/libdvr/tests/dvr_display_manager-test.cpp b/libs/vr/libdvr/tests/dvr_display_manager-test.cpp
index 2249154..f83b26e 100644
--- a/libs/vr/libdvr/tests/dvr_display_manager-test.cpp
+++ b/libs/vr/libdvr/tests/dvr_display_manager-test.cpp
@@ -1,11 +1,13 @@
#include <android-base/properties.h>
#include <base/logging.h>
#include <gtest/gtest.h>
+#include <log/log.h>
#include <poll.h>
#include <android/hardware_buffer.h>
#include <algorithm>
+#include <array>
#include <set>
#include <thread>
#include <vector>
@@ -25,7 +27,30 @@
namespace {
-DvrSurfaceAttribute GetAttribute(DvrSurfaceAttributeKey key, bool value) {
+DvrSurfaceAttribute MakeAttribute(DvrSurfaceAttributeKey key, nullptr_t) {
+ DvrSurfaceAttribute attribute;
+ attribute.key = key;
+ attribute.value.type = DVR_SURFACE_ATTRIBUTE_TYPE_NONE;
+ return attribute;
+}
+
+DvrSurfaceAttribute MakeAttribute(DvrSurfaceAttributeKey key, int32_t value) {
+ DvrSurfaceAttribute attribute;
+ attribute.key = key;
+ attribute.value.type = DVR_SURFACE_ATTRIBUTE_TYPE_INT32;
+ attribute.value.int32_value = value;
+ return attribute;
+}
+
+DvrSurfaceAttribute MakeAttribute(DvrSurfaceAttributeKey key, int64_t value) {
+ DvrSurfaceAttribute attribute;
+ attribute.key = key;
+ attribute.value.type = DVR_SURFACE_ATTRIBUTE_TYPE_INT64;
+ attribute.value.int64_value = value;
+ return attribute;
+}
+
+DvrSurfaceAttribute MakeAttribute(DvrSurfaceAttributeKey key, bool value) {
DvrSurfaceAttribute attribute;
attribute.key = key;
attribute.value.type = DVR_SURFACE_ATTRIBUTE_TYPE_BOOL;
@@ -33,11 +58,56 @@
return attribute;
}
-DvrSurfaceAttribute GetAttribute(DvrSurfaceAttributeKey key, int32_t value) {
+DvrSurfaceAttribute MakeAttribute(DvrSurfaceAttributeKey key, float value) {
DvrSurfaceAttribute attribute;
attribute.key = key;
- attribute.value.type = DVR_SURFACE_ATTRIBUTE_TYPE_INT32;
- attribute.value.bool_value = value;
+ attribute.value.type = DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT;
+ attribute.value.float_value = value;
+ return attribute;
+}
+
+DvrSurfaceAttribute MakeAttribute(DvrSurfaceAttributeKey key,
+ const std::array<float, 2>& value) {
+ DvrSurfaceAttribute attribute;
+ attribute.key = key;
+ attribute.value.type = DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT2;
+ std::copy(value.begin(), value.end(), attribute.value.float2_value);
+ return attribute;
+}
+
+DvrSurfaceAttribute MakeAttribute(DvrSurfaceAttributeKey key,
+ const std::array<float, 3>& value) {
+ DvrSurfaceAttribute attribute;
+ attribute.key = key;
+ attribute.value.type = DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT3;
+ std::copy(value.begin(), value.end(), attribute.value.float3_value);
+ return attribute;
+}
+
+DvrSurfaceAttribute MakeAttribute(DvrSurfaceAttributeKey key,
+ const std::array<float, 4>& value) {
+ DvrSurfaceAttribute attribute;
+ attribute.key = key;
+ attribute.value.type = DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT4;
+ std::copy(value.begin(), value.end(), attribute.value.float4_value);
+ return attribute;
+}
+
+DvrSurfaceAttribute MakeAttribute(DvrSurfaceAttributeKey key,
+ const std::array<float, 8>& value) {
+ DvrSurfaceAttribute attribute;
+ attribute.key = key;
+ attribute.value.type = DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT8;
+ std::copy(value.begin(), value.end(), attribute.value.float8_value);
+ return attribute;
+}
+
+DvrSurfaceAttribute MakeAttribute(DvrSurfaceAttributeKey key,
+ const std::array<float, 16>& value) {
+ DvrSurfaceAttribute attribute;
+ attribute.key = key;
+ attribute.value.type = DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT16;
+ std::copy(value.begin(), value.end(), attribute.value.float16_value);
return attribute;
}
@@ -45,8 +115,8 @@
int32_t z_order = 0) {
DvrSurface* surface = nullptr;
DvrSurfaceAttribute attributes[] = {
- GetAttribute(DVR_SURFACE_ATTRIBUTE_Z_ORDER, z_order),
- GetAttribute(DVR_SURFACE_ATTRIBUTE_VISIBLE, visible)};
+ MakeAttribute(DVR_SURFACE_ATTRIBUTE_Z_ORDER, z_order),
+ MakeAttribute(DVR_SURFACE_ATTRIBUTE_VISIBLE, visible)};
const int ret = dvrSurfaceCreate(
attributes, std::extent<decltype(attributes)>::value, &surface);
@@ -58,11 +128,12 @@
Status<UniqueDvrWriteBufferQueue> CreateSurfaceQueue(
const UniqueDvrSurface& surface, uint32_t width, uint32_t height,
- uint32_t format, uint32_t layer_count, uint64_t usage, size_t capacity) {
+ uint32_t format, uint32_t layer_count, uint64_t usage, size_t capacity,
+ size_t metadata_size) {
DvrWriteBufferQueue* queue;
- const int ret =
- dvrSurfaceCreateWriteBufferQueue(surface.get(), width, height, format,
- layer_count, usage, capacity, &queue);
+ const int ret = dvrSurfaceCreateWriteBufferQueue(
+ surface.get(), width, height, format, layer_count, usage, capacity,
+ metadata_size, &queue);
if (ret < 0)
return ErrorStatus(-ret);
else
@@ -100,13 +171,14 @@
return {};
}
- Status<void> WaitForUpdate() {
+ enum : int { kTimeoutMs = 10000 }; // 10s
+
+ Status<void> WaitForUpdate(int timeout_ms = kTimeoutMs) {
if (display_manager_event_fd_ < 0)
return ErrorStatus(-display_manager_event_fd_);
- const int kTimeoutMs = 10000; // 10s
pollfd pfd = {display_manager_event_fd_, POLLIN, 0};
- const int count = poll(&pfd, 1, kTimeoutMs);
+ const int count = poll(&pfd, 1, timeout_ms);
if (count < 0)
return ErrorStatus(errno);
else if (count == 0)
@@ -470,20 +542,218 @@
auto attributes = attribute_status.take();
EXPECT_GE(attributes.size(), 2u);
- const std::set<int32_t> expected_keys = {DVR_SURFACE_ATTRIBUTE_Z_ORDER,
- DVR_SURFACE_ATTRIBUTE_VISIBLE};
+ std::set<int32_t> actual_keys;
+ std::set<int32_t> expected_keys = {DVR_SURFACE_ATTRIBUTE_Z_ORDER,
+ DVR_SURFACE_ATTRIBUTE_VISIBLE};
// Collect all the keys in attributes that match the expected keys.
- std::set<int32_t> actual_keys;
- std::for_each(attributes.begin(), attributes.end(),
- [&expected_keys, &actual_keys](const auto& attribute) {
- if (expected_keys.find(attribute.key) != expected_keys.end())
- actual_keys.emplace(attribute.key);
- });
+ auto compare_keys = [](const auto& attributes, const auto& expected_keys) {
+ std::set<int32_t> keys;
+ for (const auto& attribute : attributes) {
+ if (expected_keys.find(attribute.key) != expected_keys.end())
+ keys.emplace(attribute.key);
+ }
+ return keys;
+ };
// If the sets match then attributes contained at least the expected keys,
// even if other keys were also present.
+ actual_keys = compare_keys(attributes, expected_keys);
EXPECT_EQ(expected_keys, actual_keys);
+
+ std::vector<DvrSurfaceAttribute> attributes_to_set = {
+ MakeAttribute(DVR_SURFACE_ATTRIBUTE_Z_ORDER, 0)};
+
+ // Test invalid args.
+ EXPECT_EQ(-EINVAL, dvrSurfaceSetAttributes(nullptr, attributes_to_set.data(),
+ attributes_to_set.size()));
+ EXPECT_EQ(-EINVAL, dvrSurfaceSetAttributes(surface.get(), nullptr,
+ attributes_to_set.size()));
+
+ // Test attribute change events.
+ ASSERT_EQ(0, dvrSurfaceSetAttributes(surface.get(), attributes_to_set.data(),
+ attributes_to_set.size()));
+ ASSERT_STATUS_OK(manager_->WaitForUpdate());
+
+ // Verify the attributes changed flag is set.
+ auto check_flags = [](const auto& value) {
+ return value & DVR_SURFACE_UPDATE_FLAGS_ATTRIBUTES_CHANGED;
+ };
+ EXPECT_STATUS_PRED(check_flags, manager_->GetUpdateFlags(0));
+
+ attribute_status = manager_->GetAttributes(0);
+ ASSERT_STATUS_OK(attribute_status);
+ attributes = attribute_status.take();
+ EXPECT_GE(attributes.size(), 2u);
+
+ expected_keys = {DVR_SURFACE_ATTRIBUTE_Z_ORDER,
+ DVR_SURFACE_ATTRIBUTE_VISIBLE};
+
+ actual_keys.clear();
+ actual_keys = compare_keys(attributes, expected_keys);
+ EXPECT_EQ(expected_keys, actual_keys);
+
+ // Test setting and then deleting an attribute.
+ const DvrSurfaceAttributeKey kUserKey = 1;
+ attributes_to_set = {MakeAttribute(kUserKey, 1024)};
+
+ ASSERT_EQ(0, dvrSurfaceSetAttributes(surface.get(), attributes_to_set.data(),
+ attributes_to_set.size()));
+ ASSERT_STATUS_OK(manager_->WaitForUpdate());
+ EXPECT_STATUS_PRED(check_flags, manager_->GetUpdateFlags(0));
+
+ attribute_status = manager_->GetAttributes(0);
+ ASSERT_STATUS_OK(attribute_status);
+ attributes = attribute_status.take();
+ EXPECT_GE(attributes.size(), 2u);
+
+ expected_keys = {DVR_SURFACE_ATTRIBUTE_Z_ORDER, DVR_SURFACE_ATTRIBUTE_VISIBLE,
+ kUserKey};
+
+ actual_keys.clear();
+ actual_keys = compare_keys(attributes, expected_keys);
+ EXPECT_EQ(expected_keys, actual_keys);
+
+ // Delete the attribute.
+ attributes_to_set = {MakeAttribute(kUserKey, nullptr)};
+
+ ASSERT_EQ(0, dvrSurfaceSetAttributes(surface.get(), attributes_to_set.data(),
+ attributes_to_set.size()));
+ ASSERT_STATUS_OK(manager_->WaitForUpdate());
+ EXPECT_STATUS_PRED(check_flags, manager_->GetUpdateFlags(0));
+
+ attribute_status = manager_->GetAttributes(0);
+ ASSERT_STATUS_OK(attribute_status);
+ attributes = attribute_status.take();
+ EXPECT_GE(attributes.size(), 2u);
+
+ expected_keys = {DVR_SURFACE_ATTRIBUTE_Z_ORDER, DVR_SURFACE_ATTRIBUTE_VISIBLE,
+ kUserKey};
+
+ actual_keys.clear();
+ actual_keys = compare_keys(attributes, expected_keys);
+ EXPECT_NE(expected_keys, actual_keys);
+
+ // Test deleting a reserved attribute.
+ attributes_to_set = {MakeAttribute(DVR_SURFACE_ATTRIBUTE_VISIBLE, nullptr)};
+
+ EXPECT_EQ(0, dvrSurfaceSetAttributes(surface.get(), attributes_to_set.data(),
+ attributes_to_set.size()));
+
+ // Failed attribute operations should not trigger update events.
+ const int kTimeoutMs = 100; // 0.1s
+ EXPECT_STATUS_ERROR_VALUE(ETIMEDOUT, manager_->WaitForUpdate(kTimeoutMs));
+
+ attribute_status = manager_->GetAttributes(0);
+ ASSERT_STATUS_OK(attribute_status);
+ attributes = attribute_status.take();
+ EXPECT_GE(attributes.size(), 2u);
+
+ expected_keys = {DVR_SURFACE_ATTRIBUTE_Z_ORDER,
+ DVR_SURFACE_ATTRIBUTE_VISIBLE};
+
+ actual_keys.clear();
+ actual_keys = compare_keys(attributes, expected_keys);
+ EXPECT_EQ(expected_keys, actual_keys);
+}
+
+TEST_F(DvrDisplayManagerTest, SurfaceAttributeTypes) {
+ // Create an application surface.
+ auto surface_status = CreateApplicationSurface();
+ ASSERT_STATUS_OK(surface_status);
+ UniqueDvrSurface surface = surface_status.take();
+ ASSERT_NE(nullptr, surface.get());
+
+ enum : std::int32_t {
+ kInt32Key = 1,
+ kInt64Key,
+ kBoolKey,
+ kFloatKey,
+ kFloat2Key,
+ kFloat3Key,
+ kFloat4Key,
+ kFloat8Key,
+ kFloat16Key,
+ };
+
+ const std::vector<DvrSurfaceAttribute> attributes_to_set = {
+ MakeAttribute(kInt32Key, int32_t{0}),
+ MakeAttribute(kInt64Key, int64_t{0}),
+ MakeAttribute(kBoolKey, false),
+ MakeAttribute(kFloatKey, 0.0f),
+ MakeAttribute(kFloat2Key, std::array<float, 2>{{1.0f, 2.0f}}),
+ MakeAttribute(kFloat3Key, std::array<float, 3>{{3.0f, 4.0f, 5.0f}}),
+ MakeAttribute(kFloat4Key, std::array<float, 4>{{6.0f, 7.0f, 8.0f, 9.0f}}),
+ MakeAttribute(kFloat8Key,
+ std::array<float, 8>{{10.0f, 11.0f, 12.0f, 13.0f, 14.0f,
+ 15.0f, 16.0f, 17.0f}}),
+ MakeAttribute(kFloat16Key, std::array<float, 16>{
+ {18.0f, 19.0f, 20.0f, 21.0f, 22.0f, 23.0f,
+ 24.0f, 25.0f, 26.0f, 27.0f, 28.0f, 29.0f,
+ 30.0f, 31.0f, 32.0f, 33.0f}})};
+
+ EXPECT_EQ(0, dvrSurfaceSetAttributes(surface.get(), attributes_to_set.data(),
+ attributes_to_set.size()));
+
+ ASSERT_STATUS_OK(manager_->WaitForUpdate());
+ auto attribute_status = manager_->GetAttributes(0);
+ ASSERT_STATUS_OK(attribute_status);
+ auto attributes = attribute_status.take();
+ EXPECT_GE(attributes.size(), attributes_to_set.size());
+
+ auto HasAttribute = [](const auto& attributes,
+ DvrSurfaceAttributeKey key) -> bool {
+ for (const auto& attribute : attributes) {
+ if (attribute.key == key)
+ return true;
+ }
+ return false;
+ };
+ auto AttributeType =
+ [](const auto& attributes,
+ DvrSurfaceAttributeKey key) -> DvrSurfaceAttributeType {
+ for (const auto& attribute : attributes) {
+ if (attribute.key == key)
+ return attribute.value.type;
+ }
+ return DVR_SURFACE_ATTRIBUTE_TYPE_NONE;
+ };
+
+ ASSERT_TRUE(HasAttribute(attributes, kInt32Key));
+ EXPECT_EQ(DVR_SURFACE_ATTRIBUTE_TYPE_INT32,
+ AttributeType(attributes, kInt32Key));
+
+ ASSERT_TRUE(HasAttribute(attributes, kInt64Key));
+ EXPECT_EQ(DVR_SURFACE_ATTRIBUTE_TYPE_INT64,
+ AttributeType(attributes, kInt64Key));
+
+ ASSERT_TRUE(HasAttribute(attributes, kBoolKey));
+ EXPECT_EQ(DVR_SURFACE_ATTRIBUTE_TYPE_BOOL,
+ AttributeType(attributes, kBoolKey));
+
+ ASSERT_TRUE(HasAttribute(attributes, kFloatKey));
+ EXPECT_EQ(DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT,
+ AttributeType(attributes, kFloatKey));
+
+ ASSERT_TRUE(HasAttribute(attributes, kFloat2Key));
+ EXPECT_EQ(DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT2,
+ AttributeType(attributes, kFloat2Key));
+
+ ASSERT_TRUE(HasAttribute(attributes, kFloat3Key));
+ EXPECT_EQ(DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT3,
+ AttributeType(attributes, kFloat3Key));
+
+ ASSERT_TRUE(HasAttribute(attributes, kFloat4Key));
+ EXPECT_EQ(DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT4,
+ AttributeType(attributes, kFloat4Key));
+
+ ASSERT_TRUE(HasAttribute(attributes, kFloat8Key));
+ EXPECT_EQ(DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT8,
+ AttributeType(attributes, kFloat8Key));
+
+ ASSERT_TRUE(HasAttribute(attributes, kFloat16Key));
+ EXPECT_EQ(DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT16,
+ AttributeType(attributes, kFloat16Key));
}
TEST_F(DvrDisplayManagerTest, SurfaceQueueEvent) {
@@ -499,13 +769,14 @@
ASSERT_STATUS_OK(manager_->WaitForUpdate());
ASSERT_STATUS_EQ(1u, manager_->GetSurfaceCount());
- // Verify there are no queues for the surface recorded in the state snapshot.
+ // Verify there are no queues for the surface recorded in the state
+ // snapshot.
EXPECT_STATUS_EQ(std::vector<int>{}, manager_->GetQueueIds(0));
// Create a new queue in the surface.
auto write_queue_status = CreateSurfaceQueue(
surface, 320, 240, AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM, 1,
- AHARDWAREBUFFER_USAGE_CPU_READ_RARELY, 1);
+ AHARDWAREBUFFER_USAGE_CPU_READ_RARELY, 1, 0);
ASSERT_STATUS_OK(write_queue_status);
UniqueDvrWriteBufferQueue write_queue = write_queue_status.take();
ASSERT_NE(nullptr, write_queue.get());
@@ -568,7 +839,7 @@
const uint32_t kLayerCount = 3;
auto write_queue_status = CreateSurfaceQueue(
surface, 320, 240, AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM, kLayerCount,
- AHARDWAREBUFFER_USAGE_CPU_READ_RARELY, 1);
+ AHARDWAREBUFFER_USAGE_CPU_READ_RARELY, 1, 0);
ASSERT_STATUS_OK(write_queue_status);
UniqueDvrWriteBufferQueue write_queue = write_queue_status.take();
ASSERT_NE(nullptr, write_queue.get());
diff --git a/libs/vr/libdvr/tests/dvr_named_buffer-test.cpp b/libs/vr/libdvr/tests/dvr_named_buffer-test.cpp
index 419083f..c21deb0 100644
--- a/libs/vr/libdvr/tests/dvr_named_buffer-test.cpp
+++ b/libs/vr/libdvr/tests/dvr_named_buffer-test.cpp
@@ -1,9 +1,8 @@
#include <android/hardware_buffer.h>
#include <dvr/dvr_buffer.h>
-#include <dvr/dvr_display_manager.h>
+#include <dvr/dvr_config.h>
#include <dvr/dvr_shared_buffers.h>
#include <dvr/dvr_surface.h>
-#include <dvr/dvr_vrflinger_config.h>
#include <system/graphics.h>
#include <base/logging.h>
@@ -14,33 +13,15 @@
namespace {
-class DvrGlobalBufferTest : public ::testing::Test {
- protected:
- void SetUp() override {
- const int ret = dvrDisplayManagerCreate(&client_);
- ASSERT_EQ(0, ret);
- ASSERT_NE(nullptr, client_);
- }
-
- void TearDown() override {
- dvrDisplayManagerDestroy(client_);
- client_ = nullptr;
- }
-
- DvrDisplayManager* client_ = nullptr;
-};
-
-TEST_F(DvrGlobalBufferTest, TestGlobalBuffersSameName) {
+TEST(DvrGlobalBufferTest, TestGlobalBuffersSameName) {
const DvrGlobalBufferKey buffer_key = 101;
DvrBuffer* buffer1 = nullptr;
- int ret1 =
- dvrDisplayManagerSetupGlobalBuffer(client_, buffer_key, 10, 0, &buffer1);
+ int ret1 = dvrSetupGlobalBuffer(buffer_key, 10, 0, &buffer1);
ASSERT_EQ(0, ret1);
ASSERT_NE(nullptr, buffer1);
DvrBuffer* buffer2 = nullptr;
- int ret2 =
- dvrDisplayManagerSetupGlobalBuffer(client_, buffer_key, 10, 0, &buffer2);
+ int ret2 = dvrSetupGlobalBuffer(buffer_key, 10, 0, &buffer2);
ASSERT_EQ(0, ret1);
ASSERT_NE(nullptr, buffer2);
@@ -97,19 +78,17 @@
AHardwareBuffer_release(hardware_buffer3);
}
-TEST_F(DvrGlobalBufferTest, TestMultipleGlobalBuffers) {
+TEST(DvrGlobalBufferTest, TestMultipleGlobalBuffers) {
const DvrGlobalBufferKey buffer_key1 = 102;
const DvrGlobalBufferKey buffer_key2 = 103;
DvrBuffer* setup_buffer1 = nullptr;
- int ret1 = dvrDisplayManagerSetupGlobalBuffer(client_, buffer_key1, 10, 0,
- &setup_buffer1);
+ int ret1 = dvrSetupGlobalBuffer(buffer_key1, 10, 0, &setup_buffer1);
ASSERT_EQ(0, ret1);
ASSERT_NE(nullptr, setup_buffer1);
dvrBufferDestroy(setup_buffer1);
DvrBuffer* setup_buffer2 = nullptr;
- int ret2 = dvrDisplayManagerSetupGlobalBuffer(client_, buffer_key2, 10, 0,
- &setup_buffer2);
+ int ret2 = dvrSetupGlobalBuffer(buffer_key2, 10, 0, &setup_buffer2);
ASSERT_EQ(0, ret2);
ASSERT_NE(nullptr, setup_buffer2);
dvrBufferDestroy(setup_buffer2);
@@ -127,7 +106,7 @@
dvrBufferDestroy(buffer2);
}
-TEST_F(DvrGlobalBufferTest, TestGlobalBufferUsage) {
+TEST(DvrGlobalBufferTest, TestGlobalBufferUsage) {
const DvrGlobalBufferKey buffer_key = 100;
// Set usage to AHARDWAREBUFFER_USAGE_VIDEO_ENCODE. We use this because
@@ -138,8 +117,7 @@
const uint64_t usage = AHARDWAREBUFFER_USAGE_VIDEO_ENCODE;
DvrBuffer* setup_buffer = nullptr;
- int e1 = dvrDisplayManagerSetupGlobalBuffer(client_, buffer_key, 10, usage,
- &setup_buffer);
+ int e1 = dvrSetupGlobalBuffer(buffer_key, 10, usage, &setup_buffer);
ASSERT_NE(nullptr, setup_buffer);
ASSERT_EQ(0, e1);
@@ -156,7 +134,7 @@
AHardwareBuffer_release(hardware_buffer);
}
-TEST_F(DvrGlobalBufferTest, TestGlobalBufferCarriesData) {
+TEST(DvrGlobalBufferTest, TestGlobalBufferCarriesData) {
const DvrGlobalBufferKey buffer_name = 110;
uint64_t usage = AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN |
@@ -167,8 +145,7 @@
{
// Allocate some data and set it to something.
DvrBuffer* setup_buffer = nullptr;
- int e1 = dvrDisplayManagerSetupGlobalBuffer(client_, buffer_name, size,
- usage, &setup_buffer);
+ int e1 = dvrSetupGlobalBuffer(buffer_name, size, usage, &setup_buffer);
ASSERT_NE(nullptr, setup_buffer);
ASSERT_EQ(0, e1);
@@ -234,7 +211,7 @@
}
}
-TEST_F(DvrGlobalBufferTest, TestGlobalBufferZeroed) {
+TEST(DvrGlobalBufferTest, TestGlobalBufferZeroed) {
const DvrGlobalBufferKey buffer_name = 120;
// Allocate 1MB and check that it is all zeros.
@@ -242,8 +219,7 @@
AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN;
constexpr size_t size = 1024 * 1024;
DvrBuffer* setup_buffer = nullptr;
- int e1 = dvrDisplayManagerSetupGlobalBuffer(client_, buffer_name, size, usage,
- &setup_buffer);
+ int e1 = dvrSetupGlobalBuffer(buffer_name, size, usage, &setup_buffer);
ASSERT_NE(nullptr, setup_buffer);
ASSERT_EQ(0, e1);
@@ -275,29 +251,28 @@
AHardwareBuffer_release(hardware_buffer);
}
-TEST_F(DvrGlobalBufferTest, TestVrflingerConfigBuffer) {
+TEST(DvrGlobalBufferTest, TestVrflingerConfigBuffer) {
const DvrGlobalBufferKey buffer_name =
DvrGlobalBuffers::kVrFlingerConfigBufferKey;
// First delete any existing buffer so we can test the failure case.
- dvrDisplayManagerDeleteGlobalBuffer(client_, buffer_name);
+ dvrDeleteGlobalBuffer(buffer_name);
const uint64_t usage = AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN |
AHARDWAREBUFFER_USAGE_CPU_WRITE_RARELY;
- size_t correct_size = DvrVrFlingerConfigRing::MemorySize();
- size_t wrong_size = DvrVrFlingerConfigRing::MemorySize(0);
+ size_t correct_size = DvrConfigRing::MemorySize();
+ size_t wrong_size = DvrConfigRing::MemorySize(0);
// Setup an invalid config buffer (too small) and assert that it fails.
DvrBuffer* setup_buffer = nullptr;
- int e1 = dvrDisplayManagerSetupGlobalBuffer(client_, buffer_name, wrong_size,
- usage, &setup_buffer);
+ int e1 = dvrSetupGlobalBuffer(buffer_name, wrong_size, usage, &setup_buffer);
ASSERT_EQ(nullptr, setup_buffer);
ASSERT_GT(0, e1);
// Setup a correct config buffer.
- int e2 = dvrDisplayManagerSetupGlobalBuffer(
- client_, buffer_name, correct_size, usage, &setup_buffer);
+ int e2 =
+ dvrSetupGlobalBuffer(buffer_name, correct_size, usage, &setup_buffer);
ASSERT_NE(nullptr, setup_buffer);
ASSERT_EQ(0, e2);
diff --git a/libs/vr/libpdx/Android.bp b/libs/vr/libpdx/Android.bp
index 69300d6..10c0b31 100644
--- a/libs/vr/libpdx/Android.bp
+++ b/libs/vr/libpdx/Android.bp
@@ -5,12 +5,15 @@
"-Wall",
"-Wextra",
"-Werror",
+ "-DLOG_TAG=\"libpdx\"",
+ "-DTRACE=0",
],
export_include_dirs: ["private"],
local_include_dirs: ["private"],
srcs: [
"client.cpp",
"service.cpp",
+ "service_dispatcher.cpp",
"status.cpp",
],
}
@@ -33,10 +36,12 @@
"variant_tests.cpp",
],
static_libs: [
+ "libcutils",
"libgmock",
"libpdx",
"liblog",
"libutils",
+ "libvndksupport",
],
}
diff --git a/libs/vr/libpdx/client.cpp b/libs/vr/libpdx/client.cpp
index bfa2d87..a01c4d6 100644
--- a/libs/vr/libpdx/client.cpp
+++ b/libs/vr/libpdx/client.cpp
@@ -1,6 +1,5 @@
#include "pdx/client.h"
-#define LOG_TAG "ServiceFramework"
#include <log/log.h>
#include <pdx/trace.h>
diff --git a/libs/vr/libpdx/mock_tests.cpp b/libs/vr/libpdx/mock_tests.cpp
index 76fd154..4143837 100644
--- a/libs/vr/libpdx/mock_tests.cpp
+++ b/libs/vr/libpdx/mock_tests.cpp
@@ -3,7 +3,6 @@
#include <pdx/mock_client_channel_factory.h>
#include <pdx/mock_message_reader.h>
#include <pdx/mock_message_writer.h>
-#include <pdx/mock_service_dispatcher.h>
#include <pdx/mock_service_endpoint.h>
TEST(MockTypes, Instantiation) {
@@ -15,6 +14,5 @@
android::pdx::MockMessageReader message_reader;
android::pdx::MockOutputResourceMapper output_resource_mapper;
android::pdx::MockMessageWriter message_writer;
- android::pdx::MockServiceDispatcher service_dispatcher;
android::pdx::MockEndpoint endpoint;
}
diff --git a/libs/vr/libpdx/private/pdx/client_channel.h b/libs/vr/libpdx/private/pdx/client_channel.h
index dbfd626..10a49bb 100644
--- a/libs/vr/libpdx/private/pdx/client_channel.h
+++ b/libs/vr/libpdx/private/pdx/client_channel.h
@@ -1,6 +1,8 @@
#ifndef ANDROID_PDX_CLIENT_CHANNEL_H_
#define ANDROID_PDX_CLIENT_CHANNEL_H_
+#include <vector>
+
#include <pdx/channel_handle.h>
#include <pdx/file_handle.h>
#include <pdx/status.h>
@@ -20,6 +22,15 @@
virtual int event_fd() const = 0;
virtual Status<int> GetEventMask(int events) = 0;
+ struct EventSource {
+ int event_fd;
+ int event_mask;
+ };
+
+ // Returns a set of event-generating fds with and event mask for each. These
+ // fds are owned by the ClientChannel and must never be closed by the caller.
+ virtual std::vector<EventSource> GetEventSources() const = 0;
+
virtual LocalChannelHandle& GetChannelHandle() = 0;
virtual void* AllocateTransactionState() = 0;
virtual void FreeTransactionState(void* state) = 0;
diff --git a/libs/vr/libpdx/private/pdx/mock_client_channel.h b/libs/vr/libpdx/private/pdx/mock_client_channel.h
index 561c939..49e0682 100644
--- a/libs/vr/libpdx/private/pdx/mock_client_channel.h
+++ b/libs/vr/libpdx/private/pdx/mock_client_channel.h
@@ -11,6 +11,7 @@
public:
MOCK_CONST_METHOD0(GetIpcTag, uint32_t());
MOCK_CONST_METHOD0(event_fd, int());
+ MOCK_CONST_METHOD0(GetEventSources, std::vector<EventSource>());
MOCK_METHOD1(GetEventMask, Status<int>(int));
MOCK_METHOD0(GetChannelHandle, LocalChannelHandle&());
MOCK_METHOD0(AllocateTransactionState, void*());
diff --git a/libs/vr/libpdx/private/pdx/mock_service_dispatcher.h b/libs/vr/libpdx/private/pdx/mock_service_dispatcher.h
deleted file mode 100644
index 9b51d30..0000000
--- a/libs/vr/libpdx/private/pdx/mock_service_dispatcher.h
+++ /dev/null
@@ -1,24 +0,0 @@
-#ifndef ANDROID_PDX_MOCK_SERVICE_DISPATCHER_H_
-#define ANDROID_PDX_MOCK_SERVICE_DISPATCHER_H_
-
-#include <gmock/gmock.h>
-#include <pdx/service_dispatcher.h>
-
-namespace android {
-namespace pdx {
-
-class MockServiceDispatcher : public ServiceDispatcher {
- public:
- MOCK_METHOD1(AddService, int(const std::shared_ptr<Service>& service));
- MOCK_METHOD1(RemoveService, int(const std::shared_ptr<Service>& service));
- MOCK_METHOD0(ReceiveAndDispatch, int());
- MOCK_METHOD1(ReceiveAndDispatch, int(int timeout));
- MOCK_METHOD0(EnterDispatchLoop, int());
- MOCK_METHOD1(SetCanceled, void(bool cancel));
- MOCK_CONST_METHOD0(IsCanceled, bool());
-};
-
-} // namespace pdx
-} // namespace android
-
-#endif // ANDROID_PDX_MOCK_SERVICE_DISPATCHER_H_
diff --git a/libs/vr/libpdx/private/pdx/mock_service_endpoint.h b/libs/vr/libpdx/private/pdx/mock_service_endpoint.h
index e741d4a..7f829e7 100644
--- a/libs/vr/libpdx/private/pdx/mock_service_endpoint.h
+++ b/libs/vr/libpdx/private/pdx/mock_service_endpoint.h
@@ -66,6 +66,7 @@
MOCK_METHOD0(AllocateMessageState, void*());
MOCK_METHOD1(FreeMessageState, void(void* state));
MOCK_METHOD0(Cancel, Status<void>());
+ MOCK_CONST_METHOD0(epoll_fd, int());
};
} // namespace pdx
diff --git a/libs/vr/libpdx/private/pdx/rpc/variant.h b/libs/vr/libpdx/private/pdx/rpc/variant.h
index cb44a51..80b1769 100644
--- a/libs/vr/libpdx/private/pdx/rpc/variant.h
+++ b/libs/vr/libpdx/private/pdx/rpc/variant.h
@@ -26,14 +26,35 @@
template <std::size_t I, typename... Types>
using TypeTagForIndex = TypeTag<TypeForIndex<I, Types...>>;
+// Similar to std::is_constructible except that it evaluates to false for bool
+// construction from pointer types: this helps prevent subtle to bugs caused by
+// assigning values that decay to pointers to Variants with bool elements.
+//
+// Here is an example of the problematic situation this trait avoids:
+//
+// Variant<int, bool> v;
+// const int array[3] = {1, 2, 3};
+// v = array; // This is allowed by regular std::is_constructible.
+//
+template <typename...>
+struct IsConstructible;
+template <typename T, typename U>
+struct IsConstructible<T, U>
+ : std::integral_constant<bool,
+ std::is_constructible<T, U>::value &&
+ !(std::is_same<std::decay_t<T>, bool>::value &&
+ std::is_pointer<std::decay_t<U>>::value)> {};
+template <typename T, typename... Args>
+struct IsConstructible<T, Args...> : std::is_constructible<T, Args...> {};
+
// Enable if T(Args...) is well formed.
template <typename R, typename T, typename... Args>
using EnableIfConstructible =
- typename std::enable_if<std::is_constructible<T, Args...>::value, R>::type;
+ typename std::enable_if<IsConstructible<T, Args...>::value, R>::type;
// Enable if T(Args...) is not well formed.
template <typename R, typename T, typename... Args>
using EnableIfNotConstructible =
- typename std::enable_if<!std::is_constructible<T, Args...>::value, R>::type;
+ typename std::enable_if<!IsConstructible<T, Args...>::value, R>::type;
// Determines whether T is an element of Types...;
template <typename... Types>
@@ -65,12 +86,11 @@
struct ConstructibleCount;
template <typename From, typename To>
struct ConstructibleCount<From, To>
- : std::integral_constant<std::size_t,
- std::is_constructible<To, From>::value> {};
+ : std::integral_constant<std::size_t, IsConstructible<To, From>::value> {};
template <typename From, typename First, typename... Rest>
struct ConstructibleCount<From, First, Rest...>
: std::integral_constant<std::size_t,
- std::is_constructible<First, From>::value +
+ IsConstructible<First, From>::value +
ConstructibleCount<From, Rest...>::value> {};
// Enable if T is an element of Types...
@@ -126,6 +146,18 @@
: first_(std::forward<T>(value)) {
*index_out = index;
}
+ Union(const Union& other, std::int32_t index) {
+ if (index == 0)
+ new (&first_) Type(other.first_);
+ }
+ Union(Union&& other, std::int32_t index) {
+ if (index == 0)
+ new (&first_) Type(std::move(other.first_));
+ }
+ Union(const Union&) = delete;
+ Union(Union&&) = delete;
+ void operator=(const Union&) = delete;
+ void operator=(Union&&) = delete;
Type& get(TypeTag<Type>) { return first_; }
const Type& get(TypeTag<Type>) const { return first_; }
@@ -217,6 +249,22 @@
template <typename T, typename U>
Union(std::int32_t index, std::int32_t* index_out, TypeTag<T>, U&& value)
: rest_(index + 1, index_out, TypeTag<T>{}, std::forward<U>(value)) {}
+ Union(const Union& other, std::int32_t index) {
+ if (index == 0)
+ new (&first_) First(other.first_);
+ else
+ new (&rest_) Union<Rest...>(other.rest_, index - 1);
+ }
+ Union(Union&& other, std::int32_t index) {
+ if (index == 0)
+ new (&first_) First(std::move(other.first_));
+ else
+ new (&rest_) Union<Rest...>(std::move(other.rest_), index - 1);
+ }
+ Union(const Union&) = delete;
+ Union(Union&&) = delete;
+ void operator=(const Union&) = delete;
+ void operator=(Union&&) = delete;
struct FirstType {};
struct RestType {};
@@ -351,6 +399,10 @@
} // namespace detail
+// Variant is a type safe union that can store values of any of its element
+// types. A Variant is different than std::tuple in that it only stores one type
+// at a time or a special empty type. Variants are always default constructible
+// to empty, even when none of the element types are default constructible.
template <typename... Types>
class Variant {
private:
@@ -393,6 +445,11 @@
explicit Variant(EmptyVariant) {}
~Variant() { Destruct(); }
+ Variant(const Variant& other)
+ : index_{other.index_}, value_{other.value_, other.index_} {}
+ Variant(Variant&& other)
+ : index_{other.index_}, value_{std::move(other.value_), other.index_} {}
+
// Copy and move construction from Variant types. Each element of OtherTypes
// must be convertible to an element of Types.
template <typename... OtherTypes>
@@ -404,6 +461,15 @@
other.Visit([this](auto&& value) { Construct(std::move(value)); });
}
+ Variant& operator=(const Variant& other) {
+ other.Visit([this](const auto& value) { *this = value; });
+ return *this;
+ }
+ Variant& operator=(Variant&& other) {
+ other.Visit([this](auto&& value) { *this = std::move(value); });
+ return *this;
+ }
+
// Construction from non-Variant types.
template <typename T, typename = EnableIfAssignable<void, T>>
explicit Variant(T&& value)
@@ -429,7 +495,7 @@
// Handles assignment from the empty type. This overload supports assignment
// in visitors using generic lambdas.
Variant& operator=(EmptyVariant) {
- Assign(EmptyVariant{});
+ Destruct();
return *this;
}
@@ -541,7 +607,10 @@
void Construct(EmptyVariant) {}
// Destroys the active element of the Variant.
- void Destruct() { value_.Destruct(index_); }
+ void Destruct() {
+ value_.Destruct(index_);
+ index_ = kEmptyIndex;
+ }
// Assigns the Variant when non-empty and the current type matches the target
// type, otherwise destroys the current value and constructs a element of the
@@ -562,8 +631,6 @@
Construct(std::forward<T>(value));
}
}
- // Handles assignment from an empty Variant.
- void Assign(EmptyVariant) { Destruct(); }
};
// Utility type to extract/convert values from a variant. This class simplifies
diff --git a/libs/vr/libpdx/private/pdx/service_dispatcher.h b/libs/vr/libpdx/private/pdx/service_dispatcher.h
index c5e342a..bd27000 100644
--- a/libs/vr/libpdx/private/pdx/service_dispatcher.h
+++ b/libs/vr/libpdx/private/pdx/service_dispatcher.h
@@ -2,6 +2,11 @@
#define ANDROID_PDX_SERVICE_DISPATCHER_H_
#include <memory>
+#include <mutex>
+#include <unordered_map>
+#include <vector>
+
+#include <pdx/file_handle.h>
namespace android {
namespace pdx {
@@ -15,7 +20,10 @@
*/
class ServiceDispatcher {
public:
- virtual ~ServiceDispatcher() = default;
+ // Get a new instance of ServiceDispatcher, or return nullptr if init failed.
+ static std::unique_ptr<ServiceDispatcher> Create();
+
+ ~ServiceDispatcher();
/*
* Adds a service to the list of services handled by this dispatcher. This
@@ -24,7 +32,7 @@
*
* Returns 0 on success; -EEXIST if the service was already added.
*/
- virtual int AddService(const std::shared_ptr<Service>& service) = 0;
+ int AddService(const std::shared_ptr<Service>& service);
/*
* Removes a service from this dispatcher. This will fail if any threads are
@@ -33,7 +41,7 @@
* Returns 0 on success; -ENOENT if the service was not previously added;
* -EBUSY if there are threads in the dispatcher.
*/
- virtual int RemoveService(const std::shared_ptr<Service>& service) = 0;
+ int RemoveService(const std::shared_ptr<Service>& service);
/*
* Receive and dispatch one set of messages. Multiple threads may enter this
@@ -42,14 +50,14 @@
* cycle, requiring an external loop. This is useful when other work needs
* to be done in the service dispatch loop.
*/
- virtual int ReceiveAndDispatch() = 0;
+ int ReceiveAndDispatch();
/*
* Same as above with timeout in milliseconds. A negative value means
* infinite timeout, while a value of 0 means return immediately if no
* messages are available to receive.
*/
- virtual int ReceiveAndDispatch(int timeout) = 0;
+ int ReceiveAndDispatch(int timeout);
/*
* Receive and dispatch messages until canceled. When more than one thread
@@ -58,19 +66,39 @@
* hands Message instances (via move assignment) over to a queue of threads
* (or perhaps one of several) to handle.
*/
- virtual int EnterDispatchLoop() = 0;
+ int EnterDispatchLoop();
/*
* Sets the canceled state of the dispatcher. When canceled is true, any
* threads blocked waiting for messages will return. This method waits until
* all dispatch threads have exited the dispatcher.
*/
- virtual void SetCanceled(bool cancel) = 0;
+ void SetCanceled(bool cancel);
/*
* Gets the canceled state of the dispatcher.
*/
- virtual bool IsCanceled() const = 0;
+ bool IsCanceled() const;
+
+ private:
+ ServiceDispatcher();
+
+ // Internal thread accounting.
+ int ThreadEnter();
+ void ThreadExit();
+
+ std::mutex mutex_;
+ std::condition_variable condition_;
+ std::atomic<bool> canceled_{false};
+
+ std::vector<std::shared_ptr<Service>> services_;
+
+ int thread_count_ = 0;
+ LocalHandle event_fd_;
+ LocalHandle epoll_fd_;
+
+ ServiceDispatcher(const ServiceDispatcher&) = delete;
+ void operator=(const ServiceDispatcher&) = delete;
};
} // namespace pdx
diff --git a/libs/vr/libpdx/private/pdx/service_endpoint.h b/libs/vr/libpdx/private/pdx/service_endpoint.h
index 28bd6bc..d581894 100644
--- a/libs/vr/libpdx/private/pdx/service_endpoint.h
+++ b/libs/vr/libpdx/private/pdx/service_endpoint.h
@@ -136,6 +136,10 @@
// Cancels the endpoint, unblocking any receiver threads waiting for a
// message.
virtual Status<void> Cancel() = 0;
+
+ // Returns an fd that can be used with epoll() to wait for incoming messages
+ // from this endpoint.
+ virtual int epoll_fd() const = 0;
};
} // namespace pdx
diff --git a/libs/vr/libpdx/private/pdx/trace.h b/libs/vr/libpdx/private/pdx/trace.h
index ebe8491..c687fd6 100644
--- a/libs/vr/libpdx/private/pdx/trace.h
+++ b/libs/vr/libpdx/private/pdx/trace.h
@@ -1,35 +1,82 @@
#ifndef ANDROID_PDX_TRACE_H_
#define ANDROID_PDX_TRACE_H_
-// Tracing utilities for libpdx. Tracing in the service framework is enabled
-// under these conditions:
-// 1. ATRACE_TAG is defined, AND
-// 2. ATRACE_TAG does not equal ATRACE_TAG_NEVER, AND
-// 3. PDX_TRACE_ENABLED is defined, AND
-// 4. PDX_TRACE_ENABLED is equal to logical true.
-//
-// If any of these conditions are not met tracing is completely removed from the
-// library and headers.
+#include <array>
-// If ATRACE_TAG is not defined, default to never.
-#ifndef ATRACE_TAG
-#define ATRACE_TAG ATRACE_TAG_NEVER
-#endif
-
-// Include tracing functions after the trace tag is defined.
#include <utils/Trace.h>
-// If PDX_TRACE_ENABLED is not defined, default to off.
-#ifndef PDX_TRACE_ENABLED
-#define PDX_TRACE_ENABLED 0
+// Enables internal tracing in libpdx. This is disabled by default to avoid
+// spamming the trace buffers during normal trace activities. libpdx must be
+// built with this set to true to enable internal tracing.
+#ifndef PDX_LIB_TRACE_ENABLED
+#define PDX_LIB_TRACE_ENABLED false
#endif
-#if (ATRACE_TAG) != (ATRACE_TAG_NEVER) && (PDX_TRACE_ENABLED)
-#define PDX_TRACE_NAME ATRACE_NAME
-#else
-#define PDX_TRACE_NAME(name) \
- do { \
- } while (0)
-#endif
+namespace android {
+namespace pdx {
+
+// Utility to generate scoped tracers with arguments.
+class ScopedTraceArgs {
+ public:
+ template <typename... Args>
+ ScopedTraceArgs(uint64_t tag, const char* format, Args&&... args)
+ : tag_{tag} {
+ if (atrace_is_tag_enabled(tag_)) {
+ std::array<char, 1024> buffer;
+ snprintf(buffer.data(), buffer.size(), format,
+ std::forward<Args>(args)...);
+ atrace_begin(tag_, buffer.data());
+ }
+ }
+
+ ~ScopedTraceArgs() { atrace_end(tag_); }
+
+ private:
+ uint64_t tag_;
+
+ ScopedTraceArgs(const ScopedTraceArgs&) = delete;
+ void operator=(const ScopedTraceArgs&) = delete;
+};
+
+// Utility to generate scoped tracers.
+class ScopedTrace {
+ public:
+ template <typename... Args>
+ ScopedTrace(uint64_t tag, bool enabled, const char* name)
+ : tag_{tag}, enabled_{enabled} {
+ if (enabled_)
+ atrace_begin(tag_, name);
+ }
+
+ ~ScopedTrace() {
+ if (enabled_)
+ atrace_end(tag_);
+ }
+
+ private:
+ uint64_t tag_;
+ bool enabled_;
+
+ ScopedTrace(const ScopedTrace&) = delete;
+ void operator=(const ScopedTrace&) = delete;
+};
+
+} // namespace pdx
+} // namespace android
+
+// Macro to define a scoped tracer with arguments. Uses PASTE(x, y) macro
+// defined in utils/Trace.h.
+#define PDX_TRACE_FORMAT(format, ...) \
+ ::android::pdx::ScopedTraceArgs PASTE(__tracer, __LINE__) { \
+ ATRACE_TAG, format, ##__VA_ARGS__ \
+ }
+
+// TODO(eieio): Rename this to PDX_LIB_TRACE_NAME() for internal use by libpdx
+// and rename internal uses inside the library. This version is only enabled
+// when PDX_LIB_TRACE_ENABLED is true.
+#define PDX_TRACE_NAME(name) \
+ ::android::pdx::ScopedTrace PASTE(__tracer, __LINE__) { \
+ ATRACE_TAG, PDX_LIB_TRACE_ENABLED, name \
+ }
#endif // ANDROID_PDX_TRACE_H_
diff --git a/libs/vr/libpdx/private/pdx/utility.h b/libs/vr/libpdx/private/pdx/utility.h
index 305c3b8..08fcaea 100644
--- a/libs/vr/libpdx/private/pdx/utility.h
+++ b/libs/vr/libpdx/private/pdx/utility.h
@@ -2,6 +2,7 @@
#define ANDROID_PDX_UTILITY_H_
#include <cstdint>
+#include <cstdlib>
#include <iterator>
#include <pdx/rpc/sequence.h>
@@ -23,6 +24,7 @@
if (other.size())
memcpy(data_, other.data(), other.size());
}
+ ~ByteBuffer() { std::free(data_); }
ByteBuffer& operator=(const ByteBuffer& other) {
resize(other.size());
@@ -69,7 +71,7 @@
size |= size >> 8;
size |= size >> 16;
size++;
- void* new_data = data_ ? realloc(data_, size) : malloc(size);
+ void* new_data = data_ ? std::realloc(data_, size) : std::malloc(size);
// TODO(avakulenko): Check for allocation failures.
data_ = static_cast<uint8_t*>(new_data);
capacity_ = size;
diff --git a/libs/vr/libpdx/service.cpp b/libs/vr/libpdx/service.cpp
index fab4770..1d3b62a 100644
--- a/libs/vr/libpdx/service.cpp
+++ b/libs/vr/libpdx/service.cpp
@@ -1,4 +1,3 @@
-#define LOG_TAG "ServiceFramework"
#include "pdx/service.h"
#include <fcntl.h>
@@ -10,8 +9,6 @@
#include <pdx/trace.h>
-#define TRACE 0
-
namespace android {
namespace pdx {
diff --git a/libs/vr/libpdx_uds/service_dispatcher.cpp b/libs/vr/libpdx/service_dispatcher.cpp
similarity index 83%
rename from libs/vr/libpdx_uds/service_dispatcher.cpp
rename to libs/vr/libpdx/service_dispatcher.cpp
index 2c52578..b112fa3 100644
--- a/libs/vr/libpdx_uds/service_dispatcher.cpp
+++ b/libs/vr/libpdx/service_dispatcher.cpp
@@ -1,26 +1,25 @@
-#include "uds/service_dispatcher.h"
+#include <pdx/service_dispatcher.h>
#include <errno.h>
#include <log/log.h>
#include <sys/epoll.h>
#include <sys/eventfd.h>
-#include "pdx/service.h"
-#include "uds/service_endpoint.h"
+#include <pdx/service.h>
+#include <pdx/service_endpoint.h>
static const int kMaxEventsPerLoop = 128;
namespace android {
namespace pdx {
-namespace uds {
-std::unique_ptr<pdx::ServiceDispatcher> ServiceDispatcher::Create() {
+std::unique_ptr<ServiceDispatcher> ServiceDispatcher::Create() {
std::unique_ptr<ServiceDispatcher> dispatcher{new ServiceDispatcher()};
if (!dispatcher->epoll_fd_ || !dispatcher->event_fd_) {
dispatcher.reset();
}
- return std::move(dispatcher);
+ return dispatcher;
}
ServiceDispatcher::ServiceDispatcher() {
@@ -70,18 +69,14 @@
}
int ServiceDispatcher::AddService(const std::shared_ptr<Service>& service) {
- if (service->endpoint()->GetIpcTag() != Endpoint::kIpcTag)
- return -EINVAL;
-
std::lock_guard<std::mutex> autolock(mutex_);
- auto* endpoint = static_cast<Endpoint*>(service->endpoint());
epoll_event event;
event.events = EPOLLIN;
event.data.ptr = service.get();
- if (epoll_ctl(epoll_fd_.Get(), EPOLL_CTL_ADD, endpoint->epoll_fd(), &event) <
- 0) {
+ if (epoll_ctl(epoll_fd_.Get(), EPOLL_CTL_ADD, service->endpoint()->epoll_fd(),
+ &event) < 0) {
ALOGE("Failed to add service to dispatcher because: %s\n", strerror(errno));
return -errno;
}
@@ -91,9 +86,6 @@
}
int ServiceDispatcher::RemoveService(const std::shared_ptr<Service>& service) {
- if (service->endpoint()->GetIpcTag() != Endpoint::kIpcTag)
- return -EINVAL;
-
std::lock_guard<std::mutex> autolock(mutex_);
// It's dangerous to remove a service while other threads may be using it.
@@ -101,16 +93,15 @@
return -EBUSY;
epoll_event dummy; // See BUGS in man 2 epoll_ctl.
-
- auto* endpoint = static_cast<Endpoint*>(service->endpoint());
- if (epoll_ctl(epoll_fd_.Get(), EPOLL_CTL_DEL, endpoint->epoll_fd(), &dummy) <
- 0) {
+ if (epoll_ctl(epoll_fd_.Get(), EPOLL_CTL_DEL, service->endpoint()->epoll_fd(),
+ &dummy) < 0) {
ALOGE("Failed to remove service from dispatcher because: %s\n",
strerror(errno));
return -errno;
}
- services_.remove(service);
+ services_.erase(std::remove(services_.begin(), services_.end(), service),
+ services_.end());
return 0;
}
@@ -139,7 +130,7 @@
Service* service = static_cast<Service*>(events[i].data.ptr);
ALOGI_IF(TRACE, "Dispatching message: fd=%d\n",
- static_cast<Endpoint*>(service->endpoint())->epoll_fd());
+ service->endpoint()->epoll_fd());
service->ReceiveAndDispatch();
}
}
@@ -171,7 +162,7 @@
Service* service = static_cast<Service*>(events[i].data.ptr);
ALOGI_IF(TRACE, "Dispatching message: fd=%d\n",
- static_cast<Endpoint*>(service->endpoint())->epoll_fd());
+ service->endpoint()->epoll_fd());
service->ReceiveAndDispatch();
}
}
@@ -197,6 +188,5 @@
bool ServiceDispatcher::IsCanceled() const { return canceled_; }
-} // namespace uds
} // namespace pdx
} // namespace android
diff --git a/libs/vr/libpdx/variant_tests.cpp b/libs/vr/libpdx/variant_tests.cpp
index 325f33f..e3520f5 100644
--- a/libs/vr/libpdx/variant_tests.cpp
+++ b/libs/vr/libpdx/variant_tests.cpp
@@ -1,3 +1,4 @@
+#include <array>
#include <cstdint>
#include <functional>
#include <memory>
@@ -584,6 +585,25 @@
EXPECT_EQ(0u, InstrumentType<int>::move_assignment_count());
EXPECT_EQ(1u, InstrumentType<int>::copy_assignment_count());
}
+
+ {
+ InstrumentType<int>::clear();
+
+ // Construct from temporary, temporary ctor/dtor.
+ Variant<int, InstrumentType<int>> v(InstrumentType<int>(25));
+
+ // Assign EmptyVariant.
+ v = EmptyVariant{};
+
+ EXPECT_EQ(2u, InstrumentType<int>::constructor_count());
+ EXPECT_EQ(2u, InstrumentType<int>::destructor_count());
+ EXPECT_EQ(0u, InstrumentType<int>::move_assignment_count());
+ EXPECT_EQ(0u, InstrumentType<int>::copy_assignment_count());
+ }
+ EXPECT_EQ(2u, InstrumentType<int>::constructor_count());
+ EXPECT_EQ(2u, InstrumentType<int>::destructor_count());
+ EXPECT_EQ(0u, InstrumentType<int>::move_assignment_count());
+ EXPECT_EQ(0u, InstrumentType<int>::copy_assignment_count());
}
TEST(Variant, MoveConstructor) {
@@ -758,7 +778,7 @@
Variant<std::string> b;
std::swap(a, b);
- EXPECT_TRUE(!a.empty());
+ EXPECT_TRUE(a.empty());
EXPECT_TRUE(!b.empty());
ASSERT_TRUE(b.is<std::string>());
EXPECT_EQ("1", std::get<std::string>(b));
@@ -770,7 +790,7 @@
std::swap(a, b);
EXPECT_TRUE(!a.empty());
- EXPECT_TRUE(!b.empty());
+ EXPECT_TRUE(b.empty());
ASSERT_TRUE(a.is<std::string>());
EXPECT_EQ("1", std::get<std::string>(a));
}
@@ -1078,6 +1098,29 @@
EXPECT_FALSE((detail::HasType<char&, int, float, bool>::value));
}
+TEST(Variant, IsConstructible) {
+ using ArrayType = const float[3];
+ struct ImplicitBool {
+ operator bool() const { return true; }
+ };
+ struct ExplicitBool {
+ explicit operator bool() const { return true; }
+ };
+ struct NonBool {};
+ struct TwoArgs {
+ TwoArgs(int, bool) {}
+ };
+
+ EXPECT_FALSE((detail::IsConstructible<bool, ArrayType>::value));
+ EXPECT_TRUE((detail::IsConstructible<bool, int>::value));
+ EXPECT_TRUE((detail::IsConstructible<bool, ImplicitBool>::value));
+ EXPECT_TRUE((detail::IsConstructible<bool, ExplicitBool>::value));
+ EXPECT_FALSE((detail::IsConstructible<bool, NonBool>::value));
+ EXPECT_TRUE((detail::IsConstructible<TwoArgs, int, bool>::value));
+ EXPECT_FALSE((detail::IsConstructible<TwoArgs, int, std::string>::value));
+ EXPECT_FALSE((detail::IsConstructible<TwoArgs, int>::value));
+}
+
TEST(Variant, Set) {
EXPECT_TRUE((detail::Set<int, bool, float>::template IsSubset<int, bool,
float>::value));
diff --git a/libs/vr/libpdx_default_transport/Android.bp b/libs/vr/libpdx_default_transport/Android.bp
index 8cfa86f..f891c59 100644
--- a/libs/vr/libpdx_default_transport/Android.bp
+++ b/libs/vr/libpdx_default_transport/Android.bp
@@ -36,12 +36,13 @@
}
cc_binary {
- name: "servicetool",
+ name: "pdx_tool",
defaults: ["pdx_default_transport_compiler_defaults"],
srcs: [
- "servicetool.cpp",
+ "pdx_tool.cpp",
],
shared_libs: [
+ "libcutils",
"liblog",
],
static_libs: [
diff --git a/libs/vr/libpdx_default_transport/servicetool.cpp b/libs/vr/libpdx_default_transport/pdx_tool.cpp
similarity index 100%
rename from libs/vr/libpdx_default_transport/servicetool.cpp
rename to libs/vr/libpdx_default_transport/pdx_tool.cpp
diff --git a/libs/vr/libpdx_default_transport/private/servicefs/pdx/default_transport/service_dispatcher.h b/libs/vr/libpdx_default_transport/private/servicefs/pdx/default_transport/service_dispatcher.h
deleted file mode 100644
index 158871c..0000000
--- a/libs/vr/libpdx_default_transport/private/servicefs/pdx/default_transport/service_dispatcher.h
+++ /dev/null
@@ -1,17 +0,0 @@
-#ifndef ANDROID_PDX_DEFAULT_TRANSPORT_SERVICEFS_SERVICE_DISPATCHER_H_
-#define ANDROID_PDX_DEFAULT_TRANSPORT_SERVICEFS_SERVICE_DISPATCHER_H_
-
-#include <servicefs/service_dispatcher.h>
-
-namespace android {
-namespace pdx {
-namespace default_transport {
-
-using ServiceDispatcher = ::android::pdx::servicefs::ServiceDispatcher;
-
-} // namespace default_transport
-} // namespace pdx
-} // namespace android
-
-
-#endif // ANDROID_PDX_DEFAULT_TRANSPORT_SERVICEFS_SERVICE_DISPATCHER_H_
diff --git a/libs/vr/libpdx_default_transport/private/uds/pdx/default_transport/service_dispatcher.h b/libs/vr/libpdx_default_transport/private/uds/pdx/default_transport/service_dispatcher.h
deleted file mode 100644
index 7cb7a80..0000000
--- a/libs/vr/libpdx_default_transport/private/uds/pdx/default_transport/service_dispatcher.h
+++ /dev/null
@@ -1,17 +0,0 @@
-#ifndef ANDROID_PDX_DEFAULT_TRANSPORT_UDS_SERVICE_DISPATCHER_H_
-#define ANDROID_PDX_DEFAULT_TRANSPORT_UDS_SERVICE_DISPATCHER_H_
-
-#include <uds/service_dispatcher.h>
-
-namespace android {
-namespace pdx {
-namespace default_transport {
-
-using ServiceDispatcher = ::android::pdx::uds::ServiceDispatcher;
-
-} // namespace default_transport
-} // namespace pdx
-} // namespace android
-
-
-#endif // ANDROID_PDX_DEFAULT_TRANSPORT_UDS_SERVICE_DISPATCHER_H_
diff --git a/libs/vr/libpdx_uds/Android.bp b/libs/vr/libpdx_uds/Android.bp
index 82a5ea7..d0b7cab 100644
--- a/libs/vr/libpdx_uds/Android.bp
+++ b/libs/vr/libpdx_uds/Android.bp
@@ -16,7 +16,6 @@
"client_channel_factory.cpp",
"client_channel.cpp",
"ipc_helper.cpp",
- "service_dispatcher.cpp",
"service_endpoint.cpp",
],
static_libs: [
diff --git a/libs/vr/libpdx_uds/channel_event_set.cpp b/libs/vr/libpdx_uds/channel_event_set.cpp
index ac4dea9..c68968e 100644
--- a/libs/vr/libpdx_uds/channel_event_set.cpp
+++ b/libs/vr/libpdx_uds/channel_event_set.cpp
@@ -1,6 +1,10 @@
#include "private/uds/channel_event_set.h"
+#include <errno.h>
#include <log/log.h>
+#include <poll.h>
+#include <sys/epoll.h>
+#include <sys/eventfd.h>
#include <uds/ipc_helper.h>
@@ -8,41 +12,34 @@
namespace pdx {
namespace uds {
-ChannelEventSet::ChannelEventSet() {
- const int flags = EFD_CLOEXEC | EFD_NONBLOCK;
- LocalHandle epoll_fd, event_fd;
+namespace {
- if (!SetupHandle(epoll_create1(EPOLL_CLOEXEC), &epoll_fd, "epoll") ||
- !SetupHandle(eventfd(0, flags), &event_fd, "event")) {
- return;
- }
-
- epoll_event event;
- event.events = 0;
- event.data.u32 = 0;
- if (epoll_ctl(epoll_fd.Get(), EPOLL_CTL_ADD, event_fd.Get(), &event) < 0) {
- const int error = errno;
- ALOGE("ChannelEventSet::ChannelEventSet: Failed to add event_fd: %s",
- strerror(error));
- return;
- }
-
- epoll_fd_ = std::move(epoll_fd);
- event_fd_ = std::move(event_fd);
-}
-
-Status<void> ChannelEventSet::AddDataFd(const LocalHandle& data_fd) {
- epoll_event event;
- event.events = EPOLLHUP | EPOLLRDHUP;
- event.data.u32 = event.events;
- if (epoll_ctl(epoll_fd_.Get(), EPOLL_CTL_ADD, data_fd.Get(), &event) < 0) {
- const int error = errno;
- ALOGE("ChannelEventSet::ChannelEventSet: Failed to add event_fd: %s",
+template <typename FileHandleType>
+Status<void> SetupHandle(int fd, FileHandleType* handle,
+ const char* error_name) {
+ const int error = errno;
+ handle->Reset(fd);
+ if (!*handle) {
+ ALOGE("SetupHandle: Failed to setup %s handle: %s", error_name,
strerror(error));
return ErrorStatus{error};
- } else {
- return {};
}
+ return {};
+}
+
+} // anonymous namespace
+
+ChannelEventSet::ChannelEventSet() {
+ const int flags = EFD_CLOEXEC | EFD_NONBLOCK;
+ LocalHandle pollin_event_fd, pollhup_event_fd;
+
+ if (!SetupHandle(eventfd(0, flags), &pollin_event_fd, "pollin_event") ||
+ !SetupHandle(eventfd(0, flags), &pollhup_event_fd, "pollhup_event")) {
+ return;
+ }
+
+ pollin_event_fd_ = std::move(pollin_event_fd);
+ pollhup_event_fd_ = std::move(pollhup_event_fd);
}
int ChannelEventSet::ModifyEvents(int clear_mask, int set_mask) {
@@ -51,63 +48,101 @@
const int old_bits = event_bits_;
const int new_bits = (event_bits_ & ~clear_mask) | set_mask;
event_bits_ = new_bits;
+ eventfd_t value;
- // If anything changed clear the event and update the event mask.
- if (old_bits != new_bits) {
- eventfd_t value;
- eventfd_read(event_fd_.Get(), &value);
+ // Calculate which bits changed and how. Bits that haven't changed since last
+ // modification will not change the state of an eventfd.
+ const int set_bits = new_bits & ~old_bits;
+ const int clear_bits = ~new_bits & old_bits;
- epoll_event event;
- event.events = POLLIN;
- event.data.u32 = event_bits_;
- if (epoll_ctl(epoll_fd_.Get(), EPOLL_CTL_MOD, event_fd_.Get(), &event) <
- 0) {
- const int error = errno;
- ALOGE("ChannelEventSet::AddEventHandle: Failed to update event: %s",
- strerror(error));
- return -error;
- }
- }
+ if (set_bits & EPOLLIN)
+ eventfd_write(pollin_event_fd_.Get(), 1);
+ else if (clear_bits & EPOLLIN)
+ eventfd_read(pollin_event_fd_.Get(), &value);
- // If there are any bits set, re-trigger the eventfd.
- if (new_bits)
- eventfd_write(event_fd_.Get(), 1);
+ if (set_bits & EPOLLHUP)
+ eventfd_write(pollhup_event_fd_.Get(), 1);
+ else if (clear_bits & EPOLLHUP)
+ eventfd_read(pollhup_event_fd_.Get(), &value);
return 0;
}
-Status<void> ChannelEventSet::SetupHandle(int fd, LocalHandle* handle,
- const char* error_name) {
- const int error = errno;
- handle->Reset(fd);
- if (!*handle) {
- ALOGE("ChannelEventSet::SetupHandle: Failed to setup %s handle: %s",
- error_name, strerror(error));
+ChannelEventReceiver::ChannelEventReceiver(LocalHandle data_fd,
+ LocalHandle pollin_event_fd,
+ LocalHandle pollhup_event_fd) {
+ LocalHandle epoll_fd;
+ if (!SetupHandle(epoll_create1(EPOLL_CLOEXEC), &epoll_fd, "epoll")) {
+ return;
+ }
+
+ epoll_event event;
+ event.events = EPOLLHUP | EPOLLRDHUP;
+ event.data.u32 = 0;
+ if (epoll_ctl(epoll_fd.Get(), EPOLL_CTL_ADD, data_fd.Get(), &event) < 0) {
+ const int error = errno;
+ ALOGE("ChannelEventSet::ChannelEventSet: Failed to add data_fd: %s",
+ strerror(error));
+ return;
+ }
+
+ event.events = EPOLLIN;
+ event.data.u32 = 0;
+ if (epoll_ctl(epoll_fd.Get(), EPOLL_CTL_ADD, pollin_event_fd.Get(), &event) <
+ 0) {
+ const int error = errno;
+ ALOGE("ChannelEventSet::ChannelEventSet: Failed to add pollin_event_fd: %s",
+ strerror(error));
+ return;
+ }
+
+ event.events = EPOLLIN;
+ event.data.u32 = 0;
+ if (epoll_ctl(epoll_fd.Get(), EPOLL_CTL_ADD, pollhup_event_fd.Get(), &event) <
+ 0) {
+ const int error = errno;
+ ALOGE(
+ "ChannelEventSet::ChannelEventSet: Failed to add pollhup_event_fd: %s",
+ strerror(error));
+ return;
+ }
+
+ pollin_event_fd_ = std::move(pollin_event_fd);
+ pollhup_event_fd_ = std::move(pollhup_event_fd);
+ data_fd_ = std::move(data_fd);
+ epoll_fd_ = std::move(epoll_fd);
+}
+
+Status<int> ChannelEventReceiver::PollPendingEvents(int timeout_ms) const {
+ std::array<pollfd, 3> pfds = {{{pollin_event_fd_.Get(), POLLIN, 0},
+ {pollhup_event_fd_.Get(), POLLIN, 0},
+ {data_fd_.Get(), POLLHUP | POLLRDHUP, 0}}};
+ if (RETRY_EINTR(poll(pfds.data(), pfds.size(), timeout_ms)) < 0) {
+ const int error = errno;
+ ALOGE(
+ "ChannelEventReceiver::PollPendingEvents: Failed to poll for events: "
+ "%s",
+ strerror(error));
return ErrorStatus{error};
}
- return {};
+
+ const int event_mask =
+ ((pfds[0].revents & POLLIN) ? EPOLLIN : 0) |
+ ((pfds[1].revents & POLLIN) ? EPOLLHUP : 0) |
+ ((pfds[2].revents & (POLLHUP | POLLRDHUP)) ? EPOLLHUP : 0);
+ return {event_mask};
}
Status<int> ChannelEventReceiver::GetPendingEvents() const {
constexpr long kTimeoutMs = 0;
- epoll_event event;
- const int count =
- RETRY_EINTR(epoll_wait(epoll_fd_.Get(), &event, 1, kTimeoutMs));
+ return PollPendingEvents(kTimeoutMs);
+}
- Status<int> status;
- if (count < 0) {
- status.SetError(errno);
- ALOGE("ChannelEventReceiver::GetPendingEvents: Failed to get events: %s",
- status.GetErrorMessage().c_str());
- return status;
- }
-
- const int mask_out = event.data.u32;
- ALOGD_IF(TRACE, "ChannelEventReceiver::GetPendingEvents: mask_out=%x",
- mask_out);
-
- status.SetValue(mask_out);
- return status;
+std::vector<ClientChannel::EventSource> ChannelEventReceiver::GetEventSources()
+ const {
+ return {{data_fd_.Get(), EPOLLHUP | EPOLLRDHUP},
+ {pollin_event_fd_.Get(), EPOLLIN},
+ {pollhup_event_fd_.Get(), POLLIN}};
}
} // namespace uds
diff --git a/libs/vr/libpdx_uds/channel_manager.cpp b/libs/vr/libpdx_uds/channel_manager.cpp
index afc0a4f..43ebe05 100644
--- a/libs/vr/libpdx_uds/channel_manager.cpp
+++ b/libs/vr/libpdx_uds/channel_manager.cpp
@@ -22,18 +22,26 @@
}
LocalChannelHandle ChannelManager::CreateHandle(LocalHandle data_fd,
- LocalHandle event_fd) {
- if (data_fd && event_fd) {
+ LocalHandle pollin_event_fd,
+ LocalHandle pollhup_event_fd) {
+ if (data_fd && pollin_event_fd && pollhup_event_fd) {
std::lock_guard<std::mutex> autolock(mutex_);
- int32_t handle = data_fd.Get();
- channels_.emplace(handle,
- ChannelData{std::move(data_fd), std::move(event_fd)});
+ const int32_t handle = data_fd.Get();
+ channels_.emplace(
+ handle,
+ ChannelEventReceiver{std::move(data_fd), std::move(pollin_event_fd),
+ std::move(pollhup_event_fd)});
return LocalChannelHandle(this, handle);
+ } else {
+ ALOGE(
+ "ChannelManager::CreateHandle: Invalid arguments: data_fd=%d "
+ "pollin_event_fd=%d pollhup_event_fd=%d",
+ data_fd.Get(), pollin_event_fd.Get(), pollhup_event_fd.Get());
+ return LocalChannelHandle(nullptr, -1);
}
- return LocalChannelHandle(nullptr, -1);
}
-ChannelManager::ChannelData* ChannelManager::GetChannelData(int32_t handle) {
+ChannelEventReceiver* ChannelManager::GetChannelData(int32_t handle) {
std::lock_guard<std::mutex> autolock(mutex_);
auto channel = channels_.find(handle);
return channel != channels_.end() ? &channel->second : nullptr;
diff --git a/libs/vr/libpdx_uds/client_channel.cpp b/libs/vr/libpdx_uds/client_channel.cpp
index 9d91617..2e9c1de 100644
--- a/libs/vr/libpdx_uds/client_channel.cpp
+++ b/libs/vr/libpdx_uds/client_channel.cpp
@@ -33,7 +33,9 @@
} else if (static_cast<size_t>(index) < response.channels.size()) {
auto& channel_info = response.channels[index];
*handle = ChannelManager::Get().CreateHandle(
- std::move(channel_info.data_fd), std::move(channel_info.event_fd));
+ std::move(channel_info.data_fd),
+ std::move(channel_info.pollin_event_fd),
+ std::move(channel_info.pollhup_event_fd));
} else {
return false;
}
@@ -53,9 +55,9 @@
if (auto* channel_data =
ChannelManager::Get().GetChannelData(handle.value())) {
- ChannelInfo<BorrowedHandle> channel_info;
- channel_info.data_fd.Reset(handle.value());
- channel_info.event_fd = channel_data->event_receiver.event_fd();
+ ChannelInfo<BorrowedHandle> channel_info{
+ channel_data->data_fd(), channel_data->pollin_event_fd(),
+ channel_data->pollhup_event_fd()};
request.channels.push_back(std::move(channel_info));
return request.channels.size() - 1;
} else {
@@ -90,10 +92,12 @@
size_t send_len = CountVectorSize(send_vector, send_count);
InitRequest(&transaction_state->request, opcode, send_len, max_recv_len,
false);
- auto status = SendData(socket_fd, transaction_state->request);
- if (status && send_len > 0)
- status = SendDataVector(socket_fd, send_vector, send_count);
- return status;
+ if (send_len == 0) {
+ send_vector = nullptr;
+ send_count = 0;
+ }
+ return SendData(socket_fd, transaction_state->request, send_vector,
+ send_count);
}
Status<void> ReceiveResponse(const BorrowedHandle& socket_fd,
diff --git a/libs/vr/libpdx_uds/client_channel_factory.cpp b/libs/vr/libpdx_uds/client_channel_factory.cpp
index 433f459..09dc7be 100644
--- a/libs/vr/libpdx_uds/client_channel_factory.cpp
+++ b/libs/vr/libpdx_uds/client_channel_factory.cpp
@@ -139,20 +139,33 @@
RequestHeader<BorrowedHandle> request;
InitRequest(&request, opcodes::CHANNEL_OPEN, 0, 0, false);
+
status = SendData(socket_.Borrow(), request);
if (!status)
return status.error_status();
+
ResponseHeader<LocalHandle> response;
status = ReceiveData(socket_.Borrow(), &response);
if (!status)
return status.error_status();
- int ref = response.ret_code;
- if (ref < 0 || static_cast<size_t>(ref) > response.file_descriptors.size())
+ else if (response.ret_code < 0 || response.channels.size() != 1)
return ErrorStatus(EIO);
- LocalHandle event_fd = std::move(response.file_descriptors[ref]);
+ LocalHandle pollin_event_fd = std::move(response.channels[0].pollin_event_fd);
+ LocalHandle pollhup_event_fd =
+ std::move(response.channels[0].pollhup_event_fd);
+
+ if (!pollin_event_fd || !pollhup_event_fd) {
+ ALOGE(
+ "ClientChannelFactory::Connect: Required fd was not returned from the "
+ "service: pollin_event_fd=%d pollhup_event_fd=%d",
+ pollin_event_fd.Get(), pollhup_event_fd.Get());
+ return ErrorStatus(EIO);
+ }
+
return ClientChannel::Create(ChannelManager::Get().CreateHandle(
- std::move(socket_), std::move(event_fd)));
+ std::move(socket_), std::move(pollin_event_fd),
+ std::move(pollhup_event_fd)));
}
} // namespace uds
diff --git a/libs/vr/libpdx_uds/client_channel_tests.cpp b/libs/vr/libpdx_uds/client_channel_tests.cpp
index 7c3c68a..1560030 100644
--- a/libs/vr/libpdx_uds/client_channel_tests.cpp
+++ b/libs/vr/libpdx_uds/client_channel_tests.cpp
@@ -13,6 +13,7 @@
#include <pdx/client.h>
#include <pdx/rpc/remote_method.h>
#include <pdx/service.h>
+#include <pdx/service_dispatcher.h>
#include <uds/client_channel_factory.h>
#include <uds/service_endpoint.h>
@@ -81,7 +82,7 @@
auto endpoint = Endpoint::CreateFromSocketFd(LocalHandle{});
endpoint->RegisterNewChannelForTests(std::move(channel_socket));
service_ = TestService::Create(std::move(endpoint));
- dispatcher_ = android::pdx::uds::ServiceDispatcher::Create();
+ dispatcher_ = ServiceDispatcher::Create();
dispatcher_->AddService(service_);
dispatch_thread_ = std::thread(
std::bind(&ServiceDispatcher::EnterDispatchLoop, dispatcher_.get()));
diff --git a/libs/vr/libpdx_uds/ipc_helper.cpp b/libs/vr/libpdx_uds/ipc_helper.cpp
index d75ce86..f85b3bb 100644
--- a/libs/vr/libpdx_uds/ipc_helper.cpp
+++ b/libs/vr/libpdx_uds/ipc_helper.cpp
@@ -20,6 +20,9 @@
namespace {
+constexpr size_t kMaxFdCount =
+ 256; // Total of 1KiB of data to transfer these FDs.
+
// Default implementations of Send/Receive interfaces to use standard socket
// send/sendmsg/recv/recvmsg functions.
class SocketSender : public SendInterface {
@@ -175,20 +178,31 @@
}
Status<void> SendPayload::Send(const BorrowedHandle& socket_fd,
- const ucred* cred) {
+ const ucred* cred, const iovec* data_vec,
+ size_t vec_count) {
+ if (file_handles_.size() > kMaxFdCount) {
+ ALOGE(
+ "SendPayload::Send: Trying to send too many file descriptors (%zu), "
+ "max allowed = %zu",
+ file_handles_.size(), kMaxFdCount);
+ return ErrorStatus{EINVAL};
+ }
+
SendInterface* sender = sender_ ? sender_ : &g_socket_sender;
MessagePreamble preamble;
preamble.magic = kMagicPreamble;
preamble.data_size = buffer_.size();
preamble.fd_count = file_handles_.size();
- Status<void> ret = SendAll(sender, socket_fd, &preamble, sizeof(preamble));
- if (!ret)
- return ret;
msghdr msg = {};
- iovec recv_vect = {buffer_.data(), buffer_.size()};
- msg.msg_iov = &recv_vect;
- msg.msg_iovlen = 1;
+ msg.msg_iovlen = 2 + vec_count;
+ msg.msg_iov = static_cast<iovec*>(alloca(sizeof(iovec) * msg.msg_iovlen));
+ msg.msg_iov[0].iov_base = &preamble;
+ msg.msg_iov[0].iov_len = sizeof(preamble);
+ msg.msg_iov[1].iov_base = buffer_.data();
+ msg.msg_iov[1].iov_len = buffer_.size();
+ for (size_t i = 0; i < vec_count; i++)
+ msg.msg_iov[i + 2] = data_vec[i];
if (cred || !file_handles_.empty()) {
const size_t fd_bytes = file_handles_.size() * sizeof(int);
@@ -270,7 +284,15 @@
ucred* cred) {
RecvInterface* receiver = receiver_ ? receiver_ : &g_socket_receiver;
MessagePreamble preamble;
- Status<void> ret = RecvAll(receiver, socket_fd, &preamble, sizeof(preamble));
+ msghdr msg = {};
+ iovec recv_vect = {&preamble, sizeof(preamble)};
+ msg.msg_iov = &recv_vect;
+ msg.msg_iovlen = 1;
+ const size_t receive_fd_bytes = kMaxFdCount * sizeof(int);
+ msg.msg_controllen = CMSG_SPACE(sizeof(ucred)) + CMSG_SPACE(receive_fd_bytes);
+ msg.msg_control = alloca(msg.msg_controllen);
+
+ Status<void> ret = RecvMsgAll(receiver, socket_fd, &msg);
if (!ret)
return ret;
@@ -284,23 +306,6 @@
file_handles_.clear();
read_pos_ = 0;
- msghdr msg = {};
- iovec recv_vect = {buffer_.data(), buffer_.size()};
- msg.msg_iov = &recv_vect;
- msg.msg_iovlen = 1;
-
- if (cred || preamble.fd_count) {
- const size_t receive_fd_bytes = preamble.fd_count * sizeof(int);
- msg.msg_controllen =
- (cred ? CMSG_SPACE(sizeof(ucred)) : 0) +
- (receive_fd_bytes == 0 ? 0 : CMSG_SPACE(receive_fd_bytes));
- msg.msg_control = alloca(msg.msg_controllen);
- }
-
- ret = RecvMsgAll(receiver, socket_fd, &msg);
- if (!ret)
- return ret;
-
bool cred_available = false;
file_handles_.reserve(preamble.fd_count);
cmsghdr* cmsg = CMSG_FIRSTHDR(&msg);
@@ -320,6 +325,10 @@
cmsg = CMSG_NXTHDR(&msg, cmsg);
}
+ ret = RecvAll(receiver, socket_fd, buffer_.data(), buffer_.size());
+ if (!ret)
+ return ret;
+
if (cred && !cred_available) {
ALOGE("ReceivePayload::Receive: Failed to obtain message credentials");
ret.SetError(EIO);
diff --git a/libs/vr/libpdx_uds/private/uds/channel_event_set.h b/libs/vr/libpdx_uds/private/uds/channel_event_set.h
index 1f464d5..e960740 100644
--- a/libs/vr/libpdx_uds/private/uds/channel_event_set.h
+++ b/libs/vr/libpdx_uds/private/uds/channel_event_set.h
@@ -1,11 +1,9 @@
#ifndef ANDROID_PDX_UDS_CHANNEL_EVENT_SET_H_
#define ANDROID_PDX_UDS_CHANNEL_EVENT_SET_H_
-#include <errno.h>
-#include <poll.h>
-#include <sys/epoll.h>
-#include <sys/eventfd.h>
+#include <vector>
+#include <pdx/client_channel.h>
#include <pdx/file_handle.h>
#include <pdx/status.h>
@@ -19,21 +17,20 @@
ChannelEventSet(ChannelEventSet&&) = default;
ChannelEventSet& operator=(ChannelEventSet&&) = default;
- BorrowedHandle event_fd() const { return epoll_fd_.Borrow(); }
+ BorrowedHandle pollin_event_fd() const { return pollin_event_fd_.Borrow(); }
+ BorrowedHandle pollhup_event_fd() const { return pollhup_event_fd_.Borrow(); }
- explicit operator bool() const { return !!epoll_fd_ && !!event_fd_; }
+ explicit operator bool() const {
+ return !!pollin_event_fd_ && !!pollhup_event_fd_;
+ }
- Status<void> AddDataFd(const LocalHandle& data_fd);
int ModifyEvents(int clear_mask, int set_mask);
private:
- LocalHandle epoll_fd_;
- LocalHandle event_fd_;
+ LocalHandle pollin_event_fd_;
+ LocalHandle pollhup_event_fd_;
uint32_t event_bits_ = 0;
- static Status<void> SetupHandle(int fd, LocalHandle* handle,
- const char* error_name);
-
ChannelEventSet(const ChannelEventSet&) = delete;
void operator=(const ChannelEventSet&) = delete;
};
@@ -41,14 +38,39 @@
class ChannelEventReceiver {
public:
ChannelEventReceiver() = default;
- ChannelEventReceiver(LocalHandle epoll_fd) : epoll_fd_{std::move(epoll_fd)} {}
+ ChannelEventReceiver(LocalHandle data_fd, LocalHandle pollin_event_fd,
+ LocalHandle pollhup_event_fd);
ChannelEventReceiver(ChannelEventReceiver&&) = default;
ChannelEventReceiver& operator=(ChannelEventReceiver&&) = default;
+ explicit operator bool() const {
+ return !!pollin_event_fd_ && !!pollhup_event_fd_ && !!data_fd_ &&
+ !!epoll_fd_;
+ }
+
BorrowedHandle event_fd() const { return epoll_fd_.Borrow(); }
+
+ BorrowedHandle pollin_event_fd() const { return pollin_event_fd_.Borrow(); }
+ BorrowedHandle pollhup_event_fd() const { return pollhup_event_fd_.Borrow(); }
+ BorrowedHandle data_fd() const { return data_fd_.Borrow(); }
+
+ // Moves file descriptors out of ChannelEventReceiver. Note these operations
+ // immediately invalidates the receiver.
+ std::tuple<LocalHandle, LocalHandle, LocalHandle> TakeFds() {
+ epoll_fd_.Close();
+ return {std::move(data_fd_), std::move(pollin_event_fd_),
+ std::move(pollhup_event_fd_)};
+ }
+
Status<int> GetPendingEvents() const;
+ Status<int> PollPendingEvents(int timeout_ms) const;
+
+ std::vector<ClientChannel::EventSource> GetEventSources() const;
private:
+ LocalHandle data_fd_;
+ LocalHandle pollin_event_fd_;
+ LocalHandle pollhup_event_fd_;
LocalHandle epoll_fd_;
ChannelEventReceiver(const ChannelEventReceiver&) = delete;
diff --git a/libs/vr/libpdx_uds/private/uds/channel_manager.h b/libs/vr/libpdx_uds/private/uds/channel_manager.h
index 2aca414..5f6a514 100644
--- a/libs/vr/libpdx_uds/private/uds/channel_manager.h
+++ b/libs/vr/libpdx_uds/private/uds/channel_manager.h
@@ -16,13 +16,11 @@
public:
static ChannelManager& Get();
- LocalChannelHandle CreateHandle(LocalHandle data_fd, LocalHandle event_fd);
- struct ChannelData {
- LocalHandle data_fd;
- ChannelEventReceiver event_receiver;
- };
+ LocalChannelHandle CreateHandle(LocalHandle data_fd,
+ LocalHandle pollin_event_fd,
+ LocalHandle pollhup_event_fd);
- ChannelData* GetChannelData(int32_t handle);
+ ChannelEventReceiver* GetChannelData(int32_t handle);
private:
ChannelManager() = default;
@@ -30,7 +28,7 @@
void CloseHandle(int32_t handle) override;
std::mutex mutex_;
- std::unordered_map<int32_t, ChannelData> channels_;
+ std::unordered_map<int32_t, ChannelEventReceiver> channels_;
};
} // namespace uds
diff --git a/libs/vr/libpdx_uds/private/uds/client_channel.h b/libs/vr/libpdx_uds/private/uds/client_channel.h
index 8f607f5..7a5ddf4 100644
--- a/libs/vr/libpdx_uds/private/uds/client_channel.h
+++ b/libs/vr/libpdx_uds/private/uds/client_channel.h
@@ -23,11 +23,19 @@
uint32_t GetIpcTag() const override { return Endpoint::kIpcTag; }
int event_fd() const override {
- return channel_data_ ? channel_data_->event_receiver.event_fd().Get() : -1;
+ return channel_data_ ? channel_data_->event_fd().Get() : -1;
}
+
+ std::vector<EventSource> GetEventSources() const override {
+ if (channel_data_)
+ return channel_data_->GetEventSources();
+ else
+ return {};
+ }
+
Status<int> GetEventMask(int /*events*/) override {
if (channel_data_)
- return channel_data_->event_receiver.GetPendingEvents();
+ return channel_data_->GetPendingEvents();
else
return ErrorStatus(EINVAL);
}
@@ -74,7 +82,7 @@
const iovec* receive_vector, size_t receive_count);
LocalChannelHandle channel_handle_;
- ChannelManager::ChannelData* channel_data_;
+ ChannelEventReceiver* channel_data_;
std::mutex socket_mutex_;
};
diff --git a/libs/vr/libpdx_uds/private/uds/ipc_helper.h b/libs/vr/libpdx_uds/private/uds/ipc_helper.h
index bde16d3..63b5b10 100644
--- a/libs/vr/libpdx_uds/private/uds/ipc_helper.h
+++ b/libs/vr/libpdx_uds/private/uds/ipc_helper.h
@@ -59,7 +59,8 @@
public:
SendPayload(SendInterface* sender = nullptr) : sender_{sender} {}
Status<void> Send(const BorrowedHandle& socket_fd);
- Status<void> Send(const BorrowedHandle& socket_fd, const ucred* cred);
+ Status<void> Send(const BorrowedHandle& socket_fd, const ucred* cred,
+ const iovec* data_vec = nullptr, size_t vec_count = 0);
// MessageWriter
void* GetNextWriteBufferSection(size_t size) override;
@@ -109,10 +110,12 @@
class ChannelInfo {
public:
FileHandleType data_fd;
- FileHandleType event_fd;
+ FileHandleType pollin_event_fd;
+ FileHandleType pollhup_event_fd;
private:
- PDX_SERIALIZABLE_MEMBERS(ChannelInfo, data_fd, event_fd);
+ PDX_SERIALIZABLE_MEMBERS(ChannelInfo, data_fd, pollin_event_fd,
+ pollhup_event_fd);
};
template <typename FileHandleType>
@@ -156,18 +159,22 @@
};
template <typename T>
-inline Status<void> SendData(const BorrowedHandle& socket_fd, const T& data) {
+inline Status<void> SendData(const BorrowedHandle& socket_fd, const T& data,
+ const iovec* data_vec = nullptr,
+ size_t vec_count = 0) {
SendPayload payload;
rpc::Serialize(data, &payload);
- return payload.Send(socket_fd);
+ return payload.Send(socket_fd, nullptr, data_vec, vec_count);
}
template <typename FileHandleType>
inline Status<void> SendData(const BorrowedHandle& socket_fd,
- const RequestHeader<FileHandleType>& request) {
+ const RequestHeader<FileHandleType>& request,
+ const iovec* data_vec = nullptr,
+ size_t vec_count = 0) {
SendPayload payload;
rpc::Serialize(request, &payload);
- return payload.Send(socket_fd, &request.cred);
+ return payload.Send(socket_fd, &request.cred, data_vec, vec_count);
}
Status<void> SendData(const BorrowedHandle& socket_fd, const void* data,
diff --git a/libs/vr/libpdx_uds/private/uds/service_dispatcher.h b/libs/vr/libpdx_uds/private/uds/service_dispatcher.h
deleted file mode 100644
index 23af4f4..0000000
--- a/libs/vr/libpdx_uds/private/uds/service_dispatcher.h
+++ /dev/null
@@ -1,55 +0,0 @@
-#ifndef ANDROID_PDX_UDS_SERVICE_DISPATCHER_H_
-#define ANDROID_PDX_UDS_SERVICE_DISPATCHER_H_
-
-#include <list>
-#include <memory>
-#include <mutex>
-#include <unordered_map>
-
-#include <pdx/file_handle.h>
-#include <pdx/service_dispatcher.h>
-
-namespace android {
-namespace pdx {
-namespace uds {
-
-class ServiceDispatcher : public pdx::ServiceDispatcher {
- public:
- // Get a new instance of ServiceDispatcher, or return nullptr if init failed.
- static std::unique_ptr<pdx::ServiceDispatcher> Create();
-
- ~ServiceDispatcher() override;
- int AddService(const std::shared_ptr<Service>& service) override;
- int RemoveService(const std::shared_ptr<Service>& service) override;
- int ReceiveAndDispatch() override;
- int ReceiveAndDispatch(int timeout) override;
- int EnterDispatchLoop() override;
- void SetCanceled(bool cancel) override;
- bool IsCanceled() const override;
-
- private:
- ServiceDispatcher();
-
- // Internal thread accounting.
- int ThreadEnter();
- void ThreadExit();
-
- std::mutex mutex_;
- std::condition_variable condition_;
- std::atomic<bool> canceled_{false};
-
- std::list<std::shared_ptr<Service>> services_;
-
- int thread_count_ = 0;
- LocalHandle event_fd_;
- LocalHandle epoll_fd_;
-
- ServiceDispatcher(const ServiceDispatcher&) = delete;
- void operator=(const ServiceDispatcher&) = delete;
-};
-
-} // namespace uds
-} // namespace pdx
-} // namespace android
-
-#endif // ANDROID_PDX_UDS_SERVICE_DISPATCHER_H_
diff --git a/libs/vr/libpdx_uds/private/uds/service_endpoint.h b/libs/vr/libpdx_uds/private/uds/service_endpoint.h
index 368891c..01ebf65 100644
--- a/libs/vr/libpdx_uds/private/uds/service_endpoint.h
+++ b/libs/vr/libpdx_uds/private/uds/service_endpoint.h
@@ -7,12 +7,12 @@
#include <mutex>
#include <string>
#include <unordered_map>
+#include <utility>
#include <vector>
#include <pdx/service.h>
#include <pdx/service_endpoint.h>
#include <uds/channel_event_set.h>
-#include <uds/service_dispatcher.h>
namespace android {
namespace pdx {
@@ -105,7 +105,7 @@
// socket file descriptor.
Status<void> RegisterNewChannelForTests(LocalHandle channel_fd);
- int epoll_fd() const { return epoll_fd_.Get(); }
+ int epoll_fd() const override { return epoll_fd_.Get(); }
private:
struct ChannelData {
@@ -140,7 +140,8 @@
Status<void> ReenableEpollEvent(const BorrowedHandle& channel_fd);
Channel* GetChannelState(int32_t channel_id);
BorrowedHandle GetChannelSocketFd(int32_t channel_id);
- BorrowedHandle GetChannelEventFd(int32_t channel_id);
+ Status<std::pair<BorrowedHandle, BorrowedHandle>> GetChannelEventFd(
+ int32_t channel_id);
int32_t GetChannelId(const BorrowedHandle& channel_fd);
Status<void> CreateChannelSocketPair(LocalHandle* local_socket,
LocalHandle* remote_socket);
diff --git a/libs/vr/libpdx_uds/remote_method_tests.cpp b/libs/vr/libpdx_uds/remote_method_tests.cpp
index 3109753..3f25776 100644
--- a/libs/vr/libpdx_uds/remote_method_tests.cpp
+++ b/libs/vr/libpdx_uds/remote_method_tests.cpp
@@ -15,9 +15,9 @@
#include <pdx/rpc/remote_method.h>
#include <pdx/rpc/serializable.h>
#include <pdx/service.h>
+#include <pdx/service_dispatcher.h>
#include <uds/client_channel.h>
#include <uds/client_channel_factory.h>
-#include <uds/service_dispatcher.h>
#include <uds/service_endpoint.h>
using android::pdx::BorrowedHandle;
@@ -561,7 +561,7 @@
void SetUp() override {
// Create a dispatcher to handle messages to services.
- dispatcher_ = android::pdx::uds::ServiceDispatcher::Create();
+ dispatcher_ = android::pdx::ServiceDispatcher::Create();
ASSERT_NE(nullptr, dispatcher_);
// Start the message dispatch loop in a separate thread.
diff --git a/libs/vr/libpdx_uds/service_endpoint.cpp b/libs/vr/libpdx_uds/service_endpoint.cpp
index 27a56f9..0ee77f4 100644
--- a/libs/vr/libpdx_uds/service_endpoint.cpp
+++ b/libs/vr/libpdx_uds/service_endpoint.cpp
@@ -49,7 +49,9 @@
} else if (static_cast<size_t>(index) < request.channels.size()) {
auto& channel_info = request.channels[index];
*handle = ChannelManager::Get().CreateHandle(
- std::move(channel_info.data_fd), std::move(channel_info.event_fd));
+ std::move(channel_info.data_fd),
+ std::move(channel_info.pollin_event_fd),
+ std::move(channel_info.pollhup_event_fd));
} else {
return false;
}
@@ -69,9 +71,9 @@
if (auto* channel_data =
ChannelManager::Get().GetChannelData(handle.value())) {
- ChannelInfo<BorrowedHandle> channel_info;
- channel_info.data_fd.Reset(handle.value());
- channel_info.event_fd = channel_data->event_receiver.event_fd();
+ ChannelInfo<BorrowedHandle> channel_info{
+ channel_data->data_fd(), channel_data->pollin_event_fd(),
+ channel_data->pollhup_event_fd()};
response.channels.push_back(std::move(channel_info));
return response.channels.size() - 1;
} else {
@@ -80,12 +82,13 @@
}
Status<ChannelReference> PushChannelHandle(BorrowedHandle data_fd,
- BorrowedHandle event_fd) {
- if (!data_fd || !event_fd)
+ BorrowedHandle pollin_event_fd,
+ BorrowedHandle pollhup_event_fd) {
+ if (!data_fd || !pollin_event_fd || !pollhup_event_fd)
return ErrorStatus{EINVAL};
- ChannelInfo<BorrowedHandle> channel_info;
- channel_info.data_fd = std::move(data_fd);
- channel_info.event_fd = std::move(event_fd);
+ ChannelInfo<BorrowedHandle> channel_info{std::move(data_fd),
+ std::move(pollin_event_fd),
+ std::move(pollhup_event_fd)};
response.channels.push_back(std::move(channel_info));
return response.channels.size() - 1;
}
@@ -287,7 +290,6 @@
return ErrorStatus(errno);
}
ChannelData channel_data;
- channel_data.event_set.AddDataFd(channel_fd);
channel_data.data_fd = std::move(channel_fd);
channel_data.channel_state = channel_state;
for (;;) {
@@ -431,18 +433,21 @@
return status.error_status();
std::lock_guard<std::mutex> autolock(channel_mutex_);
- auto channel_data = OnNewChannelLocked(std::move(local_socket), channel);
- if (!channel_data)
- return channel_data.error_status();
- *channel_id = channel_data.get().first;
+ auto channel_data_status =
+ OnNewChannelLocked(std::move(local_socket), channel);
+ if (!channel_data_status)
+ return channel_data_status.error_status();
+
+ ChannelData* channel_data;
+ std::tie(*channel_id, channel_data) = channel_data_status.take();
// Flags are ignored for now.
// TODO(xiaohuit): Implement those.
auto* state = static_cast<MessageState*>(message->GetState());
Status<ChannelReference> ref = state->PushChannelHandle(
- remote_socket.Borrow(),
- channel_data.get().second->event_set.event_fd().Borrow());
+ remote_socket.Borrow(), channel_data->event_set.pollin_event_fd(),
+ channel_data->event_set.pollhup_event_fd());
if (!ref)
return ref.error_status();
state->sockets_to_close.push_back(std::move(remote_socket));
@@ -472,13 +477,15 @@
return handle;
}
-BorrowedHandle Endpoint::GetChannelEventFd(int32_t channel_id) {
+Status<std::pair<BorrowedHandle, BorrowedHandle>> Endpoint::GetChannelEventFd(
+ int32_t channel_id) {
std::lock_guard<std::mutex> autolock(channel_mutex_);
- BorrowedHandle handle;
auto channel_data = channels_.find(channel_id);
- if (channel_data != channels_.end())
- handle = channel_data->second.event_set.event_fd().Borrow();
- return handle;
+ if (channel_data != channels_.end()) {
+ return {{channel_data->second.event_set.pollin_event_fd(),
+ channel_data->second.event_set.pollhup_event_fd()}};
+ }
+ return ErrorStatus(ENOENT);
}
int32_t Endpoint::GetChannelId(const BorrowedHandle& channel_fd) {
@@ -593,11 +600,6 @@
}
BorrowedHandle channel_fd{event.data.fd};
- if (event.events & (EPOLLRDHUP | EPOLLHUP)) {
- BuildCloseMessage(GetChannelId(channel_fd), message);
- return {};
- }
-
return ReceiveMessageForChannel(channel_fd, message);
}
@@ -616,12 +618,23 @@
if (return_code < 0) {
return CloseChannel(channel_id);
} else {
- // Reply with the event fd.
- auto push_status = state->PushFileHandle(GetChannelEventFd(channel_id));
- state->response_data.clear(); // Just in case...
- if (!push_status)
- return push_status.error_status();
- return_code = push_status.get();
+ // Open messages do not have a payload and may not transfer any channels
+ // or file descriptors on behalf of the service.
+ state->response_data.clear();
+ state->response.file_descriptors.clear();
+ state->response.channels.clear();
+
+ // Return the channel event-related fds in a single ChannelInfo entry
+ // with an empty data_fd member.
+ auto status = GetChannelEventFd(channel_id);
+ if (!status)
+ return status.error_status();
+
+ auto handles = status.take();
+ state->response.channels.push_back({BorrowedHandle(),
+ std::move(handles.first),
+ std::move(handles.second)});
+ return_code = 0;
}
break;
}
diff --git a/libs/vr/libpdx_uds/service_framework_tests.cpp b/libs/vr/libpdx_uds/service_framework_tests.cpp
index 2943239..2742716 100644
--- a/libs/vr/libpdx_uds/service_framework_tests.cpp
+++ b/libs/vr/libpdx_uds/service_framework_tests.cpp
@@ -1,5 +1,6 @@
#include <errno.h>
#include <fcntl.h>
+#include <poll.h>
#include <sys/epoll.h>
#include <sys/eventfd.h>
#include <unistd.h>
@@ -16,10 +17,10 @@
#include <pdx/client.h>
#include <pdx/file_handle.h>
#include <pdx/service.h>
+#include <pdx/service_dispatcher.h>
#include <private/android_filesystem_config.h>
#include <uds/client_channel.h>
#include <uds/client_channel_factory.h>
-#include <uds/service_dispatcher.h>
#include <uds/service_endpoint.h>
using android::pdx::BorrowedChannelHandle;
@@ -425,7 +426,7 @@
void SetUp() override {
// Create a dispatcher to handle messages to services.
- dispatcher_ = android::pdx::uds::ServiceDispatcher::Create();
+ dispatcher_ = android::pdx::ServiceDispatcher::Create();
ASSERT_NE(nullptr, dispatcher_);
// Start the message dispatch loop in a separate thread.
@@ -506,6 +507,37 @@
EXPECT_EQ(-EINVAL, client->SendAsync(invalid_pointer, sizeof(int)));
}
+// Test impulses.
+TEST_F(ServiceFrameworkTest, ImpulseHangup) {
+ // Create a test service and add it to the dispatcher.
+ auto service = TestService::Create(kTestService1);
+ ASSERT_NE(nullptr, service);
+ ASSERT_EQ(0, dispatcher_->AddService(service));
+
+ auto client = TestClient::Create(kTestService1);
+ ASSERT_NE(nullptr, client);
+
+ const int kMaxIterations = 1000;
+ for (int i = 0; i < kMaxIterations; i++) {
+ auto impulse_client = TestClient::Create(kTestService1);
+ ASSERT_NE(nullptr, impulse_client);
+
+ const uint8_t a = (i >> 0) & 0xff;
+ const uint8_t b = (i >> 8) & 0xff;
+ const uint8_t c = (i >> 16) & 0xff;
+ const uint8_t d = (i >> 24) & 0xff;
+ ImpulsePayload expected_payload = {{a, b, c, d}};
+ EXPECT_EQ(0, impulse_client->SendAsync(expected_payload.data(), 4));
+
+ // Hangup the impulse test client, then send a sync message over client to
+ // make sure the hangup message is handled before checking the impulse
+ // payload.
+ impulse_client = nullptr;
+ client->GetThisChannelId();
+ EXPECT_EQ(expected_payload, service->GetImpulsePayload());
+ }
+}
+
// Test Message::PushChannel/Service::PushChannel API.
TEST_F(ServiceFrameworkTest, PushChannel) {
// Create a test service and add it to the dispatcher.
@@ -574,9 +606,7 @@
pid_t process_id2;
- std::thread thread([&]() {
- process_id2 = client->GetThisProcessId();
- });
+ std::thread thread([&]() { process_id2 = client->GetThisProcessId(); });
thread.join();
EXPECT_LT(2, process_id2);
@@ -614,15 +644,15 @@
auto client = TestClient::Create(kTestService1);
ASSERT_NE(nullptr, client);
- epoll_event event;
- int count = epoll_wait(client->event_fd(), &event, 1, 0);
+ pollfd pfd{client->event_fd(), POLLIN, 0};
+ int count = poll(&pfd, 1, 0);
ASSERT_EQ(0, count);
client->SendPollInEvent();
- count = epoll_wait(client->event_fd(), &event, 1, -1);
+ count = poll(&pfd, 1, 10000 /*10s*/);
ASSERT_EQ(1, count);
- ASSERT_TRUE((EPOLLIN & event.events) != 0);
+ ASSERT_TRUE((POLLIN & pfd.revents) != 0);
}
TEST_F(ServiceFrameworkTest, PollHup) {
@@ -635,15 +665,15 @@
auto client = TestClient::Create(kTestService1);
ASSERT_NE(nullptr, client);
- epoll_event event;
- int count = epoll_wait(client->event_fd(), &event, 1, 0);
+ pollfd pfd{client->event_fd(), POLLIN, 0};
+ int count = poll(&pfd, 1, 0);
ASSERT_EQ(0, count);
client->SendPollHupEvent();
- count = epoll_wait(client->event_fd(), &event, 1, -1);
+ count = poll(&pfd, 1, 10000 /*10s*/);
ASSERT_EQ(1, count);
- auto event_status = client->GetEventMask(event.events);
+ auto event_status = client->GetEventMask(pfd.revents);
ASSERT_TRUE(event_status.ok());
ASSERT_TRUE((EPOLLHUP & event_status.get()) != 0);
}
diff --git a/libs/vr/libperformance/include/dvr/performance_client_api.h b/libs/vr/libperformance/include/dvr/performance_client_api.h
index 2216e38..9d617cb 100644
--- a/libs/vr/libperformance/include/dvr/performance_client_api.h
+++ b/libs/vr/libperformance/include/dvr/performance_client_api.h
@@ -8,6 +8,20 @@
extern "C" {
#endif
+/// Sets the scheduler policy for a task.
+///
+/// Sets the scheduler policy for a task to the class described by a semantic
+/// string.
+///
+/// Supported policies are device-specific.
+///
+/// @param task_id The task id of task to set the policy for. When task_id is 0
+/// the current task id is substituted.
+/// @param scheduler_policy NULL-terminated ASCII string containing the desired
+/// scheduler policy.
+/// @returns Returns 0 on success or a negative errno error code on error.
+int dvrSetSchedulerPolicy(pid_t task_id, const char* scheduler_policy);
+
/// Sets the CPU partition for a task.
///
/// Sets the CPU partition for a task to the partition described by a CPU
diff --git a/libs/vr/libperformance/include/private/dvr/performance_client.h b/libs/vr/libperformance/include/private/dvr/performance_client.h
index a61c6b2..3bd90dc 100644
--- a/libs/vr/libperformance/include/private/dvr/performance_client.h
+++ b/libs/vr/libperformance/include/private/dvr/performance_client.h
@@ -14,6 +14,10 @@
class PerformanceClient : public pdx::ClientBase<PerformanceClient> {
public:
+ int SetSchedulerPolicy(pid_t task_id, const std::string& scheduler_policy);
+ int SetSchedulerPolicy(pid_t task_id, const char* scheduler_policy);
+
+ // TODO(eieio): Consider deprecating this API.
int SetCpuPartition(pid_t task_id, const std::string& partition);
int SetCpuPartition(pid_t task_id, const char* partition);
int SetSchedulerClass(pid_t task_id, const std::string& scheduler_class);
diff --git a/libs/vr/libperformance/include/private/dvr/performance_rpc.h b/libs/vr/libperformance/include/private/dvr/performance_rpc.h
index 73bdaa7..d57bbe8 100644
--- a/libs/vr/libperformance/include/private/dvr/performance_rpc.h
+++ b/libs/vr/libperformance/include/private/dvr/performance_rpc.h
@@ -21,14 +21,17 @@
kOpSetCpuPartition = 0,
kOpSetSchedulerClass,
kOpGetCpuPartition,
+ kOpSetSchedulerPolicy,
};
// Methods.
PDX_REMOTE_METHOD(SetCpuPartition, kOpSetCpuPartition,
- int(pid_t, const std::string&));
+ void(pid_t, const std::string&));
PDX_REMOTE_METHOD(SetSchedulerClass, kOpSetSchedulerClass,
- int(pid_t, const std::string&));
+ void(pid_t, const std::string&));
PDX_REMOTE_METHOD(GetCpuPartition, kOpGetCpuPartition, std::string(pid_t));
+ PDX_REMOTE_METHOD(SetSchedulerPolicy, kOpSetSchedulerPolicy,
+ void(pid_t, const std::string&));
};
} // namespace dvr
diff --git a/libs/vr/libperformance/performance_client.cpp b/libs/vr/libperformance/performance_client.cpp
index 2124162..bf3726e 100644
--- a/libs/vr/libperformance/performance_client.cpp
+++ b/libs/vr/libperformance/performance_client.cpp
@@ -37,6 +37,26 @@
task_id, WrapString(partition)));
}
+int PerformanceClient::SetSchedulerPolicy(pid_t task_id,
+ const std::string& scheduler_policy) {
+ if (task_id == 0)
+ task_id = gettid();
+
+ return ReturnStatusOrError(
+ InvokeRemoteMethod<PerformanceRPC::SetSchedulerPolicy>(task_id,
+ scheduler_policy));
+}
+
+int PerformanceClient::SetSchedulerPolicy(pid_t task_id,
+ const char* scheduler_policy) {
+ if (task_id == 0)
+ task_id = gettid();
+
+ return ReturnStatusOrError(
+ InvokeRemoteMethod<PerformanceRPC::SetSchedulerPolicy>(
+ task_id, WrapString(scheduler_policy)));
+}
+
int PerformanceClient::SetSchedulerClass(pid_t task_id,
const std::string& scheduler_class) {
if (task_id == 0)
@@ -101,6 +121,15 @@
return error;
}
+extern "C" int dvrSetSchedulerPolicy(pid_t task_id,
+ const char* scheduler_policy) {
+ int error;
+ if (auto client = android::dvr::PerformanceClient::Create(&error))
+ return client->SetSchedulerPolicy(task_id, scheduler_policy);
+ else
+ return error;
+}
+
extern "C" int dvrSetSchedulerClass(pid_t task_id,
const char* scheduler_class) {
int error;
diff --git a/libs/vr/libvrflinger/acquired_buffer.cpp b/libs/vr/libvrflinger/acquired_buffer.cpp
index 7932a9c..9614c6d 100644
--- a/libs/vr/libvrflinger/acquired_buffer.cpp
+++ b/libs/vr/libvrflinger/acquired_buffer.cpp
@@ -9,8 +9,8 @@
namespace dvr {
AcquiredBuffer::AcquiredBuffer(const std::shared_ptr<BufferConsumer>& buffer,
- LocalHandle acquire_fence)
- : buffer_(buffer), acquire_fence_(std::move(acquire_fence)) {}
+ LocalHandle acquire_fence, std::size_t slot)
+ : buffer_(buffer), acquire_fence_(std::move(acquire_fence)), slot_(slot) {}
AcquiredBuffer::AcquiredBuffer(const std::shared_ptr<BufferConsumer>& buffer,
int* error) {
@@ -31,18 +31,20 @@
}
}
-AcquiredBuffer::AcquiredBuffer(AcquiredBuffer&& other)
- : buffer_(std::move(other.buffer_)),
- acquire_fence_(std::move(other.acquire_fence_)) {}
+AcquiredBuffer::AcquiredBuffer(AcquiredBuffer&& other) {
+ *this = std::move(other);
+}
AcquiredBuffer::~AcquiredBuffer() { Release(LocalHandle(kEmptyFence)); }
AcquiredBuffer& AcquiredBuffer::operator=(AcquiredBuffer&& other) {
if (this != &other) {
- Release(LocalHandle(kEmptyFence));
+ Release();
- buffer_ = std::move(other.buffer_);
- acquire_fence_ = std::move(other.acquire_fence_);
+ using std::swap;
+ swap(buffer_, other.buffer_);
+ swap(acquire_fence_, other.acquire_fence_);
+ swap(slot_, other.slot_);
}
return *this;
}
@@ -55,9 +57,9 @@
if (acquire_fence_) {
const int ret = sync_wait(acquire_fence_.Get(), 0);
ALOGD_IF(TRACE || (ret < 0 && errno != ETIME),
- "AcquiredBuffer::IsAvailable: acquire_fence_=%d sync_wait()=%d "
- "errno=%d.",
- acquire_fence_.Get(), ret, ret < 0 ? errno : 0);
+ "AcquiredBuffer::IsAvailable: buffer_id=%d acquire_fence=%d "
+ "sync_wait()=%d errno=%d.",
+ buffer_->id(), acquire_fence_.Get(), ret, ret < 0 ? errno : 0);
if (ret == 0) {
// The fence is completed, so to avoid further calls to sync_wait we close
// it here.
@@ -78,9 +80,9 @@
}
int AcquiredBuffer::Release(LocalHandle release_fence) {
+ ALOGD_IF(TRACE, "AcquiredBuffer::Release: buffer_id=%d release_fence=%d",
+ buffer_ ? buffer_->id() : -1, release_fence.Get());
if (buffer_) {
- // Close the release fence since we can't transfer it with an async release.
- release_fence.Close();
const int ret = buffer_->ReleaseAsync();
if (ret < 0) {
ALOGE("AcquiredBuffer::Release: Failed to release buffer %d: %s",
@@ -90,9 +92,10 @@
}
buffer_ = nullptr;
- acquire_fence_.Close();
}
+ acquire_fence_.Close();
+ slot_ = 0;
return 0;
}
diff --git a/libs/vr/libvrflinger/acquired_buffer.h b/libs/vr/libvrflinger/acquired_buffer.h
index dd4fcc5..32e912a 100644
--- a/libs/vr/libvrflinger/acquired_buffer.h
+++ b/libs/vr/libvrflinger/acquired_buffer.h
@@ -21,7 +21,7 @@
// this constructor; the constructor does not attempt to ACQUIRE the buffer
// itself.
AcquiredBuffer(const std::shared_ptr<BufferConsumer>& buffer,
- pdx::LocalHandle acquire_fence);
+ pdx::LocalHandle acquire_fence, std::size_t slot = 0);
// Constructs an AcquiredBuffer from a BufferConsumer. The BufferConsumer MUST
// be in the POSTED state prior to calling this constructor, as this
@@ -64,16 +64,21 @@
// to the producer. On success, the BufferConsumer and acquire fence are set
// to empty state; if release fails, the BufferConsumer and acquire fence are
// left in place and a negative error code is returned.
- int Release(pdx::LocalHandle release_fence);
+ int Release(pdx::LocalHandle release_fence = {});
+
+ // Returns the slot in the queue this buffer belongs to. Buffers that are not
+ // part of a queue return 0.
+ std::size_t slot() const { return slot_; }
private:
- AcquiredBuffer(const AcquiredBuffer&) = delete;
- void operator=(const AcquiredBuffer&) = delete;
-
std::shared_ptr<BufferConsumer> buffer_;
// Mutable so that the fence can be closed when it is determined to be
// signaled during IsAvailable().
mutable pdx::LocalHandle acquire_fence_;
+ std::size_t slot_{0};
+
+ AcquiredBuffer(const AcquiredBuffer&) = delete;
+ void operator=(const AcquiredBuffer&) = delete;
};
} // namespace dvr
diff --git a/libs/vr/libvrflinger/display_manager_service.cpp b/libs/vr/libvrflinger/display_manager_service.cpp
index 0e9a6ab..ef8cca3 100644
--- a/libs/vr/libvrflinger/display_manager_service.cpp
+++ b/libs/vr/libvrflinger/display_manager_service.cpp
@@ -65,6 +65,7 @@
}
pdx::Status<void> DisplayManagerService::HandleMessage(pdx::Message& message) {
+ ATRACE_NAME("DisplayManagerService::HandleMessage");
auto channel = std::static_pointer_cast<DisplayManager>(message.GetChannel());
switch (message.GetOp()) {
@@ -78,16 +79,6 @@
*this, &DisplayManagerService::OnGetSurfaceQueue, message);
return {};
- case DisplayManagerProtocol::SetupGlobalBuffer::Opcode:
- DispatchRemoteMethod<DisplayManagerProtocol::SetupGlobalBuffer>(
- *this, &DisplayManagerService::OnSetupGlobalBuffer, message);
- return {};
-
- case DisplayManagerProtocol::DeleteGlobalBuffer::Opcode:
- DispatchRemoteMethod<DisplayManagerProtocol::DeleteGlobalBuffer>(
- *this, &DisplayManagerService::OnDeleteGlobalBuffer, message);
- return {};
-
default:
return Service::DefaultHandleMessage(message);
}
@@ -134,36 +125,6 @@
return status;
}
-pdx::Status<BorrowedNativeBufferHandle>
-DisplayManagerService::OnSetupGlobalBuffer(pdx::Message& message,
- DvrGlobalBufferKey key, size_t size,
- uint64_t usage) {
- const int user_id = message.GetEffectiveUserId();
- const bool trusted = user_id == AID_ROOT || IsTrustedUid(user_id);
-
- if (!trusted) {
- ALOGE(
- "DisplayService::SetupGlobalBuffer: Global buffers may only be created "
- "by trusted UIDs: user_id=%d",
- user_id);
- return ErrorStatus(EPERM);
- }
- return display_service_->SetupGlobalBuffer(key, size, usage);
-}
-
-pdx::Status<void> DisplayManagerService::OnDeleteGlobalBuffer(
- pdx::Message& message, DvrGlobalBufferKey key) {
- const int user_id = message.GetEffectiveUserId();
- const bool trusted = (user_id == AID_ROOT) || IsTrustedUid(user_id);
-
- if (!trusted) {
- ALOGE("DisplayService::DeleteGlobalBuffer: Untrusted user_id (%d)",
- user_id);
- return ErrorStatus(EPERM);
- }
- return display_service_->DeleteGlobalBuffer(key);
-}
-
void DisplayManagerService::OnDisplaySurfaceChange() {
if (display_manager_)
display_manager_->SetNotificationsPending(true);
diff --git a/libs/vr/libvrflinger/display_manager_service.h b/libs/vr/libvrflinger/display_manager_service.h
index c869ceb..3133fe1 100644
--- a/libs/vr/libvrflinger/display_manager_service.h
+++ b/libs/vr/libvrflinger/display_manager_service.h
@@ -56,11 +56,6 @@
pdx::Status<pdx::LocalChannelHandle> OnGetSurfaceQueue(pdx::Message& message,
int surface_id,
int queue_id);
- pdx::Status<BorrowedNativeBufferHandle> OnSetupGlobalBuffer(
- pdx::Message& message, DvrGlobalBufferKey key, size_t size,
- uint64_t usage);
- pdx::Status<void> OnDeleteGlobalBuffer(pdx::Message& message,
- DvrGlobalBufferKey key);
// Called by the display service to indicate changes to display surfaces that
// the display manager should evaluate.
diff --git a/libs/vr/libvrflinger/display_service.cpp b/libs/vr/libvrflinger/display_service.cpp
index dc9807a..ac68a5e 100644
--- a/libs/vr/libvrflinger/display_service.cpp
+++ b/libs/vr/libvrflinger/display_service.cpp
@@ -1,6 +1,10 @@
#include "display_service.h"
#include <unistd.h>
+
+#include <algorithm>
+#include <sstream>
+#include <string>
#include <vector>
#include <android-base/file.h>
@@ -8,8 +12,10 @@
#include <dvr/dvr_display_types.h>
#include <pdx/default_transport/service_endpoint.h>
#include <pdx/rpc/remote_method.h>
+#include <private/android_filesystem_config.h>
#include <private/dvr/display_protocol.h>
#include <private/dvr/numeric.h>
+#include <private/dvr/trusted_uids.h>
#include <private/dvr/types.h>
using android::dvr::display::DisplayProtocol;
@@ -34,10 +40,8 @@
DisplayService::DisplayService(Hwc2::Composer* hidl,
RequestDisplayCallback request_display_callback)
: BASE("DisplayService",
- Endpoint::Create(display::DisplayProtocol::kClientPath)),
- hardware_composer_(hidl, request_display_callback),
- request_display_callback_(request_display_callback) {
- hardware_composer_.Initialize();
+ Endpoint::Create(display::DisplayProtocol::kClientPath)) {
+ hardware_composer_.Initialize(hidl, request_display_callback);
}
bool DisplayService::IsInitialized() const {
@@ -45,7 +49,65 @@
}
std::string DisplayService::DumpState(size_t /*max_length*/) {
- return hardware_composer_.Dump();
+ std::ostringstream stream;
+
+ auto surfaces = GetDisplaySurfaces();
+ std::sort(surfaces.begin(), surfaces.end(), [](const auto& a, const auto& b) {
+ return a->surface_id() < b->surface_id();
+ });
+
+ stream << "Application Surfaces:" << std::endl;
+
+ size_t count = 0;
+ for (const auto& surface : surfaces) {
+ if (surface->surface_type() == SurfaceType::Application) {
+ stream << "Surface " << count++ << ":";
+ stream << " surface_id=" << surface->surface_id()
+ << " process_id=" << surface->process_id()
+ << " user_id=" << surface->user_id()
+ << " visible=" << surface->visible()
+ << " z_order=" << surface->z_order();
+
+ stream << " queue_ids=";
+ auto queue_ids = surface->GetQueueIds();
+ std::sort(queue_ids.begin(), queue_ids.end());
+ for (int32_t id : queue_ids) {
+ if (id != queue_ids[0])
+ stream << ",";
+ stream << id;
+ }
+ stream << std::endl;
+ }
+ }
+ stream << std::endl;
+
+ stream << "Direct Surfaces:" << std::endl;
+
+ count = 0;
+ for (const auto& surface : surfaces) {
+ if (surface->surface_type() == SurfaceType::Direct) {
+ stream << "Surface " << count++ << ":";
+ stream << " surface_id=" << surface->surface_id()
+ << " process_id=" << surface->process_id()
+ << " user_id=" << surface->user_id()
+ << " visible=" << surface->visible()
+ << " z_order=" << surface->z_order();
+
+ stream << " queue_ids=";
+ auto queue_ids = surface->GetQueueIds();
+ std::sort(queue_ids.begin(), queue_ids.end());
+ for (int32_t id : queue_ids) {
+ if (id != queue_ids[0])
+ stream << ",";
+ stream << id;
+ }
+ stream << std::endl;
+ }
+ }
+ stream << std::endl;
+
+ stream << hardware_composer_.Dump();
+ return stream.str();
}
void DisplayService::OnChannelClose(pdx::Message& message,
@@ -54,8 +116,6 @@
surface->OnSetAttributes(message,
{{display::SurfaceAttribute::Visible,
display::SurfaceAttributeValue{false}}});
- SurfaceUpdated(surface->surface_type(),
- display::SurfaceUpdateFlags::VisibilityChanged);
}
}
@@ -64,6 +124,8 @@
// surface-specific messages to the per-instance handlers.
Status<void> DisplayService::HandleMessage(pdx::Message& message) {
ALOGD_IF(TRACE, "DisplayService::HandleMessage: opcode=%d", message.GetOp());
+ ATRACE_NAME("DisplayService::HandleMessage");
+
switch (message.GetOp()) {
case DisplayProtocol::GetMetrics::Opcode:
DispatchRemoteMethod<DisplayProtocol::GetMetrics>(
@@ -80,6 +142,16 @@
*this, &DisplayService::OnCreateSurface, message);
return {};
+ case DisplayProtocol::SetupGlobalBuffer::Opcode:
+ DispatchRemoteMethod<DisplayProtocol::SetupGlobalBuffer>(
+ *this, &DisplayService::OnSetupGlobalBuffer, message);
+ return {};
+
+ case DisplayProtocol::DeleteGlobalBuffer::Opcode:
+ DispatchRemoteMethod<DisplayProtocol::DeleteGlobalBuffer>(
+ *this, &DisplayService::OnDeleteGlobalBuffer, message);
+ return {};
+
case DisplayProtocol::GetGlobalBuffer::Opcode:
DispatchRemoteMethod<DisplayProtocol::GetGlobalBuffer>(
*this, &DisplayService::OnGetGlobalBuffer, message);
@@ -173,18 +245,16 @@
surface_status.GetErrorMessage().c_str());
return ErrorStatus(surface_status.error());
}
+ auto surface = surface_status.take();
+ message.SetChannel(surface);
- SurfaceType surface_type = surface_status.get()->surface_type();
- display::SurfaceUpdateFlags update_flags =
- surface_status.get()->update_flags();
- display::SurfaceInfo surface_info{surface_status.get()->surface_id(),
- surface_status.get()->visible(),
- surface_status.get()->z_order()};
+ // Update the surface with the attributes supplied with the create call. For
+ // application surfaces this has the side effect of notifying the display
+ // manager of the new surface. For direct surfaces, this may trigger a mode
+ // change, depending on the value of the visible attribute.
+ surface->OnSetAttributes(message, attributes);
- message.SetChannel(surface_status.take());
-
- SurfaceUpdated(surface_type, update_flags);
- return {surface_info};
+ return {{surface->surface_id(), surface->visible(), surface->z_order()}};
}
void DisplayService::SurfaceUpdated(SurfaceType surface_type,
@@ -199,6 +269,36 @@
}
}
+pdx::Status<BorrowedNativeBufferHandle> DisplayService::OnSetupGlobalBuffer(
+ pdx::Message& message, DvrGlobalBufferKey key, size_t size,
+ uint64_t usage) {
+ const int user_id = message.GetEffectiveUserId();
+ const bool trusted = user_id == AID_ROOT || IsTrustedUid(user_id);
+
+ if (!trusted) {
+ ALOGE(
+ "DisplayService::OnSetupGlobalBuffer: Permission denied for user_id=%d",
+ user_id);
+ return ErrorStatus(EPERM);
+ }
+ return SetupGlobalBuffer(key, size, usage);
+}
+
+pdx::Status<void> DisplayService::OnDeleteGlobalBuffer(pdx::Message& message,
+ DvrGlobalBufferKey key) {
+ const int user_id = message.GetEffectiveUserId();
+ const bool trusted = (user_id == AID_ROOT) || IsTrustedUid(user_id);
+
+ if (!trusted) {
+ ALOGE(
+ "DisplayService::OnDeleteGlobalBuffer: Permission denied for "
+ "user_id=%d",
+ user_id);
+ return ErrorStatus(EPERM);
+ }
+ return DeleteGlobalBuffer(key);
+}
+
pdx::Status<BorrowedNativeBufferHandle> DisplayService::OnGetGlobalBuffer(
pdx::Message& /* message */, DvrGlobalBufferKey key) {
ALOGD_IF(TRACE, "DisplayService::OnGetGlobalBuffer: key=%d", key);
@@ -251,17 +351,9 @@
void DisplayService::UpdateActiveDisplaySurfaces() {
auto visible_surfaces = GetVisibleDisplaySurfaces();
-
- std::sort(visible_surfaces.begin(), visible_surfaces.end(),
- [](const std::shared_ptr<DisplaySurface>& a,
- const std::shared_ptr<DisplaySurface>& b) {
- return a->z_order() < b->z_order();
- });
-
ALOGD_IF(TRACE,
"DisplayService::UpdateActiveDisplaySurfaces: %zd visible surfaces",
visible_surfaces.size());
-
hardware_composer_.SetDisplaySurfaces(std::move(visible_surfaces));
}
@@ -296,10 +388,6 @@
return {0};
}
-void DisplayService::OnHardwareComposerRefresh() {
- hardware_composer_.OnHardwareComposerRefresh();
-}
-
void DisplayService::SetDisplayConfigurationUpdateNotifier(
DisplayConfigurationUpdateNotifier update_notifier) {
update_notifier_ = update_notifier;
diff --git a/libs/vr/libvrflinger/display_service.h b/libs/vr/libvrflinger/display_service.h
index cb21e9f..55e33ab 100644
--- a/libs/vr/libvrflinger/display_service.h
+++ b/libs/vr/libvrflinger/display_service.h
@@ -72,8 +72,6 @@
void GrantDisplayOwnership() { hardware_composer_.Enable(); }
void SeizeDisplayOwnership() { hardware_composer_.Disable(); }
- void OnHardwareComposerRefresh();
-
private:
friend BASE;
friend DisplaySurface;
@@ -92,6 +90,11 @@
pdx::Message& message, display::ConfigFileType config_type);
pdx::Status<display::SurfaceInfo> OnCreateSurface(
pdx::Message& message, const display::SurfaceAttributes& attributes);
+ pdx::Status<BorrowedNativeBufferHandle> OnSetupGlobalBuffer(
+ pdx::Message& message, DvrGlobalBufferKey key, size_t size,
+ uint64_t usage);
+ pdx::Status<void> OnDeleteGlobalBuffer(pdx::Message& message,
+ DvrGlobalBufferKey key);
// Temporary query for current VR status. Will be removed later.
pdx::Status<bool> IsVrAppRunning(pdx::Message& message);
@@ -114,7 +117,6 @@
pdx::Status<void> HandleSurfaceMessage(pdx::Message& message);
HardwareComposer hardware_composer_;
- RequestDisplayCallback request_display_callback_;
EpollEventDispatcher dispatcher_;
DisplayConfigurationUpdateNotifier update_notifier_;
diff --git a/libs/vr/libvrflinger/display_surface.cpp b/libs/vr/libvrflinger/display_surface.cpp
index d836fba..87c823e 100644
--- a/libs/vr/libvrflinger/display_surface.cpp
+++ b/libs/vr/libvrflinger/display_surface.cpp
@@ -26,14 +26,12 @@
DisplaySurface::DisplaySurface(DisplayService* service,
SurfaceType surface_type, int surface_id,
- int process_id, int user_id,
- const display::SurfaceAttributes& attributes)
+ int process_id, int user_id)
: service_(service),
surface_type_(surface_type),
surface_id_(surface_id),
process_id_(process_id),
user_id_(user_id),
- attributes_(attributes),
update_flags_(display::SurfaceUpdateFlags::NewSurface) {}
DisplaySurface::~DisplaySurface() {
@@ -68,7 +66,7 @@
display::SurfaceUpdateFlags update_flags;
for (const auto& attribute : attributes) {
- const auto& key = attribute.first;
+ const auto key = attribute.first;
const auto* variant = &attribute.second;
bool invalid_value = false;
bool visibility_changed = false;
@@ -95,14 +93,23 @@
break;
}
+ // Only update the attribute map with valid values. This check also has the
+ // effect of preventing special attributes handled above from being deleted
+ // by an empty value.
if (invalid_value) {
ALOGW(
"DisplaySurface::OnClientSetAttributes: Failed to set display "
"surface attribute '%d' because of incompatible type: %d",
key, variant->index());
} else {
- // Only update the attribute map with valid values.
- attributes_[attribute.first] = attribute.second;
+ // An empty value indicates the attribute should be deleted.
+ if (variant->empty()) {
+ auto search = attributes_.find(key);
+ if (search != attributes_.end())
+ attributes_.erase(search);
+ } else {
+ attributes_[key] = *variant;
+ }
// All attribute changes generate a notification, even if the value
// doesn't change. Visibility attributes set a flag only if the value
@@ -127,7 +134,8 @@
}
void DisplaySurface::ClearUpdate() {
- ALOGD_IF(TRACE, "DisplaySurface::ClearUpdate: surface_id=%d", surface_id());
+ ALOGD_IF(TRACE > 1, "DisplaySurface::ClearUpdate: surface_id=%d",
+ surface_id());
update_flags_ = display::SurfaceUpdateFlags::None;
}
@@ -184,6 +192,7 @@
"ApplicationDisplaySurface::GetQueue: surface_id=%d queue_id=%d",
surface_id(), queue_id);
+ std::lock_guard<std::mutex> autolock(lock_);
auto search = consumer_queues_.find(queue_id);
if (search != consumer_queues_.end())
return search->second;
@@ -192,6 +201,7 @@
}
std::vector<int32_t> ApplicationDisplaySurface::GetQueueIds() const {
+ std::lock_guard<std::mutex> autolock(lock_);
std::vector<int32_t> queue_ids;
for (const auto& entry : consumer_queues_)
queue_ids.push_back(entry.first);
@@ -203,8 +213,8 @@
ATRACE_NAME("ApplicationDisplaySurface::OnCreateQueue");
ALOGD_IF(TRACE,
"ApplicationDisplaySurface::OnCreateQueue: surface_id=%d, "
- "meta_size_bytes=%zu",
- surface_id(), config.meta_size_bytes);
+ "user_metadata_size=%zu",
+ surface_id(), config.user_metadata_size);
std::lock_guard<std::mutex> autolock(lock_);
auto producer = ProducerQueue::Create(config, UsagePolicy{});
@@ -238,11 +248,12 @@
"ApplicationDisplaySurface::OnQueueEvent: queue_id=%d events=%x",
consumer_queue->id(), events);
+ std::lock_guard<std::mutex> autolock(lock_);
+
// Always give the queue a chance to handle its internal bookkeeping.
consumer_queue->HandleQueueEvents();
// Check for hangup and remove a queue that is no longer needed.
- std::lock_guard<std::mutex> autolock(lock_);
if (consumer_queue->hung_up()) {
ALOGD_IF(TRACE, "ApplicationDisplaySurface::OnQueueEvent: Removing queue.");
UnregisterQueue(consumer_queue);
@@ -258,13 +269,21 @@
}
}
+std::vector<int32_t> DirectDisplaySurface::GetQueueIds() const {
+ std::lock_guard<std::mutex> autolock(lock_);
+ std::vector<int32_t> queue_ids;
+ if (direct_queue_)
+ queue_ids.push_back(direct_queue_->id());
+ return queue_ids;
+}
+
Status<LocalChannelHandle> DirectDisplaySurface::OnCreateQueue(
Message& /*message*/, const ProducerQueueConfig& config) {
ATRACE_NAME("DirectDisplaySurface::OnCreateQueue");
- ALOGD_IF(
- TRACE,
- "DirectDisplaySurface::OnCreateQueue: surface_id=%d meta_size_bytes=%zu",
- surface_id(), config.meta_size_bytes);
+ ALOGD_IF(TRACE,
+ "DirectDisplaySurface::OnCreateQueue: surface_id=%d "
+ "user_metadata_size=%zu",
+ surface_id(), config.user_metadata_size);
std::lock_guard<std::mutex> autolock(lock_);
if (!direct_queue_) {
@@ -280,6 +299,9 @@
}
direct_queue_ = producer->CreateConsumerQueue();
+ if (direct_queue_->metadata_size() > 0) {
+ metadata_.reset(new uint8_t[direct_queue_->metadata_size()]);
+ }
auto status = RegisterQueue(direct_queue_);
if (!status) {
ALOGE(
@@ -300,11 +322,12 @@
ALOGD_IF(TRACE, "DirectDisplaySurface::OnQueueEvent: queue_id=%d events=%x",
consumer_queue->id(), events);
+ std::lock_guard<std::mutex> autolock(lock_);
+
// Always give the queue a chance to handle its internal bookkeeping.
consumer_queue->HandleQueueEvents();
// Check for hangup and remove a queue that is no longer needed.
- std::lock_guard<std::mutex> autolock(lock_);
if (consumer_queue->hung_up()) {
ALOGD_IF(TRACE, "DirectDisplaySurface::OnQueueEvent: Removing queue.");
UnregisterQueue(consumer_queue);
@@ -323,10 +346,15 @@
while (true) {
LocalHandle acquire_fence;
size_t slot;
- auto buffer_status = direct_queue_->Dequeue(0, &slot, &acquire_fence);
+ auto buffer_status = direct_queue_->Dequeue(
+ 0, &slot, metadata_.get(),
+ direct_queue_->metadata_size(), &acquire_fence);
+ ALOGD_IF(TRACE,
+ "DirectDisplaySurface::DequeueBuffersLocked: Dequeue with metadata_size: %zu",
+ direct_queue_->metadata_size());
if (!buffer_status) {
ALOGD_IF(
- TRACE && buffer_status.error() == ETIMEDOUT,
+ TRACE > 1 && buffer_status.error() == ETIMEDOUT,
"DirectDisplaySurface::DequeueBuffersLocked: All buffers dequeued.");
ALOGE_IF(buffer_status.error() != ETIMEDOUT,
"DirectDisplaySurface::DequeueBuffersLocked: Failed to dequeue "
@@ -354,7 +382,7 @@
}
acquired_buffers_.Append(
- AcquiredBuffer(buffer_consumer, std::move(acquire_fence)));
+ AcquiredBuffer(buffer_consumer, std::move(acquire_fence), slot));
}
}
@@ -370,8 +398,8 @@
}
AcquiredBuffer buffer = std::move(acquired_buffers_.Front());
acquired_buffers_.PopFront();
- ALOGD_IF(TRACE, "DirectDisplaySurface::AcquireCurrentBuffer: buffer: %p",
- buffer.buffer().get());
+ ALOGD_IF(TRACE, "DirectDisplaySurface::AcquireCurrentBuffer: buffer_id=%d",
+ buffer.buffer()->id());
return buffer;
}
@@ -399,8 +427,8 @@
break;
}
ALOGD_IF(TRACE,
- "DirectDisplaySurface::AcquireNewestAvailableBuffer: buffer: %p",
- buffer.buffer().get());
+ "DirectDisplaySurface::AcquireNewestAvailableBuffer: buffer_id=%d",
+ buffer.buffer()->id());
return buffer;
}
@@ -441,8 +469,8 @@
if (direct) {
const bool trusted = user_id == AID_ROOT || IsTrustedUid(user_id);
if (trusted) {
- return {std::shared_ptr<DisplaySurface>{new DirectDisplaySurface(
- service, surface_id, process_id, user_id, attributes)}};
+ return {std::shared_ptr<DisplaySurface>{
+ new DirectDisplaySurface(service, surface_id, process_id, user_id)}};
} else {
ALOGE(
"DisplaySurface::Create: Direct surfaces may only be created by "
@@ -452,7 +480,7 @@
}
} else {
return {std::shared_ptr<DisplaySurface>{new ApplicationDisplaySurface(
- service, surface_id, process_id, user_id, attributes)}};
+ service, surface_id, process_id, user_id)}};
}
}
diff --git a/libs/vr/libvrflinger/display_surface.h b/libs/vr/libvrflinger/display_surface.h
index 5380062..c8b1a07 100644
--- a/libs/vr/libvrflinger/display_surface.h
+++ b/libs/vr/libvrflinger/display_surface.h
@@ -53,8 +53,7 @@
protected:
DisplaySurface(DisplayService* service, SurfaceType surface_type,
- int surface_id, int process_id, int user_id,
- const display::SurfaceAttributes& attributes);
+ int surface_id, int process_id, int user_id);
// Utility to retrieve a shared pointer to this channel as the desired derived
// type.
@@ -119,10 +118,9 @@
class ApplicationDisplaySurface : public DisplaySurface {
public:
ApplicationDisplaySurface(DisplayService* service, int surface_id,
- int process_id, int user_id,
- const display::SurfaceAttributes& attributes)
+ int process_id, int user_id)
: DisplaySurface(service, SurfaceType::Application, surface_id,
- process_id, user_id, attributes) {}
+ process_id, user_id) {}
std::shared_ptr<ConsumerQueue> GetQueue(int32_t queue_id);
std::vector<int32_t> GetQueueIds() const override;
@@ -133,17 +131,19 @@
void OnQueueEvent(const std::shared_ptr<ConsumerQueue>& consumer_queue,
int events) override;
+ // Accessed by both message dispatch thread and epoll event thread.
std::unordered_map<int32_t, std::shared_ptr<ConsumerQueue>> consumer_queues_;
};
class DirectDisplaySurface : public DisplaySurface {
public:
DirectDisplaySurface(DisplayService* service, int surface_id, int process_id,
- int user_id,
- const display::SurfaceAttributes& attributes)
+ int user_id)
: DisplaySurface(service, SurfaceType::Direct, surface_id, process_id,
- user_id, attributes),
- acquired_buffers_(kMaxPostedBuffers) {}
+ user_id),
+ acquired_buffers_(kMaxPostedBuffers),
+ metadata_(nullptr) {}
+ std::vector<int32_t> GetQueueIds() const override;
bool IsBufferAvailable();
bool IsBufferPosted();
AcquiredBuffer AcquireCurrentBuffer();
@@ -177,6 +177,9 @@
RingBuffer<AcquiredBuffer> acquired_buffers_;
std::shared_ptr<ConsumerQueue> direct_queue_;
+
+ // Stores metadata when it dequeue buffers from consumer queue.
+ std::unique_ptr<uint8_t[]> metadata_;
};
} // namespace dvr
diff --git a/libs/vr/libvrflinger/epoll_event_dispatcher.cpp b/libs/vr/libvrflinger/epoll_event_dispatcher.cpp
index 06b69bb..962c745 100644
--- a/libs/vr/libvrflinger/epoll_event_dispatcher.cpp
+++ b/libs/vr/libvrflinger/epoll_event_dispatcher.cpp
@@ -101,12 +101,12 @@
if (num_events < 0 && errno != EINTR)
break;
- ALOGD_IF(TRACE, "EpollEventDispatcher::EventThread: num_events=%d",
+ ALOGD_IF(TRACE > 1, "EpollEventDispatcher::EventThread: num_events=%d",
num_events);
for (int i = 0; i < num_events; i++) {
ALOGD_IF(
- TRACE,
+ TRACE > 1,
"EpollEventDispatcher::EventThread: event %d: handler=%p events=0x%x",
i, events[i].data.ptr, events[i].events);
diff --git a/libs/vr/libvrflinger/hardware_composer.cpp b/libs/vr/libvrflinger/hardware_composer.cpp
index 7a78d1f..44be0ab 100644
--- a/libs/vr/libvrflinger/hardware_composer.cpp
+++ b/libs/vr/libvrflinger/hardware_composer.cpp
@@ -5,12 +5,14 @@
#include <fcntl.h>
#include <log/log.h>
#include <poll.h>
+#include <stdint.h>
#include <sync/sync.h>
#include <sys/eventfd.h>
#include <sys/prctl.h>
#include <sys/resource.h>
#include <sys/system_properties.h>
#include <sys/timerfd.h>
+#include <sys/types.h>
#include <time.h>
#include <unistd.h>
#include <utils/Trace.h>
@@ -19,6 +21,8 @@
#include <chrono>
#include <functional>
#include <map>
+#include <sstream>
+#include <string>
#include <tuple>
#include <dvr/dvr_display_types.h>
@@ -26,7 +30,11 @@
#include <private/dvr/clock_ns.h>
#include <private/dvr/ion_buffer.h>
+using android::hardware::Return;
+using android::hardware::Void;
+using android::pdx::ErrorStatus;
using android::pdx::LocalHandle;
+using android::pdx::Status;
using android::pdx::rpc::EmptyVariant;
using android::pdx::rpc::IfAnyOf;
@@ -40,12 +48,8 @@
const char kBacklightBrightnessSysFile[] =
"/sys/class/leds/lcd-backlight/brightness";
-const char kPrimaryDisplayVSyncEventFile[] =
- "/sys/class/graphics/fb0/vsync_event";
-
-const char kPrimaryDisplayWaitPPEventFile[] = "/sys/class/graphics/fb0/wait_pp";
-
const char kDvrPerformanceProperty[] = "sys.dvr.performance";
+const char kDvrStandaloneProperty[] = "ro.boot.vr";
const char kRightEyeOffsetProperty[] = "dvr.right_eye_offset_ns";
@@ -82,24 +86,33 @@
return true;
}
+// Utility to generate scoped tracers with arguments.
+// TODO(eieio): Move/merge this into utils/Trace.h?
+class TraceArgs {
+ public:
+ template <typename... Args>
+ TraceArgs(const char* format, Args&&... args) {
+ std::array<char, 1024> buffer;
+ snprintf(buffer.data(), buffer.size(), format, std::forward<Args>(args)...);
+ atrace_begin(ATRACE_TAG, buffer.data());
+ }
+
+ ~TraceArgs() { atrace_end(ATRACE_TAG); }
+
+ private:
+ TraceArgs(const TraceArgs&) = delete;
+ void operator=(const TraceArgs&) = delete;
+};
+
+// Macro to define a scoped tracer with arguments. Uses PASTE(x, y) macro
+// defined in utils/Trace.h.
+#define TRACE_FORMAT(format, ...) \
+ TraceArgs PASTE(__tracer, __LINE__) { format, ##__VA_ARGS__ }
+
} // anonymous namespace
-// Layer static data.
-Hwc2::Composer* Layer::hwc2_hidl_;
-const HWCDisplayMetrics* Layer::display_metrics_;
-
-// HardwareComposer static data;
-constexpr size_t HardwareComposer::kMaxHardwareLayers;
-
HardwareComposer::HardwareComposer()
- : HardwareComposer(nullptr, RequestDisplayCallback()) {}
-
-HardwareComposer::HardwareComposer(
- Hwc2::Composer* hwc2_hidl, RequestDisplayCallback request_display_callback)
- : initialized_(false),
- hwc2_hidl_(hwc2_hidl),
- request_display_callback_(request_display_callback),
- callbacks_(new ComposerCallback) {}
+ : initialized_(false), request_display_callback_(nullptr) {}
HardwareComposer::~HardwareComposer(void) {
UpdatePostThreadState(PostThreadState::Quit, true);
@@ -107,16 +120,21 @@
post_thread_.join();
}
-bool HardwareComposer::Initialize() {
+bool HardwareComposer::Initialize(
+ Hwc2::Composer* composer, RequestDisplayCallback request_display_callback) {
if (initialized_) {
ALOGE("HardwareComposer::Initialize: already initialized.");
return false;
}
+ is_standalone_device_ = property_get_bool(kDvrStandaloneProperty, false);
+
+ request_display_callback_ = request_display_callback;
+
HWC::Error error = HWC::Error::None;
Hwc2::Config config;
- error = hwc2_hidl_->getActiveConfig(HWC_DISPLAY_PRIMARY, &config);
+ error = composer->getActiveConfig(HWC_DISPLAY_PRIMARY, &config);
if (error != HWC::Error::None) {
ALOGE("HardwareComposer: Failed to get current display config : %d",
@@ -124,8 +142,8 @@
return false;
}
- error =
- GetDisplayMetrics(HWC_DISPLAY_PRIMARY, config, &native_display_metrics_);
+ error = GetDisplayMetrics(composer, HWC_DISPLAY_PRIMARY, config,
+ &native_display_metrics_);
if (error != HWC::Error::None) {
ALOGE(
@@ -147,8 +165,8 @@
display_transform_ = HWC_TRANSFORM_NONE;
display_metrics_ = native_display_metrics_;
- // Pass hwc instance and metrics to setup globals for Layer.
- Layer::InitializeGlobals(hwc2_hidl_, &native_display_metrics_);
+ // Setup the display metrics used by all Layer instances.
+ Layer::SetDisplayMetrics(native_display_metrics_);
post_thread_event_fd_.Reset(eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK));
LOG_ALWAYS_FATAL_IF(
@@ -208,15 +226,19 @@
}
void HardwareComposer::OnPostThreadResumed() {
- hwc2_hidl_->resetCommands();
+ // Phones create a new composer client on resume and destroy it on pause.
+ // Standalones only create the composer client once and then use SetPowerMode
+ // to control the screen on pause/resume.
+ if (!is_standalone_device_ || !composer_) {
+ composer_.reset(new Hwc2::Composer("default"));
+ composer_callback_ = new ComposerCallback;
+ composer_->registerCallback(composer_callback_);
+ Layer::SetComposer(composer_.get());
+ } else {
+ SetPowerMode(true);
+ }
- // HIDL HWC seems to have an internal race condition. If we submit a frame too
- // soon after turning on VSync we don't get any VSync signals. Give poor HWC
- // implementations a chance to enable VSync before we continue.
- EnableVsync(false);
- std::this_thread::sleep_for(100ms);
EnableVsync(true);
- std::this_thread::sleep_for(100ms);
// TODO(skiazyk): We need to do something about accessing this directly,
// supposedly there is a backlight service on the way.
@@ -231,16 +253,19 @@
void HardwareComposer::OnPostThreadPaused() {
retire_fence_fds_.clear();
- display_surfaces_.clear();
+ layers_.clear();
- for (size_t i = 0; i < kMaxHardwareLayers; ++i) {
- layers_[i].Reset();
+ if (composer_) {
+ EnableVsync(false);
}
- active_layer_count_ = 0;
- EnableVsync(false);
-
- hwc2_hidl_->resetCommands();
+ if (!is_standalone_device_) {
+ composer_callback_ = nullptr;
+ composer_.reset(nullptr);
+ Layer::SetComposer(nullptr);
+ } else {
+ SetPowerMode(false);
+ }
// Trigger target-specific performance mode change.
property_set(kDvrPerformanceProperty, "idle");
@@ -250,29 +275,35 @@
uint32_t num_types;
uint32_t num_requests;
HWC::Error error =
- hwc2_hidl_->validateDisplay(display, &num_types, &num_requests);
+ composer_->validateDisplay(display, &num_types, &num_requests);
if (error == HWC2_ERROR_HAS_CHANGES) {
// TODO(skiazyk): We might need to inspect the requested changes first, but
// so far it seems like we shouldn't ever hit a bad state.
// error = hwc2_funcs_.accept_display_changes_fn_(hardware_composer_device_,
// display);
- error = hwc2_hidl_->acceptDisplayChanges(display);
+ error = composer_->acceptDisplayChanges(display);
}
return error;
}
-int32_t HardwareComposer::EnableVsync(bool enabled) {
- return (int32_t)hwc2_hidl_->setVsyncEnabled(
+HWC::Error HardwareComposer::EnableVsync(bool enabled) {
+ return composer_->setVsyncEnabled(
HWC_DISPLAY_PRIMARY,
(Hwc2::IComposerClient::Vsync)(enabled ? HWC2_VSYNC_ENABLE
: HWC2_VSYNC_DISABLE));
}
+HWC::Error HardwareComposer::SetPowerMode(bool active) {
+ HWC::PowerMode power_mode = active ? HWC::PowerMode::On : HWC::PowerMode::Off;
+ return composer_->setPowerMode(
+ HWC_DISPLAY_PRIMARY, power_mode.cast<Hwc2::IComposerClient::PowerMode>());
+}
+
HWC::Error HardwareComposer::Present(hwc2_display_t display) {
int32_t present_fence;
- HWC::Error error = hwc2_hidl_->presentDisplay(display, &present_fence);
+ HWC::Error error = composer_->presentDisplay(display, &present_fence);
// According to the documentation, this fence is signaled at the time of
// vsync/DMA for physical displays.
@@ -286,20 +317,21 @@
return error;
}
-HWC::Error HardwareComposer::GetDisplayAttribute(hwc2_display_t display,
+HWC::Error HardwareComposer::GetDisplayAttribute(Hwc2::Composer* composer,
+ hwc2_display_t display,
hwc2_config_t config,
hwc2_attribute_t attribute,
int32_t* out_value) const {
- return hwc2_hidl_->getDisplayAttribute(
+ return composer->getDisplayAttribute(
display, config, (Hwc2::IComposerClient::Attribute)attribute, out_value);
}
HWC::Error HardwareComposer::GetDisplayMetrics(
- hwc2_display_t display, hwc2_config_t config,
+ Hwc2::Composer* composer, hwc2_display_t display, hwc2_config_t config,
HWCDisplayMetrics* out_metrics) const {
HWC::Error error;
- error = GetDisplayAttribute(display, config, HWC2_ATTRIBUTE_WIDTH,
+ error = GetDisplayAttribute(composer, display, config, HWC2_ATTRIBUTE_WIDTH,
&out_metrics->width);
if (error != HWC::Error::None) {
ALOGE(
@@ -308,7 +340,7 @@
return error;
}
- error = GetDisplayAttribute(display, config, HWC2_ATTRIBUTE_HEIGHT,
+ error = GetDisplayAttribute(composer, display, config, HWC2_ATTRIBUTE_HEIGHT,
&out_metrics->height);
if (error != HWC::Error::None) {
ALOGE(
@@ -317,7 +349,8 @@
return error;
}
- error = GetDisplayAttribute(display, config, HWC2_ATTRIBUTE_VSYNC_PERIOD,
+ error = GetDisplayAttribute(composer, display, config,
+ HWC2_ATTRIBUTE_VSYNC_PERIOD,
&out_metrics->vsync_period_ns);
if (error != HWC::Error::None) {
ALOGE(
@@ -326,7 +359,7 @@
return error;
}
- error = GetDisplayAttribute(display, config, HWC2_ATTRIBUTE_DPI_X,
+ error = GetDisplayAttribute(composer, display, config, HWC2_ATTRIBUTE_DPI_X,
&out_metrics->dpi.x);
if (error != HWC::Error::None) {
ALOGE(
@@ -335,7 +368,7 @@
return error;
}
- error = GetDisplayAttribute(display, config, HWC2_ATTRIBUTE_DPI_Y,
+ error = GetDisplayAttribute(composer, display, config, HWC2_ATTRIBUTE_DPI_Y,
&out_metrics->dpi.y);
if (error != HWC::Error::None) {
ALOGE(
@@ -347,14 +380,43 @@
return HWC::Error::None;
}
-std::string HardwareComposer::Dump() { return hwc2_hidl_->dumpDebugInfo(); }
+std::string HardwareComposer::Dump() {
+ std::unique_lock<std::mutex> lock(post_thread_mutex_);
+ std::ostringstream stream;
+
+ stream << "Display metrics: " << display_metrics_.width << "x"
+ << display_metrics_.height << " " << (display_metrics_.dpi.x / 1000.0)
+ << "x" << (display_metrics_.dpi.y / 1000.0) << " dpi @ "
+ << (1000000000.0 / display_metrics_.vsync_period_ns) << " Hz"
+ << std::endl;
+
+ stream << "Post thread resumed: " << post_thread_resumed_ << std::endl;
+ stream << "Active layers: " << layers_.size() << std::endl;
+ stream << std::endl;
+
+ for (size_t i = 0; i < layers_.size(); i++) {
+ stream << "Layer " << i << ":";
+ stream << " type=" << layers_[i].GetCompositionType().to_string();
+ stream << " surface_id=" << layers_[i].GetSurfaceId();
+ stream << " buffer_id=" << layers_[i].GetBufferId();
+ stream << std::endl;
+ }
+ stream << std::endl;
+
+ if (post_thread_resumed_) {
+ stream << "Hardware Composer Debug Info:" << std::endl;
+ stream << composer_->dumpDebugInfo();
+ }
+
+ return stream.str();
+}
void HardwareComposer::PostLayers() {
ATRACE_NAME("HardwareComposer::PostLayers");
// Setup the hardware composer layers with current buffers.
- for (size_t i = 0; i < active_layer_count_; i++) {
- layers_[i].Prepare();
+ for (auto& layer : layers_) {
+ layer.Prepare();
}
HWC::Error error = Validate(HWC_DISPLAY_PRIMARY);
@@ -376,20 +438,18 @@
retire_fence_fds_.erase(retire_fence_fds_.begin());
}
- const bool is_frame_pending = IsFramePendingInDriver();
- const bool is_fence_pending = retire_fence_fds_.size() >
+ const bool is_fence_pending = static_cast<int32_t>(retire_fence_fds_.size()) >
post_thread_config_.allowed_pending_fence_count;
- if (is_fence_pending || is_frame_pending) {
+ if (is_fence_pending) {
ATRACE_INT("frame_skip_count", ++frame_skip_count_);
- ALOGW_IF(is_frame_pending, "Warning: frame already queued, dropping frame");
ALOGW_IF(is_fence_pending,
"Warning: dropping a frame to catch up with HWC (pending = %zd)",
retire_fence_fds_.size());
- for (size_t i = 0; i < active_layer_count_; i++) {
- layers_[i].Drop();
+ for (auto& layer : layers_) {
+ layer.Drop();
}
return;
} else {
@@ -398,10 +458,12 @@
ATRACE_INT("frame_skip_count", 0);
}
-#if TRACE
- for (size_t i = 0; i < active_layer_count_; i++)
- ALOGI("HardwareComposer::PostLayers: layer=%zu composition=%s", i,
+#if TRACE > 1
+ for (size_t i = 0; i < layers_.size(); i++) {
+ ALOGI("HardwareComposer::PostLayers: layer=%zu buffer_id=%d composition=%s",
+ i, layers_[i].GetBufferId(),
layers_[i].GetCompositionType().to_string().c_str());
+ }
#endif
error = Present(HWC_DISPLAY_PRIMARY);
@@ -413,18 +475,18 @@
std::vector<Hwc2::Layer> out_layers;
std::vector<int> out_fences;
- error = hwc2_hidl_->getReleaseFences(HWC_DISPLAY_PRIMARY, &out_layers,
- &out_fences);
+ error = composer_->getReleaseFences(HWC_DISPLAY_PRIMARY, &out_layers,
+ &out_fences);
ALOGE_IF(error != HWC::Error::None,
"HardwareComposer::PostLayers: Failed to get release fences: %s",
error.to_string().c_str());
- // Perform post-frame bookkeeping. Unused layers are a no-op.
+ // Perform post-frame bookkeeping.
uint32_t num_elements = out_layers.size();
for (size_t i = 0; i < num_elements; ++i) {
- for (size_t j = 0; j < active_layer_count_; ++j) {
- if (layers_[j].GetLayerHandle() == out_layers[i]) {
- layers_[j].Finish(out_fences[i]);
+ for (auto& layer : layers_) {
+ if (layer.GetLayerHandle() == out_layers[i]) {
+ layer.Finish(out_fences[i]);
}
}
}
@@ -440,19 +502,11 @@
pending_surfaces_ = std::move(surfaces);
}
+ if (request_display_callback_ && (!is_standalone_device_ || !composer_))
+ request_display_callback_(!display_idle);
+
// Set idle state based on whether there are any surfaces to handle.
UpdatePostThreadState(PostThreadState::Idle, display_idle);
-
- // XXX: TEMPORARY
- // Request control of the display based on whether there are any surfaces to
- // handle. This callback sets the post thread active state once the transition
- // is complete in SurfaceFlinger.
- // TODO(eieio): Unify the control signal used to move SurfaceFlinger into VR
- // mode. Currently this is hooked up to persistent VR mode, but perhaps this
- // makes more sense to control it from VrCore, which could in turn base its
- // decision on persistent VR mode.
- if (request_display_callback_)
- request_display_callback_(!display_idle);
}
int HardwareComposer::OnNewGlobalBuffer(DvrGlobalBufferKey key,
@@ -481,9 +535,9 @@
int HardwareComposer::MapConfigBuffer(IonBuffer& ion_buffer) {
std::lock_guard<std::mutex> lock(shared_config_mutex_);
- shared_config_ring_ = DvrVrFlingerConfigRing();
+ shared_config_ring_ = DvrConfigRing();
- if (ion_buffer.width() < DvrVrFlingerConfigRing::MemorySize()) {
+ if (ion_buffer.width() < DvrConfigRing::MemorySize()) {
ALOGE("HardwareComposer::MapConfigBuffer: invalid buffer size.");
return -EINVAL;
}
@@ -492,13 +546,13 @@
int result = ion_buffer.Lock(ion_buffer.usage(), 0, 0, ion_buffer.width(),
ion_buffer.height(), &buffer_base);
if (result != 0) {
- ALOGE("HardwareComposer::MapConfigBuffer: Failed to map vrflinger config "
- "buffer.");
+ ALOGE(
+ "HardwareComposer::MapConfigBuffer: Failed to map vrflinger config "
+ "buffer.");
return -EPERM;
}
- shared_config_ring_ =
- DvrVrFlingerConfigRing::Create(buffer_base, ion_buffer.width());
+ shared_config_ring_ = DvrConfigRing::Create(buffer_base, ion_buffer.width());
ion_buffer.Unlock();
return 0;
@@ -506,7 +560,7 @@
void HardwareComposer::ConfigBufferDeleted() {
std::lock_guard<std::mutex> lock(shared_config_mutex_);
- shared_config_ring_ = DvrVrFlingerConfigRing();
+ shared_config_ring_ = DvrConfigRing();
}
void HardwareComposer::UpdateConfigBuffer() {
@@ -514,14 +568,17 @@
if (!shared_config_ring_.is_valid())
return;
// Copy from latest record in shared_config_ring_ to local copy.
- DvrVrFlingerConfig record;
+ DvrConfig record;
if (shared_config_ring_.GetNewest(&shared_config_ring_sequence_, &record)) {
+ ALOGI("DvrConfig updated: sequence %u, post offset %d",
+ shared_config_ring_sequence_, record.frame_post_offset_ns);
+ ++shared_config_ring_sequence_;
post_thread_config_ = record;
}
}
int HardwareComposer::PostThreadPollInterruptible(
- const pdx::LocalHandle& event_fd, int requested_events) {
+ const pdx::LocalHandle& event_fd, int requested_events, int timeout_ms) {
pollfd pfd[2] = {
{
.fd = event_fd.Get(),
@@ -536,7 +593,7 @@
};
int ret, error;
do {
- ret = poll(pfd, 2, -1);
+ ret = poll(pfd, 2, timeout_ms);
error = errno;
ALOGW_IF(ret < 0,
"HardwareComposer::PostThreadPollInterruptible: Error during "
@@ -546,167 +603,40 @@
if (ret < 0) {
return -error;
+ } else if (ret == 0) {
+ return -ETIMEDOUT;
} else if (pfd[0].revents != 0) {
return 0;
} else if (pfd[1].revents != 0) {
- ALOGI("VrHwcPost thread interrupted");
+ ALOGI("VrHwcPost thread interrupted: revents=%x", pfd[1].revents);
return kPostThreadInterrupted;
} else {
return 0;
}
}
-// Reads the value of the display driver wait_pingpong state. Returns 0 or 1
-// (the value of the state) on success or a negative error otherwise.
-// TODO(eieio): This is pretty driver specific, this should be moved to a
-// separate class eventually.
-int HardwareComposer::ReadWaitPPState() {
- // Gracefully handle when the kernel does not support this feature.
- if (!primary_display_wait_pp_fd_)
- return 0;
-
- const int wait_pp_fd = primary_display_wait_pp_fd_.Get();
- int ret, error;
-
- ret = lseek(wait_pp_fd, 0, SEEK_SET);
- if (ret < 0) {
- error = errno;
- ALOGE("HardwareComposer::ReadWaitPPState: Failed to seek wait_pp fd: %s",
- strerror(error));
- return -error;
- }
-
- char data = -1;
- ret = read(wait_pp_fd, &data, sizeof(data));
- if (ret < 0) {
- error = errno;
- ALOGE("HardwareComposer::ReadWaitPPState: Failed to read wait_pp state: %s",
- strerror(error));
- return -error;
- }
-
- switch (data) {
- case '0':
- return 0;
- case '1':
- return 1;
- default:
- ALOGE(
- "HardwareComposer::ReadWaitPPState: Unexpected value for wait_pp: %d",
- data);
- return -EINVAL;
- }
-}
-
-// Reads the timestamp of the last vsync from the display driver.
-// TODO(eieio): This is pretty driver specific, this should be moved to a
-// separate class eventually.
-int HardwareComposer::ReadVSyncTimestamp(int64_t* timestamp) {
- const int event_fd = primary_display_vsync_event_fd_.Get();
- int ret, error;
-
- // The driver returns data in the form "VSYNC=<timestamp ns>".
- std::array<char, 32> data;
- data.fill('\0');
-
- // Seek back to the beginning of the event file.
- ret = lseek(event_fd, 0, SEEK_SET);
- if (ret < 0) {
- error = errno;
- ALOGE(
- "HardwareComposer::ReadVSyncTimestamp: Failed to seek vsync event fd: "
- "%s",
- strerror(error));
- return -error;
- }
-
- // Read the vsync event timestamp.
- ret = read(event_fd, data.data(), data.size());
- if (ret < 0) {
- error = errno;
- ALOGE_IF(
- error != EAGAIN,
- "HardwareComposer::ReadVSyncTimestamp: Error while reading timestamp: "
- "%s",
- strerror(error));
- return -error;
- }
-
- ret = sscanf(data.data(), "VSYNC=%" PRIu64,
- reinterpret_cast<uint64_t*>(timestamp));
- if (ret < 0) {
- error = errno;
- ALOGE(
- "HardwareComposer::ReadVSyncTimestamp: Error while parsing timestamp: "
- "%s",
- strerror(error));
- return -error;
- }
-
- return 0;
-}
-
-// Blocks until the next vsync event is signaled by the display driver.
-// TODO(eieio): This is pretty driver specific, this should be moved to a
-// separate class eventually.
-int HardwareComposer::BlockUntilVSync() {
- // Vsync is signaled by POLLPRI on the fb vsync node.
- return PostThreadPollInterruptible(primary_display_vsync_event_fd_, POLLPRI);
+Status<int64_t> HardwareComposer::GetVSyncTime() {
+ auto status = composer_callback_->GetVsyncTime(HWC_DISPLAY_PRIMARY);
+ ALOGE_IF(!status,
+ "HardwareComposer::GetVSyncTime: Failed to get vsync timestamp: %s",
+ status.GetErrorMessage().c_str());
+ return status;
}
// Waits for the next vsync and returns the timestamp of the vsync event. If
// vsync already passed since the last call, returns the latest vsync timestamp
-// instead of blocking. This method updates the last_vsync_timeout_ in the
-// process.
-//
-// TODO(eieio): This is pretty driver specific, this should be moved to a
-// separate class eventually.
-int HardwareComposer::WaitForVSync(int64_t* timestamp) {
- int error;
-
- // Get the current timestamp and decide what to do.
- while (true) {
- int64_t current_vsync_timestamp;
- error = ReadVSyncTimestamp(¤t_vsync_timestamp);
- if (error < 0 && error != -EAGAIN)
- return error;
-
- if (error == -EAGAIN) {
- // Vsync was turned off, wait for the next vsync event.
- error = BlockUntilVSync();
- if (error < 0 || error == kPostThreadInterrupted)
- return error;
-
- // Try again to get the timestamp for this new vsync interval.
- continue;
- }
-
- // Check that we advanced to a later vsync interval.
- if (TimestampGT(current_vsync_timestamp, last_vsync_timestamp_)) {
- *timestamp = last_vsync_timestamp_ = current_vsync_timestamp;
- return 0;
- }
-
- // See how close we are to the next expected vsync. If we're within 1ms,
- // sleep for 1ms and try again.
- const int64_t ns_per_frame = display_metrics_.vsync_period_ns;
- const int64_t threshold_ns = 1000000; // 1ms
-
- const int64_t next_vsync_est = last_vsync_timestamp_ + ns_per_frame;
- const int64_t distance_to_vsync_est = next_vsync_est - GetSystemClockNs();
-
- if (distance_to_vsync_est > threshold_ns) {
- // Wait for vsync event notification.
- error = BlockUntilVSync();
- if (error < 0 || error == kPostThreadInterrupted)
- return error;
- } else {
- // Sleep for a short time (1 millisecond) before retrying.
- error = SleepUntil(GetSystemClockNs() + threshold_ns);
- if (error < 0 || error == kPostThreadInterrupted)
- return error;
- }
+// instead of blocking.
+Status<int64_t> HardwareComposer::WaitForVSync() {
+ const int64_t predicted_vsync_time =
+ last_vsync_timestamp_ +
+ display_metrics_.vsync_period_ns * vsync_prediction_interval_;
+ const int error = SleepUntil(predicted_vsync_time);
+ if (error < 0) {
+ ALOGE("HardwareComposer::WaifForVSync:: Failed to sleep: %s",
+ strerror(-error));
+ return error;
}
+ return {predicted_vsync_time};
}
int HardwareComposer::SleepUntil(int64_t wakeup_timestamp) {
@@ -724,7 +654,8 @@
return -error;
}
- return PostThreadPollInterruptible(vsync_sleep_timer_fd_, POLLIN);
+ return PostThreadPollInterruptible(vsync_sleep_timer_fd_, POLLIN,
+ /*timeout_ms*/ -1);
}
void HardwareComposer::PostThread() {
@@ -747,24 +678,6 @@
strerror(errno));
#endif // ENABLE_BACKLIGHT_BRIGHTNESS
- // Open the vsync event node for the primary display.
- // TODO(eieio): Move this into a platform-specific class.
- primary_display_vsync_event_fd_ =
- LocalHandle(kPrimaryDisplayVSyncEventFile, O_RDONLY);
- ALOGE_IF(!primary_display_vsync_event_fd_,
- "HardwareComposer: Failed to open vsync event node for primary "
- "display: %s",
- strerror(errno));
-
- // Open the wait pingpong status node for the primary display.
- // TODO(eieio): Move this into a platform-specific class.
- primary_display_wait_pp_fd_ =
- LocalHandle(kPrimaryDisplayWaitPPEventFile, O_RDONLY);
- ALOGW_IF(
- !primary_display_wait_pp_fd_,
- "HardwareComposer: Failed to open wait_pp node for primary display: %s",
- strerror(errno));
-
// Create a timerfd based on CLOCK_MONOTINIC.
vsync_sleep_timer_fd_.Reset(timerfd_create(CLOCK_MONOTONIC, 0));
LOG_ALWAYS_FATAL_IF(
@@ -796,8 +709,9 @@
std::unique_lock<std::mutex> lock(post_thread_mutex_);
ALOGI("HardwareComposer::PostThread: Entering quiescent state.");
- // Tear down resources.
- OnPostThreadPaused();
+ // Tear down resources if necessary.
+ if (was_running)
+ OnPostThreadPaused();
was_running = false;
post_thread_resumed_ = false;
@@ -828,26 +742,41 @@
thread_policy_setup =
SetThreadPolicy("graphics:high", "/system/performance");
}
+
+ // Initialize the last vsync timestamp with the current time. The
+ // predictor below uses this time + the vsync interval in absolute time
+ // units for the initial delay. Once the driver starts reporting vsync the
+ // predictor will sync up with the real vsync.
+ last_vsync_timestamp_ = GetSystemClockNs();
}
int64_t vsync_timestamp = 0;
{
- std::array<char, 128> buf;
- snprintf(buf.data(), buf.size(), "wait_vsync|vsync=%d|",
- vsync_count_ + 1);
- ATRACE_NAME(buf.data());
+ TRACE_FORMAT("wait_vsync|vsync=%u;last_timestamp=%" PRId64
+ ";prediction_interval=%d|",
+ vsync_count_ + 1, last_vsync_timestamp_,
+ vsync_prediction_interval_);
- const int error = WaitForVSync(&vsync_timestamp);
+ auto status = WaitForVSync();
ALOGE_IF(
- error < 0,
+ !status,
"HardwareComposer::PostThread: Failed to wait for vsync event: %s",
- strerror(-error));
- // Don't bother processing this frame if a pause was requested
- if (error == kPostThreadInterrupted)
+ status.GetErrorMessage().c_str());
+
+ // If there was an error either sleeping was interrupted due to pausing or
+ // there was an error getting the latest timestamp.
+ if (!status)
continue;
+
+ // Predicted vsync timestamp for this interval. This is stable because we
+ // use absolute time for the wakeup timer.
+ vsync_timestamp = status.get();
}
- ++vsync_count_;
+ // Advance the vsync counter only if the system is keeping up with hardware
+ // vsync to give clients an indication of the delays.
+ if (vsync_prediction_interval_ == 1)
+ ++vsync_count_;
const bool layer_config_changed = UpdateLayerConfig();
@@ -897,6 +826,38 @@
}
}
+ {
+ auto status = GetVSyncTime();
+ if (!status) {
+ ALOGE("HardwareComposer::PostThread: Failed to get VSYNC time: %s",
+ status.GetErrorMessage().c_str());
+ }
+
+ // If we failed to read vsync there might be a problem with the driver.
+ // Since there's nothing we can do just behave as though we didn't get an
+ // updated vsync time and let the prediction continue.
+ const int64_t current_vsync_timestamp =
+ status ? status.get() : last_vsync_timestamp_;
+
+ const bool vsync_delayed =
+ last_vsync_timestamp_ == current_vsync_timestamp;
+ ATRACE_INT("vsync_delayed", vsync_delayed);
+
+ // If vsync was delayed advance the prediction interval and allow the
+ // fence logic in PostLayers() to skip the frame.
+ if (vsync_delayed) {
+ ALOGW(
+ "HardwareComposer::PostThread: VSYNC timestamp did not advance "
+ "since last frame: timestamp=%" PRId64 " prediction_interval=%d",
+ current_vsync_timestamp, vsync_prediction_interval_);
+ vsync_prediction_interval_++;
+ } else {
+ // We have an updated vsync timestamp, reset the prediction interval.
+ last_vsync_timestamp_ = current_vsync_timestamp;
+ vsync_prediction_interval_ = 1;
+ }
+ }
+
PostLayers();
}
}
@@ -915,37 +876,60 @@
ATRACE_NAME("UpdateLayerConfig_HwLayers");
- display_surfaces_.clear();
+ // Sort the new direct surface list by z-order to determine the relative order
+ // of the surfaces. This relative order is used for the HWC z-order value to
+ // insulate VrFlinger and HWC z-order semantics from each other.
+ std::sort(surfaces.begin(), surfaces.end(), [](const auto& a, const auto& b) {
+ return a->z_order() < b->z_order();
+ });
- Layer* target_layer;
- size_t layer_index;
- for (layer_index = 0;
- layer_index < std::min(surfaces.size(), kMaxHardwareLayers);
- layer_index++) {
+ // Prepare a new layer stack, pulling in layers from the previous
+ // layer stack that are still active and updating their attributes.
+ std::vector<Layer> layers;
+ size_t layer_index = 0;
+ for (const auto& surface : surfaces) {
// The bottom layer is opaque, other layers blend.
HWC::BlendMode blending =
layer_index == 0 ? HWC::BlendMode::None : HWC::BlendMode::Coverage;
- layers_[layer_index].Setup(surfaces[layer_index], blending,
- display_transform_, HWC::Composition::Device,
- layer_index);
- display_surfaces_.push_back(surfaces[layer_index]);
+
+ // Try to find a layer for this surface in the set of active layers.
+ auto search =
+ std::lower_bound(layers_.begin(), layers_.end(), surface->surface_id());
+ const bool found = search != layers_.end() &&
+ search->GetSurfaceId() == surface->surface_id();
+ if (found) {
+ // Update the attributes of the layer that may have changed.
+ search->SetBlending(blending);
+ search->SetZOrder(layer_index); // Relative z-order.
+
+ // Move the existing layer to the new layer set and remove the empty layer
+ // object from the current set.
+ layers.push_back(std::move(*search));
+ layers_.erase(search);
+ } else {
+ // Insert a layer for the new surface.
+ layers.emplace_back(surface, blending, display_transform_,
+ HWC::Composition::Device, layer_index);
+ }
+
+ ALOGI_IF(
+ TRACE,
+ "HardwareComposer::UpdateLayerConfig: layer_index=%zu surface_id=%d",
+ layer_index, layers[layer_index].GetSurfaceId());
+
+ layer_index++;
}
- // Clear unused layers.
- for (size_t i = layer_index; i < kMaxHardwareLayers; i++)
- layers_[i].Reset();
+ // Sort the new layer stack by ascending surface id.
+ std::sort(layers.begin(), layers.end());
- active_layer_count_ = layer_index;
+ // Replace the previous layer set with the new layer set. The destructor of
+ // the previous set will clean up the remaining Layers that are not moved to
+ // the new layer set.
+ layers_ = std::move(layers);
+
ALOGD_IF(TRACE, "HardwareComposer::UpdateLayerConfig: %zd active layers",
- active_layer_count_);
-
- // Any surfaces left over could not be assigned a hardware layer and will
- // not be displayed.
- ALOGW_IF(surfaces.size() != display_surfaces_.size(),
- "HardwareComposer::UpdateLayerConfig: More surfaces than layers: "
- "pending_surfaces=%zu display_surfaces=%zu",
- surfaces.size(), display_surfaces_.size());
-
+ layers_.size());
return true;
}
@@ -953,30 +937,6 @@
vsync_callback_ = callback;
}
-void HardwareComposer::HwcRefresh(hwc2_callback_data_t /*data*/,
- hwc2_display_t /*display*/) {
- // TODO(eieio): implement invalidate callbacks.
-}
-
-void HardwareComposer::HwcVSync(hwc2_callback_data_t /*data*/,
- hwc2_display_t /*display*/,
- int64_t /*timestamp*/) {
- ATRACE_NAME(__PRETTY_FUNCTION__);
- // Intentionally empty. HWC may require a callback to be set to enable vsync
- // signals. We bypass this callback thread by monitoring the vsync event
- // directly, but signals still need to be enabled.
-}
-
-void HardwareComposer::HwcHotplug(hwc2_callback_data_t /*callbackData*/,
- hwc2_display_t /*display*/,
- hwc2_connection_t /*connected*/) {
- // TODO(eieio): implement display hotplug callbacks.
-}
-
-void HardwareComposer::OnHardwareComposerRefresh() {
- // TODO(steventhomas): Handle refresh.
-}
-
void HardwareComposer::SetBacklightBrightness(int brightness) {
if (backlight_brightness_fd_) {
std::array<char, 32> text;
@@ -985,15 +945,121 @@
}
}
-void Layer::InitializeGlobals(Hwc2::Composer* hwc2_hidl,
- const HWCDisplayMetrics* metrics) {
- hwc2_hidl_ = hwc2_hidl;
- display_metrics_ = metrics;
+Return<void> HardwareComposer::ComposerCallback::onHotplug(
+ Hwc2::Display display, IComposerCallback::Connection /*conn*/) {
+ // See if the driver supports the vsync_event node in sysfs.
+ if (display < HWC_NUM_PHYSICAL_DISPLAY_TYPES &&
+ !displays_[display].driver_vsync_event_fd) {
+ std::array<char, 1024> buffer;
+ snprintf(buffer.data(), buffer.size(),
+ "/sys/class/graphics/fb%" PRIu64 "/vsync_event", display);
+ if (LocalHandle handle{buffer.data(), O_RDONLY}) {
+ ALOGI(
+ "HardwareComposer::ComposerCallback::onHotplug: Driver supports "
+ "vsync_event node for display %" PRIu64,
+ display);
+ displays_[display].driver_vsync_event_fd = std::move(handle);
+ } else {
+ ALOGI(
+ "HardwareComposer::ComposerCallback::onHotplug: Driver does not "
+ "support vsync_event node for display %" PRIu64,
+ display);
+ }
+ }
+
+ return Void();
}
+Return<void> HardwareComposer::ComposerCallback::onRefresh(
+ Hwc2::Display /*display*/) {
+ return hardware::Void();
+}
+
+Return<void> HardwareComposer::ComposerCallback::onVsync(Hwc2::Display display,
+ int64_t timestamp) {
+ TRACE_FORMAT("vsync_callback|display=%" PRIu64 ";timestamp=%" PRId64 "|",
+ display, timestamp);
+ if (display < HWC_NUM_PHYSICAL_DISPLAY_TYPES) {
+ displays_[display].callback_vsync_timestamp = timestamp;
+ } else {
+ ALOGW(
+ "HardwareComposer::ComposerCallback::onVsync: Received vsync on "
+ "non-physical display: display=%" PRId64,
+ display);
+ }
+ return Void();
+}
+
+Status<int64_t> HardwareComposer::ComposerCallback::GetVsyncTime(
+ Hwc2::Display display) {
+ if (display >= HWC_NUM_PHYSICAL_DISPLAY_TYPES) {
+ ALOGE(
+ "HardwareComposer::ComposerCallback::GetVsyncTime: Invalid physical "
+ "display requested: display=%" PRIu64,
+ display);
+ return ErrorStatus(EINVAL);
+ }
+
+ // See if the driver supports direct vsync events.
+ LocalHandle& event_fd = displays_[display].driver_vsync_event_fd;
+ if (!event_fd) {
+ // Fall back to returning the last timestamp returned by the vsync
+ // callback.
+ std::lock_guard<std::mutex> autolock(vsync_mutex_);
+ return displays_[display].callback_vsync_timestamp;
+ }
+
+ // When the driver supports the vsync_event sysfs node we can use it to
+ // determine the latest vsync timestamp, even if the HWC callback has been
+ // delayed.
+
+ // The driver returns data in the form "VSYNC=<timestamp ns>".
+ std::array<char, 32> data;
+ data.fill('\0');
+
+ // Seek back to the beginning of the event file.
+ int ret = lseek(event_fd.Get(), 0, SEEK_SET);
+ if (ret < 0) {
+ const int error = errno;
+ ALOGE(
+ "HardwareComposer::ComposerCallback::GetVsyncTime: Failed to seek "
+ "vsync event fd: %s",
+ strerror(error));
+ return ErrorStatus(error);
+ }
+
+ // Read the vsync event timestamp.
+ ret = read(event_fd.Get(), data.data(), data.size());
+ if (ret < 0) {
+ const int error = errno;
+ ALOGE_IF(error != EAGAIN,
+ "HardwareComposer::ComposerCallback::GetVsyncTime: Error "
+ "while reading timestamp: %s",
+ strerror(error));
+ return ErrorStatus(error);
+ }
+
+ int64_t timestamp;
+ ret = sscanf(data.data(), "VSYNC=%" PRIu64,
+ reinterpret_cast<uint64_t*>(×tamp));
+ if (ret < 0) {
+ const int error = errno;
+ ALOGE(
+ "HardwareComposer::ComposerCallback::GetVsyncTime: Error while "
+ "parsing timestamp: %s",
+ strerror(error));
+ return ErrorStatus(error);
+ }
+
+ return {timestamp};
+}
+
+Hwc2::Composer* Layer::composer_{nullptr};
+HWCDisplayMetrics Layer::display_metrics_{0, 0, {0, 0}, 0};
+
void Layer::Reset() {
- if (hwc2_hidl_ != nullptr && hardware_composer_layer_) {
- hwc2_hidl_->destroyLayer(HWC_DISPLAY_PRIMARY, hardware_composer_layer_);
+ if (hardware_composer_layer_) {
+ composer_->destroyLayer(HWC_DISPLAY_PRIMARY, hardware_composer_layer_);
hardware_composer_layer_ = 0;
}
@@ -1005,41 +1071,74 @@
source_ = EmptyVariant{};
acquire_fence_.Close();
surface_rect_functions_applied_ = false;
+ pending_visibility_settings_ = true;
+ cached_buffer_map_.clear();
}
-void Layer::Setup(const std::shared_ptr<DirectDisplaySurface>& surface,
- HWC::BlendMode blending, HWC::Transform transform,
- HWC::Composition composition_type, size_t z_order) {
- Reset();
- z_order_ = z_order;
- blending_ = blending;
- transform_ = transform;
- composition_type_ = HWC::Composition::Invalid;
- target_composition_type_ = composition_type;
- source_ = SourceSurface{surface};
+Layer::Layer(const std::shared_ptr<DirectDisplaySurface>& surface,
+ HWC::BlendMode blending, HWC::Transform transform,
+ HWC::Composition composition_type, size_t z_order)
+ : z_order_{z_order},
+ blending_{blending},
+ transform_{transform},
+ target_composition_type_{composition_type},
+ source_{SourceSurface{surface}} {
CommonLayerSetup();
}
-void Layer::Setup(const std::shared_ptr<IonBuffer>& buffer,
- HWC::BlendMode blending, HWC::Transform transform,
- HWC::Composition composition_type, size_t z_order) {
- Reset();
- z_order_ = z_order;
- blending_ = blending;
- transform_ = transform;
- composition_type_ = HWC::Composition::Invalid;
- target_composition_type_ = composition_type;
- source_ = SourceBuffer{buffer};
+Layer::Layer(const std::shared_ptr<IonBuffer>& buffer, HWC::BlendMode blending,
+ HWC::Transform transform, HWC::Composition composition_type,
+ size_t z_order)
+ : z_order_{z_order},
+ blending_{blending},
+ transform_{transform},
+ target_composition_type_{composition_type},
+ source_{SourceBuffer{buffer}} {
CommonLayerSetup();
}
+Layer::~Layer() { Reset(); }
+
+Layer::Layer(Layer&& other) { *this = std::move(other); }
+
+Layer& Layer::operator=(Layer&& other) {
+ if (this != &other) {
+ Reset();
+ using std::swap;
+ swap(hardware_composer_layer_, other.hardware_composer_layer_);
+ swap(z_order_, other.z_order_);
+ swap(blending_, other.blending_);
+ swap(transform_, other.transform_);
+ swap(composition_type_, other.composition_type_);
+ swap(target_composition_type_, other.target_composition_type_);
+ swap(source_, other.source_);
+ swap(acquire_fence_, other.acquire_fence_);
+ swap(surface_rect_functions_applied_,
+ other.surface_rect_functions_applied_);
+ swap(pending_visibility_settings_, other.pending_visibility_settings_);
+ swap(cached_buffer_map_, other.cached_buffer_map_);
+ }
+ return *this;
+}
+
void Layer::UpdateBuffer(const std::shared_ptr<IonBuffer>& buffer) {
if (source_.is<SourceBuffer>())
std::get<SourceBuffer>(source_) = {buffer};
}
-void Layer::SetBlending(HWC::BlendMode blending) { blending_ = blending; }
-void Layer::SetZOrder(size_t z_order) { z_order_ = z_order; }
+void Layer::SetBlending(HWC::BlendMode blending) {
+ if (blending_ != blending) {
+ blending_ = blending;
+ pending_visibility_settings_ = true;
+ }
+}
+
+void Layer::SetZOrder(size_t z_order) {
+ if (z_order_ != z_order) {
+ z_order_ = z_order;
+ pending_visibility_settings_ = true;
+ }
+}
IonBuffer* Layer::GetBuffer() {
struct Visitor {
@@ -1050,93 +1149,108 @@
return source_.Visit(Visitor{});
}
-void Layer::UpdateLayerSettings() {
- if (!IsLayerSetup()) {
- ALOGE(
- "HardwareComposer::Layer::UpdateLayerSettings: Attempt to update "
- "unused Layer!");
- return;
- }
+void Layer::UpdateVisibilitySettings() {
+ if (pending_visibility_settings_) {
+ pending_visibility_settings_ = false;
+ HWC::Error error;
+ hwc2_display_t display = HWC_DISPLAY_PRIMARY;
+
+ error = composer_->setLayerBlendMode(
+ display, hardware_composer_layer_,
+ blending_.cast<Hwc2::IComposerClient::BlendMode>());
+ ALOGE_IF(error != HWC::Error::None,
+ "Layer::UpdateLayerSettings: Error setting layer blend mode: %s",
+ error.to_string().c_str());
+
+ error =
+ composer_->setLayerZOrder(display, hardware_composer_layer_, z_order_);
+ ALOGE_IF(error != HWC::Error::None,
+ "Layer::UpdateLayerSettings: Error setting z_ order: %s",
+ error.to_string().c_str());
+ }
+}
+
+void Layer::UpdateLayerSettings() {
HWC::Error error;
hwc2_display_t display = HWC_DISPLAY_PRIMARY;
- error = hwc2_hidl_->setLayerCompositionType(
- display, hardware_composer_layer_,
- composition_type_.cast<Hwc2::IComposerClient::Composition>());
- ALOGE_IF(
- error != HWC::Error::None,
- "Layer::UpdateLayerSettings: Error setting layer composition type: %s",
- error.to_string().c_str());
-
- error = hwc2_hidl_->setLayerBlendMode(
- display, hardware_composer_layer_,
- blending_.cast<Hwc2::IComposerClient::BlendMode>());
- ALOGE_IF(error != HWC::Error::None,
- "Layer::UpdateLayerSettings: Error setting layer blend mode: %s",
- error.to_string().c_str());
+ UpdateVisibilitySettings();
// TODO(eieio): Use surface attributes or some other mechanism to control
// the layer display frame.
- error = hwc2_hidl_->setLayerDisplayFrame(
+ error = composer_->setLayerDisplayFrame(
display, hardware_composer_layer_,
- {0, 0, display_metrics_->width, display_metrics_->height});
+ {0, 0, display_metrics_.width, display_metrics_.height});
ALOGE_IF(error != HWC::Error::None,
"Layer::UpdateLayerSettings: Error setting layer display frame: %s",
error.to_string().c_str());
- error = hwc2_hidl_->setLayerVisibleRegion(
+ error = composer_->setLayerVisibleRegion(
display, hardware_composer_layer_,
- {{0, 0, display_metrics_->width, display_metrics_->height}});
+ {{0, 0, display_metrics_.width, display_metrics_.height}});
ALOGE_IF(error != HWC::Error::None,
"Layer::UpdateLayerSettings: Error setting layer visible region: %s",
error.to_string().c_str());
error =
- hwc2_hidl_->setLayerPlaneAlpha(display, hardware_composer_layer_, 1.0f);
+ composer_->setLayerPlaneAlpha(display, hardware_composer_layer_, 1.0f);
ALOGE_IF(error != HWC::Error::None,
"Layer::UpdateLayerSettings: Error setting layer plane alpha: %s",
error.to_string().c_str());
-
- error =
- hwc2_hidl_->setLayerZOrder(display, hardware_composer_layer_, z_order_);
- ALOGE_IF(error != HWC::Error::None,
- "Layer::UpdateLayerSettings: Error setting z_ order: %s",
- error.to_string().c_str());
}
void Layer::CommonLayerSetup() {
HWC::Error error =
- hwc2_hidl_->createLayer(HWC_DISPLAY_PRIMARY, &hardware_composer_layer_);
- ALOGE_IF(
- error != HWC::Error::None,
- "Layer::CommonLayerSetup: Failed to create layer on primary display: %s",
- error.to_string().c_str());
+ composer_->createLayer(HWC_DISPLAY_PRIMARY, &hardware_composer_layer_);
+ ALOGE_IF(error != HWC::Error::None,
+ "Layer::CommonLayerSetup: Failed to create layer on primary "
+ "display: %s",
+ error.to_string().c_str());
UpdateLayerSettings();
}
+bool Layer::CheckAndUpdateCachedBuffer(std::size_t slot, int buffer_id) {
+ auto search = cached_buffer_map_.find(slot);
+ if (search != cached_buffer_map_.end() && search->second == buffer_id)
+ return true;
+
+ // Assign or update the buffer slot.
+ if (buffer_id >= 0)
+ cached_buffer_map_[slot] = buffer_id;
+ return false;
+}
+
void Layer::Prepare() {
- int right, bottom;
+ int right, bottom, id;
sp<GraphicBuffer> handle;
+ std::size_t slot;
// Acquire the next buffer according to the type of source.
IfAnyOf<SourceSurface, SourceBuffer>::Call(&source_, [&](auto& source) {
- std::tie(right, bottom, handle, acquire_fence_) = source.Acquire();
+ std::tie(right, bottom, id, handle, acquire_fence_, slot) =
+ source.Acquire();
});
- // When a layer is first setup there may be some time before the first buffer
- // arrives. Setup the HWC layer as a solid color to stall for time until the
- // first buffer arrives. Once the first buffer arrives there will always be a
- // buffer for the frame even if it is old.
+ TRACE_FORMAT("Layer::Prepare|buffer_id=%d;slot=%zu|", id, slot);
+
+ // Update any visibility (blending, z-order) changes that occurred since
+ // last prepare.
+ UpdateVisibilitySettings();
+
+ // When a layer is first setup there may be some time before the first
+ // buffer arrives. Setup the HWC layer as a solid color to stall for time
+ // until the first buffer arrives. Once the first buffer arrives there will
+ // always be a buffer for the frame even if it is old.
if (!handle.get()) {
if (composition_type_ == HWC::Composition::Invalid) {
composition_type_ = HWC::Composition::SolidColor;
- hwc2_hidl_->setLayerCompositionType(
+ composer_->setLayerCompositionType(
HWC_DISPLAY_PRIMARY, hardware_composer_layer_,
composition_type_.cast<Hwc2::IComposerClient::Composition>());
Hwc2::IComposerClient::Color layer_color = {0, 0, 0, 0};
- hwc2_hidl_->setLayerColor(HWC_DISPLAY_PRIMARY, hardware_composer_layer_,
- layer_color);
+ composer_->setLayerColor(HWC_DISPLAY_PRIMARY, hardware_composer_layer_,
+ layer_color);
} else {
// The composition type is already set. Nothing else to do until a
// buffer arrives.
@@ -1144,15 +1258,20 @@
} else {
if (composition_type_ != target_composition_type_) {
composition_type_ = target_composition_type_;
- hwc2_hidl_->setLayerCompositionType(
+ composer_->setLayerCompositionType(
HWC_DISPLAY_PRIMARY, hardware_composer_layer_,
composition_type_.cast<Hwc2::IComposerClient::Composition>());
}
+ // See if the HWC cache already has this buffer.
+ const bool cached = CheckAndUpdateCachedBuffer(slot, id);
+ if (cached)
+ handle = nullptr;
+
HWC::Error error{HWC::Error::None};
- error = hwc2_hidl_->setLayerBuffer(HWC_DISPLAY_PRIMARY,
- hardware_composer_layer_, 0, handle,
- acquire_fence_.Get());
+ error =
+ composer_->setLayerBuffer(HWC_DISPLAY_PRIMARY, hardware_composer_layer_,
+ slot, handle, acquire_fence_.Get());
ALOGE_IF(error != HWC::Error::None,
"Layer::Prepare: Error setting layer buffer: %s",
@@ -1161,9 +1280,9 @@
if (!surface_rect_functions_applied_) {
const float float_right = right;
const float float_bottom = bottom;
- error = hwc2_hidl_->setLayerSourceCrop(HWC_DISPLAY_PRIMARY,
- hardware_composer_layer_,
- {0, 0, float_right, float_bottom});
+ error = composer_->setLayerSourceCrop(HWC_DISPLAY_PRIMARY,
+ hardware_composer_layer_,
+ {0, 0, float_right, float_bottom});
ALOGE_IF(error != HWC::Error::None,
"Layer::Prepare: Error setting layer source crop: %s",
diff --git a/libs/vr/libvrflinger/hardware_composer.h b/libs/vr/libvrflinger/hardware_composer.h
index de6f9ff..7010db9 100644
--- a/libs/vr/libvrflinger/hardware_composer.h
+++ b/libs/vr/libvrflinger/hardware_composer.h
@@ -17,7 +17,7 @@
#include <tuple>
#include <vector>
-#include <dvr/dvr_vrflinger_config.h>
+#include <dvr/dvr_config.h>
#include <dvr/dvr_vsync.h>
#include <pdx/file_handle.h>
#include <pdx/rpc/variant.h>
@@ -52,15 +52,7 @@
// source supplying buffers for the layer's contents.
class Layer {
public:
- Layer() {}
-
- // Sets up the global state used by all Layer instances. This must be called
- // before using any Layer methods.
- static void InitializeGlobals(Hwc2::Composer* hwc2_hidl,
- const HWCDisplayMetrics* metrics);
-
- // Releases any shared pointers and fence handles held by this instance.
- void Reset();
+ Layer() = default;
// Sets up the layer to use a display surface as its content source. The Layer
// automatically handles ACQUIRE/RELEASE phases for the surface's buffer train
@@ -71,9 +63,9 @@
// |composition_type| receives either HWC_FRAMEBUFFER for most layers or
// HWC_FRAMEBUFFER_TARGET (unless you know what you are doing).
// |index| is the index of this surface in the DirectDisplaySurface array.
- void Setup(const std::shared_ptr<DirectDisplaySurface>& surface,
- HWC::BlendMode blending, HWC::Transform transform,
- HWC::Composition composition_type, size_t z_roder);
+ Layer(const std::shared_ptr<DirectDisplaySurface>& surface,
+ HWC::BlendMode blending, HWC::Transform transform,
+ HWC::Composition composition_type, size_t z_roder);
// Sets up the layer to use a direct buffer as its content source. No special
// handling of the buffer is performed; responsibility for updating or
@@ -83,9 +75,17 @@
// |transform| receives HWC_TRANSFORM_* values.
// |composition_type| receives either HWC_FRAMEBUFFER for most layers or
// HWC_FRAMEBUFFER_TARGET (unless you know what you are doing).
- void Setup(const std::shared_ptr<IonBuffer>& buffer, HWC::BlendMode blending,
- HWC::Transform transform, HWC::Composition composition_type,
- size_t z_order);
+ Layer(const std::shared_ptr<IonBuffer>& buffer, HWC::BlendMode blending,
+ HWC::Transform transform, HWC::Composition composition_type,
+ size_t z_order);
+
+ Layer(Layer&&);
+ Layer& operator=(Layer&&);
+
+ ~Layer();
+
+ // Releases any shared pointers and fence handles held by this instance.
+ void Reset();
// Layers that use a direct IonBuffer should call this each frame to update
// which buffer will be used for the next PostLayers.
@@ -120,23 +120,65 @@
HWC::Layer GetLayerHandle() const { return hardware_composer_layer_; }
bool IsLayerSetup() const { return !source_.empty(); }
- // Applies all of the settings to this layer using the hwc functions
- void UpdateLayerSettings();
-
int GetSurfaceId() const {
int surface_id = -1;
pdx::rpc::IfAnyOf<SourceSurface>::Call(
&source_, [&surface_id](const SourceSurface& surface_source) {
- surface_id = surface_source.surface->surface_id();
+ surface_id = surface_source.GetSurfaceId();
});
return surface_id;
}
+ int GetBufferId() const {
+ int buffer_id = -1;
+ pdx::rpc::IfAnyOf<SourceSurface>::Call(
+ &source_, [&buffer_id](const SourceSurface& surface_source) {
+ buffer_id = surface_source.GetBufferId();
+ });
+ return buffer_id;
+ }
+
+ // Compares Layers by surface id.
+ bool operator<(const Layer& other) const {
+ return GetSurfaceId() < other.GetSurfaceId();
+ }
+ bool operator<(int surface_id) const { return GetSurfaceId() < surface_id; }
+
+ // Sets the composer instance used by all Layer instances.
+ static void SetComposer(Hwc2::Composer* composer) { composer_ = composer; }
+
+ // Sets the display metrics used by all Layer instances.
+ static void SetDisplayMetrics(HWCDisplayMetrics display_metrics) {
+ display_metrics_ = display_metrics;
+ }
+
private:
void CommonLayerSetup();
- static Hwc2::Composer* hwc2_hidl_;
- static const HWCDisplayMetrics* display_metrics_;
+ // Applies all of the settings to this layer using the hwc functions
+ void UpdateLayerSettings();
+
+ // Applies visibility settings that may have changed.
+ void UpdateVisibilitySettings();
+
+ // Checks whether the buffer, given by id, is associated with the given slot
+ // in the HWC buffer cache. If the slot is not associated with the given
+ // buffer the cache is updated to establish the association and the buffer
+ // should be sent to HWC using setLayerBuffer. Returns true if the association
+ // was already established, false if not. A buffer_id of -1 is never
+ // associated and always returns false.
+ bool CheckAndUpdateCachedBuffer(std::size_t slot, int buffer_id);
+
+ // Composer instance shared by all instances of Layer. This must be set
+ // whenever a new instance of the Composer is created. This may be set to
+ // nullptr as long as there are no instances of Layer that might need to use
+ // it.
+ static Hwc2::Composer* composer_;
+
+ // Display metrics shared by all instances of Layer. This must be set at least
+ // once during VrFlinger initialization and is expected to remain constant
+ // thereafter.
+ static HWCDisplayMetrics display_metrics_;
// The hardware composer layer and metrics to use during the prepare cycle.
hwc2_layer_t hardware_composer_layer_ = 0;
@@ -164,19 +206,21 @@
// the previous buffer is returned or an empty value if no buffer has ever
// been posted. When a new buffer is acquired the previous buffer's release
// fence is passed out automatically.
- std::tuple<int, int, sp<GraphicBuffer>, pdx::LocalHandle> Acquire() {
+ std::tuple<int, int, int, sp<GraphicBuffer>, pdx::LocalHandle, std::size_t>
+ Acquire() {
if (surface->IsBufferAvailable()) {
acquired_buffer.Release(std::move(release_fence));
acquired_buffer = surface->AcquireCurrentBuffer();
ATRACE_ASYNC_END("BufferPost", acquired_buffer.buffer()->id());
}
if (!acquired_buffer.IsEmpty()) {
- return std::make_tuple(acquired_buffer.buffer()->width(),
- acquired_buffer.buffer()->height(),
- acquired_buffer.buffer()->buffer()->buffer(),
- acquired_buffer.ClaimAcquireFence());
+ return std::make_tuple(
+ acquired_buffer.buffer()->width(),
+ acquired_buffer.buffer()->height(), acquired_buffer.buffer()->id(),
+ acquired_buffer.buffer()->buffer()->buffer(),
+ acquired_buffer.ClaimAcquireFence(), acquired_buffer.slot());
} else {
- return std::make_tuple(0, 0, nullptr, pdx::LocalHandle{});
+ return std::make_tuple(0, 0, -1, nullptr, pdx::LocalHandle{}, 0);
}
}
@@ -192,7 +236,15 @@
}
// Returns the surface id of the surface.
- int GetSurfaceId() { return surface->surface_id(); }
+ int GetSurfaceId() const { return surface->surface_id(); }
+
+ // Returns the buffer id for the current buffer.
+ int GetBufferId() const {
+ if (acquired_buffer.IsAvailable())
+ return acquired_buffer.buffer()->id();
+ else
+ return -1;
+ }
};
// State when the layer is connected to a buffer. Provides the same interface
@@ -200,12 +252,13 @@
struct SourceBuffer {
std::shared_ptr<IonBuffer> buffer;
- std::tuple<int, int, sp<GraphicBuffer>, pdx::LocalHandle> Acquire() {
+ std::tuple<int, int, int, sp<GraphicBuffer>, pdx::LocalHandle, std::size_t>
+ Acquire() {
if (buffer)
- return std::make_tuple(buffer->width(), buffer->height(),
- buffer->buffer(), pdx::LocalHandle{});
+ return std::make_tuple(buffer->width(), buffer->height(), -1,
+ buffer->buffer(), pdx::LocalHandle{}, 0);
else
- return std::make_tuple(0, 0, nullptr, pdx::LocalHandle{});
+ return std::make_tuple(0, 0, -1, nullptr, pdx::LocalHandle{}, 0);
}
void Finish(pdx::LocalHandle /*fence*/) {}
@@ -213,6 +266,7 @@
IonBuffer* GetBuffer() { return buffer.get(); }
int GetSurfaceId() const { return -1; }
+ int GetBufferId() const { return -1; }
};
// The underlying hardware composer layer is supplied buffers either from a
@@ -221,6 +275,13 @@
pdx::LocalHandle acquire_fence_;
bool surface_rect_functions_applied_ = false;
+ bool pending_visibility_settings_ = true;
+
+ // Map of buffer slot assignments that have already been established with HWC:
+ // slot -> buffer_id. When this map contains a matching slot and buffer_id the
+ // buffer argument to setLayerBuffer may be nullptr to avoid the cost of
+ // importing a buffer HWC already knows about.
+ std::map<std::size_t, int> cached_buffer_map_;
Layer(const Layer&) = delete;
void operator=(const Layer&) = delete;
@@ -240,16 +301,11 @@
using VSyncCallback = std::function<void(int, int64_t, int64_t, uint32_t)>;
using RequestDisplayCallback = std::function<void(bool)>;
- // Since there is no universal way to query the number of hardware layers,
- // just set it to 4 for now.
- static constexpr size_t kMaxHardwareLayers = 4;
-
HardwareComposer();
- HardwareComposer(Hwc2::Composer* hidl,
- RequestDisplayCallback request_display_callback);
~HardwareComposer();
- bool Initialize();
+ bool Initialize(Hwc2::Composer* composer,
+ RequestDisplayCallback request_display_callback);
bool IsInitialized() const { return initialized_; }
@@ -263,11 +319,6 @@
// Get the HMD display metrics for the current display.
display::Metrics GetHmdDisplayMetrics() const;
- HWC::Error GetDisplayAttribute(hwc2_display_t display, hwc2_config_t config,
- hwc2_attribute_t attributes,
- int32_t* out_value) const;
- HWC::Error GetDisplayMetrics(hwc2_display_t display, hwc2_config_t config,
- HWCDisplayMetrics* out_metrics) const;
std::string Dump();
void SetVSyncCallback(VSyncCallback callback);
@@ -290,34 +341,37 @@
int OnNewGlobalBuffer(DvrGlobalBufferKey key, IonBuffer& ion_buffer);
void OnDeletedGlobalBuffer(DvrGlobalBufferKey key);
- void OnHardwareComposerRefresh();
-
private:
- int32_t EnableVsync(bool enabled);
+ HWC::Error GetDisplayAttribute(Hwc2::Composer* composer,
+ hwc2_display_t display, hwc2_config_t config,
+ hwc2_attribute_t attributes,
+ int32_t* out_value) const;
+ HWC::Error GetDisplayMetrics(Hwc2::Composer* composer, hwc2_display_t display,
+ hwc2_config_t config,
+ HWCDisplayMetrics* out_metrics) const;
+
+ HWC::Error EnableVsync(bool enabled);
+ HWC::Error SetPowerMode(bool active);
class ComposerCallback : public Hwc2::IComposerCallback {
public:
- ComposerCallback() {}
+ ComposerCallback() = default;
+ hardware::Return<void> onHotplug(Hwc2::Display display,
+ Connection conn) override;
+ hardware::Return<void> onRefresh(Hwc2::Display display) override;
+ hardware::Return<void> onVsync(Hwc2::Display display,
+ int64_t timestamp) override;
- hardware::Return<void> onHotplug(Hwc2::Display /*display*/,
- Connection /*connected*/) override {
- // TODO(skiazyk): depending on how the server is implemented, we might
- // have to set it up to synchronize with receiving this event, as it can
- // potentially be a critical event for setting up state within the
- // hwc2 module. That is, we (technically) should not call any other hwc
- // methods until this method has been called after registering the
- // callbacks.
- return hardware::Void();
- }
+ pdx::Status<int64_t> GetVsyncTime(Hwc2::Display display);
- hardware::Return<void> onRefresh(Hwc2::Display /*display*/) override {
- return hardware::Void();
- }
+ private:
+ std::mutex vsync_mutex_;
- hardware::Return<void> onVsync(Hwc2::Display /*display*/,
- int64_t /*timestamp*/) override {
- return hardware::Void();
- }
+ struct Display {
+ pdx::LocalHandle driver_vsync_event_fd;
+ int64_t callback_vsync_timestamp{0};
+ };
+ std::array<Display, HWC_NUM_PHYSICAL_DISPLAY_TYPES> displays_;
};
HWC::Error Validate(hwc2_display_t display);
@@ -346,22 +400,21 @@
void UpdatePostThreadState(uint32_t state, bool suspend);
// Blocks until either event_fd becomes readable, or we're interrupted by a
- // control thread. Any errors are returned as negative errno values. If we're
- // interrupted, kPostThreadInterrupted will be returned.
+ // control thread, or timeout_ms is reached before any events occur. Any
+ // errors are returned as negative errno values, with -ETIMEDOUT returned in
+ // the case of a timeout. If we're interrupted, kPostThreadInterrupted will be
+ // returned.
int PostThreadPollInterruptible(const pdx::LocalHandle& event_fd,
- int requested_events);
+ int requested_events, int timeout_ms);
- // BlockUntilVSync, WaitForVSync, and SleepUntil are all blocking calls made
- // on the post thread that can be interrupted by a control thread. If
- // interrupted, these calls return kPostThreadInterrupted.
+ // WaitForVSync and SleepUntil are blocking calls made on the post thread that
+ // can be interrupted by a control thread. If interrupted, these calls return
+ // kPostThreadInterrupted.
int ReadWaitPPState();
- int BlockUntilVSync();
- int ReadVSyncTimestamp(int64_t* timestamp);
- int WaitForVSync(int64_t* timestamp);
+ pdx::Status<int64_t> WaitForVSync();
+ pdx::Status<int64_t> GetVSyncTime();
int SleepUntil(int64_t wakeup_timestamp);
- bool IsFramePendingInDriver() { return ReadWaitPPState() == 1; }
-
// Reconfigures the layer stack if the display surfaces changed since the last
// frame. Called only from the post thread.
bool UpdateLayerConfig();
@@ -379,12 +432,11 @@
void UpdateConfigBuffer();
bool initialized_;
+ bool is_standalone_device_;
- // Hardware composer HAL device from SurfaceFlinger. VrFlinger does not own
- // this pointer.
- Hwc2::Composer* hwc2_hidl_;
+ std::unique_ptr<Hwc2::Composer> composer_;
+ sp<ComposerCallback> composer_callback_;
RequestDisplayCallback request_display_callback_;
- sp<ComposerCallback> callbacks_;
// Display metrics of the physical display.
HWCDisplayMetrics native_display_metrics_;
@@ -399,13 +451,9 @@
// thread and read by the post thread.
std::vector<std::shared_ptr<DirectDisplaySurface>> pending_surfaces_;
- // The surfaces displayed by the post thread. Used exclusively by the post
- // thread.
- std::vector<std::shared_ptr<DirectDisplaySurface>> display_surfaces_;
-
- // Layer array for handling buffer flow into hardware composer layers.
- std::array<Layer, kMaxHardwareLayers> layers_;
- size_t active_layer_count_ = 0;
+ // Layer set for handling buffer flow into hardware composer layers. This
+ // vector must be sorted by surface_id in ascending order.
+ std::vector<Layer> layers_;
// Handler to hook vsync events outside of this class.
VSyncCallback vsync_callback_;
@@ -415,7 +463,8 @@
std::thread post_thread_;
// Post thread state machine and synchronization primitives.
- PostThreadStateType post_thread_state_{PostThreadState::Idle};
+ PostThreadStateType post_thread_state_{PostThreadState::Idle |
+ PostThreadState::Suspended};
std::atomic<bool> post_thread_quiescent_{true};
bool post_thread_resumed_{false};
pdx::LocalHandle post_thread_event_fd_;
@@ -426,18 +475,15 @@
// Backlight LED brightness sysfs node.
pdx::LocalHandle backlight_brightness_fd_;
- // Primary display vsync event sysfs node.
- pdx::LocalHandle primary_display_vsync_event_fd_;
-
- // Primary display wait_pingpong state sysfs node.
- pdx::LocalHandle primary_display_wait_pp_fd_;
-
// VSync sleep timerfd.
pdx::LocalHandle vsync_sleep_timer_fd_;
// The timestamp of the last vsync.
int64_t last_vsync_timestamp_ = 0;
+ // The number of vsync intervals to predict since the last vsync.
+ int vsync_prediction_interval_ = 1;
+
// Vsync count since display on.
uint32_t vsync_count_ = 0;
@@ -452,20 +498,14 @@
std::unique_ptr<CPUMappedBroadcastRing<DvrVsyncRing>> vsync_ring_;
// Broadcast ring for receiving config data from the DisplayManager.
- DvrVrFlingerConfigRing shared_config_ring_;
+ DvrConfigRing shared_config_ring_;
uint32_t shared_config_ring_sequence_{0};
// Config buffer for reading from the post thread.
- DvrVrFlingerConfig post_thread_config_;
+ DvrConfig post_thread_config_;
std::mutex shared_config_mutex_;
static constexpr int kPostThreadInterrupted = 1;
- static void HwcRefresh(hwc2_callback_data_t data, hwc2_display_t display);
- static void HwcVSync(hwc2_callback_data_t data, hwc2_display_t display,
- int64_t timestamp);
- static void HwcHotplug(hwc2_callback_data_t callbackData,
- hwc2_display_t display, hwc2_connection_t connected);
-
HardwareComposer(const HardwareComposer&) = delete;
void operator=(const HardwareComposer&) = delete;
};
diff --git a/libs/vr/libvrflinger/include/dvr/vr_flinger.h b/libs/vr/libvrflinger/include/dvr/vr_flinger.h
index 145852e..33cbc84 100644
--- a/libs/vr/libvrflinger/include/dvr/vr_flinger.h
+++ b/libs/vr/libvrflinger/include/dvr/vr_flinger.h
@@ -4,7 +4,7 @@
#include <thread>
#include <memory>
-#include <pdx/default_transport/service_dispatcher.h>
+#include <pdx/service_dispatcher.h>
#include <vr/vr_manager/vr_manager.h>
namespace android {
@@ -29,8 +29,8 @@
void GrantDisplayOwnership();
void SeizeDisplayOwnership();
- // Called on a binder thread.
- void OnHardwareComposerRefresh();
+ // dump all vr flinger state.
+ std::string Dump();
private:
VrFlinger();
diff --git a/libs/vr/libvrflinger/vr_flinger.cpp b/libs/vr/libvrflinger/vr_flinger.cpp
index b2dc1d8..85dc586 100644
--- a/libs/vr/libvrflinger/vr_flinger.cpp
+++ b/libs/vr/libvrflinger/vr_flinger.cpp
@@ -18,8 +18,6 @@
#include <sys/prctl.h>
#include <sys/resource.h>
-#include <pdx/default_transport/service_dispatcher.h>
-
#include <functional>
#include "DisplayHardware/ComposerHal.h"
@@ -66,9 +64,6 @@
ALOGI("Starting up VrFlinger...");
- setpriority(PRIO_PROCESS, 0, android::PRIORITY_URGENT_DISPLAY);
- set_sched_policy(0, SP_FOREGROUND);
-
// We need to be able to create endpoints with full perms.
umask(0000);
@@ -76,7 +71,7 @@
request_display_callback_ = request_display_callback;
- dispatcher_ = android::pdx::default_transport::ServiceDispatcher::Create();
+ dispatcher_ = android::pdx::ServiceDispatcher::Create();
CHECK_ERROR(!dispatcher_, error, "Failed to create service dispatcher.");
display_service_ =
@@ -102,6 +97,9 @@
prctl(PR_SET_NAME, reinterpret_cast<unsigned long>("VrDispatch"), 0, 0, 0);
ALOGI("Entering message loop.");
+ setpriority(PRIO_PROCESS, 0, android::PRIORITY_URGENT_DISPLAY);
+ set_sched_policy(0, SP_FOREGROUND);
+
int ret = dispatcher_->EnterDispatchLoop();
if (ret < 0) {
ALOGE("Dispatch loop exited because: %s\n", strerror(-ret));
@@ -135,8 +133,9 @@
display_service_->SeizeDisplayOwnership();
}
-void VrFlinger::OnHardwareComposerRefresh() {
- display_service_->OnHardwareComposerRefresh();
+std::string VrFlinger::Dump() {
+ // TODO(karthikrs): Add more state information here.
+ return display_service_->DumpState(0/*unused*/);
}
void VrFlinger::PersistentVrStateCallback::onPersistentVrStateChanged(
@@ -146,6 +145,5 @@
// Persistent VR mode is not enough.
// request_display_callback_(enabled);
}
-
} // namespace dvr
} // namespace android
diff --git a/libs/vr/libvrflinger/vsync_service.cpp b/libs/vr/libvrflinger/vsync_service.cpp
index 2a83933..fdeb899 100644
--- a/libs/vr/libvrflinger/vsync_service.cpp
+++ b/libs/vr/libvrflinger/vsync_service.cpp
@@ -110,6 +110,7 @@
}
pdx::Status<void> VSyncService::HandleMessage(pdx::Message& message) {
+ ATRACE_NAME("VSyncService::HandleMessage");
switch (message.GetOp()) {
case VSyncProtocol::Wait::Opcode:
AddWaiter(message);
@@ -200,12 +201,12 @@
}
void VSyncChannel::Ack() {
- ALOGD_IF(TRACE, "VSyncChannel::Ack: pid=%d cid=%d\n", pid_, cid_);
+ ALOGD_IF(TRACE > 1, "VSyncChannel::Ack: pid=%d cid=%d\n", pid_, cid_);
service_.ModifyChannelEvents(cid_, POLLPRI, 0);
}
void VSyncChannel::Signal() {
- ALOGD_IF(TRACE, "VSyncChannel::Signal: pid=%d cid=%d\n", pid_, cid_);
+ ALOGD_IF(TRACE > 1, "VSyncChannel::Signal: pid=%d cid=%d\n", pid_, cid_);
service_.ModifyChannelEvents(cid_, 0, POLLPRI);
}
diff --git a/libs/vr/libvrsensor/include/dvr/pose_client.h b/libs/vr/libvrsensor/include/dvr/pose_client.h
index d684ddc..bb25f1d 100644
--- a/libs/vr/libvrsensor/include/dvr/pose_client.h
+++ b/libs/vr/libvrsensor/include/dvr/pose_client.h
@@ -157,6 +157,18 @@
// @return Zero on success
int dvrPoseClientSensorsEnable(DvrPoseClient* client, bool enabled);
+// Requests a burst of data samples from pose service. The data samples are
+// passed through a shared memory buffer obtained by calling
+// dvrPoseClientGetDataReader().
+//
+// @param DvrPoseDataCaptureRequest Parameters on how to capture data.
+// @return Zero on success.
+int dvrPoseClientDataCapture(DvrPoseClient* client,
+ const DvrPoseDataCaptureRequest* request);
+
+// Destroys the write buffer queue for the given |data_type|.
+int dvrPoseClientDataReaderDestroy(DvrPoseClient* client, uint64_t data_type);
+
#ifdef __cplusplus
} // extern "C"
#endif
diff --git a/libs/vr/libvrsensor/include/private/dvr/pose-ipc.h b/libs/vr/libvrsensor/include/private/dvr/pose-ipc.h
index e4455f1..7bf1cd4 100644
--- a/libs/vr/libvrsensor/include/private/dvr/pose-ipc.h
+++ b/libs/vr/libvrsensor/include/private/dvr/pose-ipc.h
@@ -17,6 +17,9 @@
DVR_POSE_GET_CONTROLLER_RING_BUFFER,
DVR_POSE_LOG_CONTROLLER,
DVR_POSE_SENSORS_ENABLE,
+ DVR_POSE_GET_TANGO_READER,
+ DVR_POSE_DATA_CAPTURE,
+ DVR_POSE_TANGO_READER_DESTROY,
};
#ifdef __cplusplus
diff --git a/libs/vr/libvrsensor/include/private/dvr/pose_client_internal.h b/libs/vr/libvrsensor/include/private/dvr/pose_client_internal.h
new file mode 100644
index 0000000..39592bb
--- /dev/null
+++ b/libs/vr/libvrsensor/include/private/dvr/pose_client_internal.h
@@ -0,0 +1,19 @@
+#ifndef ANDROID_DVR_POSE_CLIENT_INTERNAL_H_
+#define ANDROID_DVR_POSE_CLIENT_INTERNAL_H_
+
+#include <private/dvr/buffer_hub_queue_client.h>
+
+using android::dvr::ConsumerQueue;
+
+typedef struct DvrPoseClient DvrPoseClient;
+
+namespace android {
+namespace dvr {
+
+int dvrPoseClientGetDataReaderHandle(DvrPoseClient *client, uint64_t data_type,
+ ConsumerQueue **queue_out);
+
+} // namespace dvr
+} // namespace android
+
+#endif // ANDROID_DVR_POSE_CLIENT_INTERNAL_H_
diff --git a/libs/vr/libvrsensor/pose_client.cpp b/libs/vr/libvrsensor/pose_client.cpp
index b21c7cf..4acc085 100644
--- a/libs/vr/libvrsensor/pose_client.cpp
+++ b/libs/vr/libvrsensor/pose_client.cpp
@@ -9,19 +9,25 @@
#include <pdx/default_transport/client_channel_factory.h>
#include <pdx/file_handle.h>
#include <private/dvr/buffer_hub_client.h>
+#include <private/dvr/buffer_hub_queue_client.h>
#include <private/dvr/display_client.h>
#include <private/dvr/pose-ipc.h>
#include <private/dvr/shared_buffer_helpers.h>
+using android::dvr::ConsumerQueue;
using android::pdx::LocalHandle;
using android::pdx::LocalChannelHandle;
using android::pdx::Status;
using android::pdx::Transaction;
-#define arraysize(x) (static_cast<int32_t>(std::extent<decltype(x)>::value))
-
namespace android {
namespace dvr {
+namespace {
+
+typedef CPUMappedBroadcastRing<DvrPoseRing> SensorPoseRing;
+
+constexpr static int32_t MAX_CONTROLLERS = 2;
+} // namespace
// PoseClient is a remote interface to the pose service in sensord.
class PoseClient : public pdx::ClientBase<PoseClient> {
@@ -36,16 +42,21 @@
// Polls the pose service for the current state and stores it in *state.
// Returns zero on success, a negative error code otherwise.
int Poll(DvrPose* state) {
- const auto vsync_buffer = GetVsyncBuffer();
- if (vsync_buffer) {
- if (state) {
- // Fill the state
- *state = vsync_buffer->current_pose;
- }
- return -EINVAL;
+ // Allocate the helper class to access the sensor pose buffer.
+ if (sensor_pose_buffer_ == nullptr) {
+ sensor_pose_buffer_ = std::make_unique<SensorPoseRing>(
+ DvrGlobalBuffers::kSensorPoseBuffer, CPUUsageMode::READ_RARELY);
}
- return -EAGAIN;
+ if (state) {
+ if (sensor_pose_buffer_->GetNewest(state)) {
+ return 0;
+ } else {
+ return -EAGAIN;
+ }
+ }
+
+ return -EINVAL;
}
int GetPose(uint32_t vsync_count, DvrPoseAsync* out_pose) {
@@ -71,7 +82,7 @@
int GetControllerPose(int32_t controller_id, uint32_t vsync_count,
DvrPoseAsync* out_pose) {
- if (controller_id < 0 || controller_id >= arraysize(controllers_)) {
+ if (controller_id < 0 || controller_id >= MAX_CONTROLLERS) {
return -EINVAL;
}
if (!controllers_[controller_id].mapped_pose_buffer) {
@@ -130,6 +141,44 @@
return ReturnStatusOrError(status);
}
+ int GetTangoReaderHandle(uint64_t data_type, ConsumerQueue** queue_out) {
+ // Get buffer.
+ Transaction trans{*this};
+ Status<LocalChannelHandle> status = trans.Send<LocalChannelHandle>(
+ DVR_POSE_GET_TANGO_READER, &data_type, sizeof(data_type), nullptr, 0);
+
+ if (!status) {
+ ALOGE("PoseClient GetTangoReaderHandle() failed because: %s",
+ status.GetErrorMessage().c_str());
+ *queue_out = nullptr;
+ return -status.error();
+ }
+
+ std::unique_ptr<ConsumerQueue> consumer_queue =
+ ConsumerQueue::Import(status.take());
+ *queue_out = consumer_queue.release();
+ return 0;
+ }
+
+ int DataCapture(const DvrPoseDataCaptureRequest* request) {
+ Transaction trans{*this};
+ Status<int> status = trans.Send<int>(DVR_POSE_DATA_CAPTURE, request,
+ sizeof(*request), nullptr, 0);
+ ALOGE_IF(!status, "PoseClient DataCapture() failed because: %s\n",
+ status.GetErrorMessage().c_str());
+ return ReturnStatusOrError(status);
+ }
+
+ int DataReaderDestroy(uint64_t data_type) {
+ Transaction trans{*this};
+ Status<int> status = trans.Send<int>(DVR_POSE_TANGO_READER_DESTROY,
+ &data_type, sizeof(data_type), nullptr,
+ 0);
+ ALOGE_IF(!status, "PoseClient DataReaderDestroy() failed because: %s\n",
+ status.GetErrorMessage().c_str());
+ return ReturnStatusOrError(status);
+ }
+
// Enables or disables all pose processing from sensors
int EnableSensors(bool enabled) {
Transaction trans{*this};
@@ -156,7 +205,7 @@
}
int GetControllerRingBuffer(int32_t controller_id) {
- if (controller_id < 0 || controller_id >= arraysize(controllers_)) {
+ if (controller_id < 0 || controller_id >= MAX_CONTROLLERS) {
return -EINVAL;
}
ControllerClientState& client_state = controllers_[controller_id];
@@ -235,15 +284,23 @@
// The vsync pose buffer if already mapped.
std::unique_ptr<CPUMappedBuffer> vsync_pose_buffer_;
+ // The direct sensor pose buffer.
+ std::unique_ptr<SensorPoseRing> sensor_pose_buffer_;
+
const DvrVsyncPoseBuffer* mapped_vsync_pose_buffer_ = nullptr;
struct ControllerClientState {
std::unique_ptr<BufferConsumer> pose_buffer;
const DvrPoseAsync* mapped_pose_buffer = nullptr;
};
- ControllerClientState controllers_[2];
+ ControllerClientState controllers_[MAX_CONTROLLERS];
};
+int dvrPoseClientGetDataReaderHandle(DvrPoseClient* client, uint64_t type,
+ ConsumerQueue** queue_out) {
+ return PoseClient::FromC(client)->GetTangoReaderHandle(type, queue_out);
+}
+
} // namespace dvr
} // namespace android
@@ -295,9 +352,17 @@
return PoseClient::FromC(client)->GetMode(mode);
}
-
int dvrPoseClientSensorsEnable(DvrPoseClient* client, bool enabled) {
return PoseClient::FromC(client)->EnableSensors(enabled);
}
+int dvrPoseClientDataCapture(DvrPoseClient* client,
+ const DvrPoseDataCaptureRequest* request) {
+ return PoseClient::FromC(client)->DataCapture(request);
+}
+
+int dvrPoseClientDataReaderDestroy(DvrPoseClient* client, uint64_t data_type) {
+ return PoseClient::FromC(client)->DataReaderDestroy(data_type);
+}
+
} // extern "C"
diff --git a/opengl/Android.bp b/opengl/Android.bp
index c520bda..9ca8b0b 100644
--- a/opengl/Android.bp
+++ b/opengl/Android.bp
@@ -52,6 +52,36 @@
license: "include/KHR/NOTICE",
}
+llndk_library {
+ name: "libEGL",
+ symbol_file: "libs/libEGL.map.txt",
+ export_include_dirs: ["include"],
+}
+
+llndk_library {
+ name: "libGLESv1_CM",
+ symbol_file: "libs/libGLESv1_CM.map.txt",
+ export_include_dirs: ["include"],
+}
+
+llndk_library {
+ name: "libGLESv2",
+ symbol_file: "libs/libGLESv2.map.txt",
+ export_include_dirs: ["include"],
+}
+
+llndk_library {
+ name: "libGLESv3",
+ symbol_file: "libs/libGLESv3.map.txt",
+ export_include_dirs: ["include"],
+}
+
+cc_library_headers {
+ name: "gl_headers",
+ vendor_available: true,
+ export_include_dirs: ["include"],
+}
+
subdirs = [
"*",
]
diff --git a/opengl/include/EGL/NOTICE b/opengl/include/EGL/NOTICE
index 55f5efa..93d0f2e 100644
--- a/opengl/include/EGL/NOTICE
+++ b/opengl/include/EGL/NOTICE
@@ -1,4 +1,4 @@
-Copyright (c) 2007-2009 The Khronos Group Inc.
+Copyright (c) 2007-2017 The Khronos Group Inc.
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and/or associated documentation files (the
diff --git a/opengl/include/EGL/egl.h b/opengl/include/EGL/egl.h
index ccb54ea..93a3965 100644
--- a/opengl/include/EGL/egl.h
+++ b/opengl/include/EGL/egl.h
@@ -1,11 +1,12 @@
-/* -*- mode: c; tab-width: 8; -*- */
-/* vi: set sw=4 ts=8: */
-/* Reference version of egl.h for EGL 1.4.
- * $Revision: 9356 $ on $Date: 2009-10-21 02:52:25 -0700 (Wed, 21 Oct 2009) $
- */
+#ifndef __egl_h_
+#define __egl_h_ 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
/*
-** Copyright (c) 2007-2009 The Khronos Group Inc.
+** Copyright (c) 2013-2017 The Khronos Group Inc.
**
** Permission is hereby granted, free of charge, to any person obtaining a
** copy of this software and/or associated documentation files (the
@@ -26,304 +27,221 @@
** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
*/
+/*
+** This header is generated from the Khronos OpenGL / OpenGL ES XML
+** API Registry. The current version of the Registry, generator scripts
+** used to make the header, and the header can be found at
+** http://www.khronos.org/registry/egl
+**
+** Khronos $Git commit SHA1: a732b061e7 $ on $Git commit date: 2017-06-17 23:27:53 +0100 $
+*/
-#ifndef __egl_h_
-#define __egl_h_
-
-/* All platform-dependent types and macro boilerplate (such as EGLAPI
- * and EGLAPIENTRY) should go in eglplatform.h.
- */
#include <EGL/eglplatform.h>
-#ifdef __cplusplus
-extern "C" {
-#endif
+/* Generated on date 20170627 */
-/* EGL Types */
-/* EGLint is defined in eglplatform.h */
+/* Generated C header for:
+ * API: egl
+ * Versions considered: .*
+ * Versions emitted: .*
+ * Default extensions included: None
+ * Additional extensions included: _nomatch_^
+ * Extensions removed: _nomatch_^
+ */
+
+#ifndef EGL_VERSION_1_0
+#define EGL_VERSION_1_0 1
typedef unsigned int EGLBoolean;
-typedef unsigned int EGLenum;
-typedef void *EGLConfig;
-typedef void *EGLContext;
typedef void *EGLDisplay;
+#include <KHR/khrplatform.h>
+#include <EGL/eglplatform.h>
+typedef void *EGLConfig;
typedef void *EGLSurface;
-typedef void *EGLClientBuffer;
-
-/* EGL Versioning */
-#define EGL_VERSION_1_0 1
-#define EGL_VERSION_1_1 1
-#define EGL_VERSION_1_2 1
-#define EGL_VERSION_1_3 1
-#define EGL_VERSION_1_4 1
-
-/* EGL Enumerants. Bitmasks and other exceptional cases aside, most
- * enums are assigned unique values starting at 0x3000.
- */
-
-/* EGL aliases */
-#define EGL_FALSE 0
-#define EGL_TRUE 1
-
-/* Out-of-band handle values */
-#define EGL_DEFAULT_DISPLAY EGL_CAST(EGLNativeDisplayType, 0)
-#define EGL_NO_CONTEXT EGL_CAST(EGLContext, 0)
-#define EGL_NO_DISPLAY EGL_CAST(EGLDisplay, 0)
-#define EGL_NO_SURFACE EGL_CAST(EGLSurface, 0)
-
-/* Out-of-band attribute value */
-#define EGL_DONT_CARE EGL_CAST(EGLint, -1)
-
-/* Errors / GetError return values */
-#define EGL_SUCCESS 0x3000
-#define EGL_NOT_INITIALIZED 0x3001
-#define EGL_BAD_ACCESS 0x3002
-#define EGL_BAD_ALLOC 0x3003
-#define EGL_BAD_ATTRIBUTE 0x3004
-#define EGL_BAD_CONFIG 0x3005
-#define EGL_BAD_CONTEXT 0x3006
-#define EGL_BAD_CURRENT_SURFACE 0x3007
-#define EGL_BAD_DISPLAY 0x3008
-#define EGL_BAD_MATCH 0x3009
-#define EGL_BAD_NATIVE_PIXMAP 0x300A
-#define EGL_BAD_NATIVE_WINDOW 0x300B
-#define EGL_BAD_PARAMETER 0x300C
-#define EGL_BAD_SURFACE 0x300D
-#define EGL_CONTEXT_LOST 0x300E /* EGL 1.1 - IMG_power_management */
-
-/* Reserved 0x300F-0x301F for additional errors */
-
-/* Config attributes */
-#define EGL_BUFFER_SIZE 0x3020
-#define EGL_ALPHA_SIZE 0x3021
-#define EGL_BLUE_SIZE 0x3022
-#define EGL_GREEN_SIZE 0x3023
-#define EGL_RED_SIZE 0x3024
-#define EGL_DEPTH_SIZE 0x3025
-#define EGL_STENCIL_SIZE 0x3026
-#define EGL_CONFIG_CAVEAT 0x3027
-#define EGL_CONFIG_ID 0x3028
-#define EGL_LEVEL 0x3029
-#define EGL_MAX_PBUFFER_HEIGHT 0x302A
-#define EGL_MAX_PBUFFER_PIXELS 0x302B
-#define EGL_MAX_PBUFFER_WIDTH 0x302C
-#define EGL_NATIVE_RENDERABLE 0x302D
-#define EGL_NATIVE_VISUAL_ID 0x302E
-#define EGL_NATIVE_VISUAL_TYPE 0x302F
-#define EGL_SAMPLES 0x3031
-#define EGL_SAMPLE_BUFFERS 0x3032
-#define EGL_SURFACE_TYPE 0x3033
-#define EGL_TRANSPARENT_TYPE 0x3034
-#define EGL_TRANSPARENT_BLUE_VALUE 0x3035
-#define EGL_TRANSPARENT_GREEN_VALUE 0x3036
-#define EGL_TRANSPARENT_RED_VALUE 0x3037
-#define EGL_NONE 0x3038 /* Attrib list terminator */
-#define EGL_BIND_TO_TEXTURE_RGB 0x3039
-#define EGL_BIND_TO_TEXTURE_RGBA 0x303A
-#define EGL_MIN_SWAP_INTERVAL 0x303B
-#define EGL_MAX_SWAP_INTERVAL 0x303C
-#define EGL_LUMINANCE_SIZE 0x303D
-#define EGL_ALPHA_MASK_SIZE 0x303E
-#define EGL_COLOR_BUFFER_TYPE 0x303F
-#define EGL_RENDERABLE_TYPE 0x3040
-#define EGL_MATCH_NATIVE_PIXMAP 0x3041 /* Pseudo-attribute (not queryable) */
-#define EGL_CONFORMANT 0x3042
-
-/* Reserved 0x3041-0x304F for additional config attributes */
-
-/* Config attribute values */
-#define EGL_SLOW_CONFIG 0x3050 /* EGL_CONFIG_CAVEAT value */
-#define EGL_NON_CONFORMANT_CONFIG 0x3051 /* EGL_CONFIG_CAVEAT value */
-#define EGL_TRANSPARENT_RGB 0x3052 /* EGL_TRANSPARENT_TYPE value */
-#define EGL_RGB_BUFFER 0x308E /* EGL_COLOR_BUFFER_TYPE value */
-#define EGL_LUMINANCE_BUFFER 0x308F /* EGL_COLOR_BUFFER_TYPE value */
-
-/* More config attribute values, for EGL_TEXTURE_FORMAT */
-#define EGL_NO_TEXTURE 0x305C
-#define EGL_TEXTURE_RGB 0x305D
-#define EGL_TEXTURE_RGBA 0x305E
-#define EGL_TEXTURE_2D 0x305F
-
-/* Config attribute mask bits */
-#define EGL_PBUFFER_BIT 0x0001 /* EGL_SURFACE_TYPE mask bits */
-#define EGL_PIXMAP_BIT 0x0002 /* EGL_SURFACE_TYPE mask bits */
-#define EGL_WINDOW_BIT 0x0004 /* EGL_SURFACE_TYPE mask bits */
-#define EGL_VG_COLORSPACE_LINEAR_BIT 0x0020 /* EGL_SURFACE_TYPE mask bits */
-#define EGL_VG_ALPHA_FORMAT_PRE_BIT 0x0040 /* EGL_SURFACE_TYPE mask bits */
-#define EGL_MULTISAMPLE_RESOLVE_BOX_BIT 0x0200 /* EGL_SURFACE_TYPE mask bits */
-#define EGL_SWAP_BEHAVIOR_PRESERVED_BIT 0x0400 /* EGL_SURFACE_TYPE mask bits */
-
-#define EGL_OPENGL_ES_BIT 0x0001 /* EGL_RENDERABLE_TYPE mask bits */
-#define EGL_OPENVG_BIT 0x0002 /* EGL_RENDERABLE_TYPE mask bits */
-#define EGL_OPENGL_ES2_BIT 0x0004 /* EGL_RENDERABLE_TYPE mask bits */
-#define EGL_OPENGL_BIT 0x0008 /* EGL_RENDERABLE_TYPE mask bits */
-
-/* QueryString targets */
-#define EGL_VENDOR 0x3053
-#define EGL_VERSION 0x3054
-#define EGL_EXTENSIONS 0x3055
-#define EGL_CLIENT_APIS 0x308D
-
-/* QuerySurface / SurfaceAttrib / CreatePbufferSurface targets */
-#define EGL_HEIGHT 0x3056
-#define EGL_WIDTH 0x3057
-#define EGL_LARGEST_PBUFFER 0x3058
-#define EGL_TEXTURE_FORMAT 0x3080
-#define EGL_TEXTURE_TARGET 0x3081
-#define EGL_MIPMAP_TEXTURE 0x3082
-#define EGL_MIPMAP_LEVEL 0x3083
-#define EGL_RENDER_BUFFER 0x3086
-#define EGL_VG_COLORSPACE 0x3087
-#define EGL_VG_ALPHA_FORMAT 0x3088
-#define EGL_HORIZONTAL_RESOLUTION 0x3090
-#define EGL_VERTICAL_RESOLUTION 0x3091
-#define EGL_PIXEL_ASPECT_RATIO 0x3092
-#define EGL_SWAP_BEHAVIOR 0x3093
-#define EGL_MULTISAMPLE_RESOLVE 0x3099
-
-/* EGL_RENDER_BUFFER values / BindTexImage / ReleaseTexImage buffer targets */
-#define EGL_BACK_BUFFER 0x3084
-#define EGL_SINGLE_BUFFER 0x3085
-
-/* OpenVG color spaces */
-#define EGL_VG_COLORSPACE_sRGB 0x3089 /* EGL_VG_COLORSPACE value */
-#define EGL_VG_COLORSPACE_LINEAR 0x308A /* EGL_VG_COLORSPACE value */
-
-/* OpenVG alpha formats */
-#define EGL_VG_ALPHA_FORMAT_NONPRE 0x308B /* EGL_ALPHA_FORMAT value */
-#define EGL_VG_ALPHA_FORMAT_PRE 0x308C /* EGL_ALPHA_FORMAT value */
-
-/* Constant scale factor by which fractional display resolutions &
- * aspect ratio are scaled when queried as integer values.
- */
-#define EGL_DISPLAY_SCALING 10000
-
-/* Unknown display resolution/aspect ratio */
-#define EGL_UNKNOWN EGL_CAST(EGLint, -1)
-
-/* Back buffer swap behaviors */
-#define EGL_BUFFER_PRESERVED 0x3094 /* EGL_SWAP_BEHAVIOR value */
-#define EGL_BUFFER_DESTROYED 0x3095 /* EGL_SWAP_BEHAVIOR value */
-
-/* CreatePbufferFromClientBuffer buffer types */
-#define EGL_OPENVG_IMAGE 0x3096
-
-/* QueryContext targets */
-#define EGL_CONTEXT_CLIENT_TYPE 0x3097
-
-/* CreateContext attributes */
-#define EGL_CONTEXT_CLIENT_VERSION 0x3098
-
-/* Multisample resolution behaviors */
-#define EGL_MULTISAMPLE_RESOLVE_DEFAULT 0x309A /* EGL_MULTISAMPLE_RESOLVE value */
-#define EGL_MULTISAMPLE_RESOLVE_BOX 0x309B /* EGL_MULTISAMPLE_RESOLVE value */
-
-/* BindAPI/QueryAPI targets */
-#define EGL_OPENGL_ES_API 0x30A0
-#define EGL_OPENVG_API 0x30A1
-#define EGL_OPENGL_API 0x30A2
-
-/* GetCurrentSurface targets */
-#define EGL_DRAW 0x3059
-#define EGL_READ 0x305A
-
-/* WaitNative engines */
-#define EGL_CORE_NATIVE_ENGINE 0x305B
-
-/* EGL 1.2 tokens renamed for consistency in EGL 1.3 */
-#define EGL_COLORSPACE EGL_VG_COLORSPACE
-#define EGL_ALPHA_FORMAT EGL_VG_ALPHA_FORMAT
-#define EGL_COLORSPACE_sRGB EGL_VG_COLORSPACE_sRGB
-#define EGL_COLORSPACE_LINEAR EGL_VG_COLORSPACE_LINEAR
-#define EGL_ALPHA_FORMAT_NONPRE EGL_VG_ALPHA_FORMAT_NONPRE
-#define EGL_ALPHA_FORMAT_PRE EGL_VG_ALPHA_FORMAT_PRE
-
-/* EGL extensions must request enum blocks from the Khronos
- * API Registrar, who maintains the enumerant registry. Submit
- * a bug in Khronos Bugzilla against task "Registry".
- */
-
-
-
-/* EGL Functions */
-
-EGLAPI EGLint EGLAPIENTRY eglGetError(void);
-
-EGLAPI EGLDisplay EGLAPIENTRY eglGetDisplay(EGLNativeDisplayType display_id);
-EGLAPI EGLBoolean EGLAPIENTRY eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor);
-EGLAPI EGLBoolean EGLAPIENTRY eglTerminate(EGLDisplay dpy);
-
-EGLAPI const char * EGLAPIENTRY eglQueryString(EGLDisplay dpy, EGLint name);
-
-EGLAPI EGLBoolean EGLAPIENTRY eglGetConfigs(EGLDisplay dpy, EGLConfig *configs,
- EGLint config_size, EGLint *num_config);
-EGLAPI EGLBoolean EGLAPIENTRY eglChooseConfig(EGLDisplay dpy, const EGLint *attrib_list,
- EGLConfig *configs, EGLint config_size,
- EGLint *num_config);
-EGLAPI EGLBoolean EGLAPIENTRY eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config,
- EGLint attribute, EGLint *value);
-
-EGLAPI EGLSurface EGLAPIENTRY eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config,
- EGLNativeWindowType win,
- const EGLint *attrib_list);
-EGLAPI EGLSurface EGLAPIENTRY eglCreatePbufferSurface(EGLDisplay dpy, EGLConfig config,
- const EGLint *attrib_list);
-EGLAPI EGLSurface EGLAPIENTRY eglCreatePixmapSurface(EGLDisplay dpy, EGLConfig config,
- EGLNativePixmapType pixmap,
- const EGLint *attrib_list);
-EGLAPI EGLBoolean EGLAPIENTRY eglDestroySurface(EGLDisplay dpy, EGLSurface surface);
-EGLAPI EGLBoolean EGLAPIENTRY eglQuerySurface(EGLDisplay dpy, EGLSurface surface,
- EGLint attribute, EGLint *value);
-
-EGLAPI EGLBoolean EGLAPIENTRY eglBindAPI(EGLenum api);
-EGLAPI EGLenum EGLAPIENTRY eglQueryAPI(void);
-
-EGLAPI EGLBoolean EGLAPIENTRY eglWaitClient(void);
-
-EGLAPI EGLBoolean EGLAPIENTRY eglReleaseThread(void);
-
-EGLAPI EGLSurface EGLAPIENTRY eglCreatePbufferFromClientBuffer(
- EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer,
- EGLConfig config, const EGLint *attrib_list);
-
-EGLAPI EGLBoolean EGLAPIENTRY eglSurfaceAttrib(EGLDisplay dpy, EGLSurface surface,
- EGLint attribute, EGLint value);
-EGLAPI EGLBoolean EGLAPIENTRY eglBindTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer);
-EGLAPI EGLBoolean EGLAPIENTRY eglReleaseTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer);
-
-
-EGLAPI EGLBoolean EGLAPIENTRY eglSwapInterval(EGLDisplay dpy, EGLint interval);
-
-
-EGLAPI EGLContext EGLAPIENTRY eglCreateContext(EGLDisplay dpy, EGLConfig config,
- EGLContext share_context,
- const EGLint *attrib_list);
-EGLAPI EGLBoolean EGLAPIENTRY eglDestroyContext(EGLDisplay dpy, EGLContext ctx);
-EGLAPI EGLBoolean EGLAPIENTRY eglMakeCurrent(EGLDisplay dpy, EGLSurface draw,
- EGLSurface read, EGLContext ctx);
-
-EGLAPI EGLContext EGLAPIENTRY eglGetCurrentContext(void);
-EGLAPI EGLSurface EGLAPIENTRY eglGetCurrentSurface(EGLint readdraw);
-EGLAPI EGLDisplay EGLAPIENTRY eglGetCurrentDisplay(void);
-EGLAPI EGLBoolean EGLAPIENTRY eglQueryContext(EGLDisplay dpy, EGLContext ctx,
- EGLint attribute, EGLint *value);
-
-EGLAPI EGLBoolean EGLAPIENTRY eglWaitGL(void);
-EGLAPI EGLBoolean EGLAPIENTRY eglWaitNative(EGLint engine);
-EGLAPI EGLBoolean EGLAPIENTRY eglSwapBuffers(EGLDisplay dpy, EGLSurface surface);
-EGLAPI EGLBoolean EGLAPIENTRY eglCopyBuffers(EGLDisplay dpy, EGLSurface surface,
- EGLNativePixmapType target);
-
-/* This is a generic function pointer type, whose name indicates it must
- * be cast to the proper type *and calling convention* before use.
- */
+typedef void *EGLContext;
typedef void (*__eglMustCastToProperFunctionPointerType)(void);
+#define EGL_ALPHA_SIZE 0x3021
+#define EGL_BAD_ACCESS 0x3002
+#define EGL_BAD_ALLOC 0x3003
+#define EGL_BAD_ATTRIBUTE 0x3004
+#define EGL_BAD_CONFIG 0x3005
+#define EGL_BAD_CONTEXT 0x3006
+#define EGL_BAD_CURRENT_SURFACE 0x3007
+#define EGL_BAD_DISPLAY 0x3008
+#define EGL_BAD_MATCH 0x3009
+#define EGL_BAD_NATIVE_PIXMAP 0x300A
+#define EGL_BAD_NATIVE_WINDOW 0x300B
+#define EGL_BAD_PARAMETER 0x300C
+#define EGL_BAD_SURFACE 0x300D
+#define EGL_BLUE_SIZE 0x3022
+#define EGL_BUFFER_SIZE 0x3020
+#define EGL_CONFIG_CAVEAT 0x3027
+#define EGL_CONFIG_ID 0x3028
+#define EGL_CORE_NATIVE_ENGINE 0x305B
+#define EGL_DEPTH_SIZE 0x3025
+#define EGL_DONT_CARE EGL_CAST(EGLint,-1)
+#define EGL_DRAW 0x3059
+#define EGL_EXTENSIONS 0x3055
+#define EGL_FALSE 0
+#define EGL_GREEN_SIZE 0x3023
+#define EGL_HEIGHT 0x3056
+#define EGL_LARGEST_PBUFFER 0x3058
+#define EGL_LEVEL 0x3029
+#define EGL_MAX_PBUFFER_HEIGHT 0x302A
+#define EGL_MAX_PBUFFER_PIXELS 0x302B
+#define EGL_MAX_PBUFFER_WIDTH 0x302C
+#define EGL_NATIVE_RENDERABLE 0x302D
+#define EGL_NATIVE_VISUAL_ID 0x302E
+#define EGL_NATIVE_VISUAL_TYPE 0x302F
+#define EGL_NONE 0x3038
+#define EGL_NON_CONFORMANT_CONFIG 0x3051
+#define EGL_NOT_INITIALIZED 0x3001
+#define EGL_NO_CONTEXT EGL_CAST(EGLContext,0)
+#define EGL_NO_DISPLAY EGL_CAST(EGLDisplay,0)
+#define EGL_NO_SURFACE EGL_CAST(EGLSurface,0)
+#define EGL_PBUFFER_BIT 0x0001
+#define EGL_PIXMAP_BIT 0x0002
+#define EGL_READ 0x305A
+#define EGL_RED_SIZE 0x3024
+#define EGL_SAMPLES 0x3031
+#define EGL_SAMPLE_BUFFERS 0x3032
+#define EGL_SLOW_CONFIG 0x3050
+#define EGL_STENCIL_SIZE 0x3026
+#define EGL_SUCCESS 0x3000
+#define EGL_SURFACE_TYPE 0x3033
+#define EGL_TRANSPARENT_BLUE_VALUE 0x3035
+#define EGL_TRANSPARENT_GREEN_VALUE 0x3036
+#define EGL_TRANSPARENT_RED_VALUE 0x3037
+#define EGL_TRANSPARENT_RGB 0x3052
+#define EGL_TRANSPARENT_TYPE 0x3034
+#define EGL_TRUE 1
+#define EGL_VENDOR 0x3053
+#define EGL_VERSION 0x3054
+#define EGL_WIDTH 0x3057
+#define EGL_WINDOW_BIT 0x0004
+EGLAPI EGLBoolean EGLAPIENTRY eglChooseConfig (EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_config);
+EGLAPI EGLBoolean EGLAPIENTRY eglCopyBuffers (EGLDisplay dpy, EGLSurface surface, EGLNativePixmapType target);
+EGLAPI EGLContext EGLAPIENTRY eglCreateContext (EGLDisplay dpy, EGLConfig config, EGLContext share_context, const EGLint *attrib_list);
+EGLAPI EGLSurface EGLAPIENTRY eglCreatePbufferSurface (EGLDisplay dpy, EGLConfig config, const EGLint *attrib_list);
+EGLAPI EGLSurface EGLAPIENTRY eglCreatePixmapSurface (EGLDisplay dpy, EGLConfig config, EGLNativePixmapType pixmap, const EGLint *attrib_list);
+EGLAPI EGLSurface EGLAPIENTRY eglCreateWindowSurface (EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, const EGLint *attrib_list);
+EGLAPI EGLBoolean EGLAPIENTRY eglDestroyContext (EGLDisplay dpy, EGLContext ctx);
+EGLAPI EGLBoolean EGLAPIENTRY eglDestroySurface (EGLDisplay dpy, EGLSurface surface);
+EGLAPI EGLBoolean EGLAPIENTRY eglGetConfigAttrib (EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value);
+EGLAPI EGLBoolean EGLAPIENTRY eglGetConfigs (EGLDisplay dpy, EGLConfig *configs, EGLint config_size, EGLint *num_config);
+EGLAPI EGLDisplay EGLAPIENTRY eglGetCurrentDisplay (void);
+EGLAPI EGLSurface EGLAPIENTRY eglGetCurrentSurface (EGLint readdraw);
+EGLAPI EGLDisplay EGLAPIENTRY eglGetDisplay (EGLNativeDisplayType display_id);
+EGLAPI EGLint EGLAPIENTRY eglGetError (void);
+EGLAPI __eglMustCastToProperFunctionPointerType EGLAPIENTRY eglGetProcAddress (const char *procname);
+EGLAPI EGLBoolean EGLAPIENTRY eglInitialize (EGLDisplay dpy, EGLint *major, EGLint *minor);
+EGLAPI EGLBoolean EGLAPIENTRY eglMakeCurrent (EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx);
+EGLAPI EGLBoolean EGLAPIENTRY eglQueryContext (EGLDisplay dpy, EGLContext ctx, EGLint attribute, EGLint *value);
+EGLAPI const char *EGLAPIENTRY eglQueryString (EGLDisplay dpy, EGLint name);
+EGLAPI EGLBoolean EGLAPIENTRY eglQuerySurface (EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint *value);
+EGLAPI EGLBoolean EGLAPIENTRY eglSwapBuffers (EGLDisplay dpy, EGLSurface surface);
+EGLAPI EGLBoolean EGLAPIENTRY eglTerminate (EGLDisplay dpy);
+EGLAPI EGLBoolean EGLAPIENTRY eglWaitGL (void);
+EGLAPI EGLBoolean EGLAPIENTRY eglWaitNative (EGLint engine);
+#endif /* EGL_VERSION_1_0 */
-/* Now, define eglGetProcAddress using the generic function ptr. type */
-EGLAPI __eglMustCastToProperFunctionPointerType EGLAPIENTRY
- eglGetProcAddress(const char *procname);
+#ifndef EGL_VERSION_1_1
+#define EGL_VERSION_1_1 1
+#define EGL_BACK_BUFFER 0x3084
+#define EGL_BIND_TO_TEXTURE_RGB 0x3039
+#define EGL_BIND_TO_TEXTURE_RGBA 0x303A
+#define EGL_CONTEXT_LOST 0x300E
+#define EGL_MIN_SWAP_INTERVAL 0x303B
+#define EGL_MAX_SWAP_INTERVAL 0x303C
+#define EGL_MIPMAP_TEXTURE 0x3082
+#define EGL_MIPMAP_LEVEL 0x3083
+#define EGL_NO_TEXTURE 0x305C
+#define EGL_TEXTURE_2D 0x305F
+#define EGL_TEXTURE_FORMAT 0x3080
+#define EGL_TEXTURE_RGB 0x305D
+#define EGL_TEXTURE_RGBA 0x305E
+#define EGL_TEXTURE_TARGET 0x3081
+EGLAPI EGLBoolean EGLAPIENTRY eglBindTexImage (EGLDisplay dpy, EGLSurface surface, EGLint buffer);
+EGLAPI EGLBoolean EGLAPIENTRY eglReleaseTexImage (EGLDisplay dpy, EGLSurface surface, EGLint buffer);
+EGLAPI EGLBoolean EGLAPIENTRY eglSurfaceAttrib (EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value);
+EGLAPI EGLBoolean EGLAPIENTRY eglSwapInterval (EGLDisplay dpy, EGLint interval);
+#endif /* EGL_VERSION_1_1 */
+
+#ifndef EGL_VERSION_1_2
+#define EGL_VERSION_1_2 1
+typedef unsigned int EGLenum;
+typedef void *EGLClientBuffer;
+#define EGL_ALPHA_FORMAT 0x3088
+#define EGL_ALPHA_FORMAT_NONPRE 0x308B
+#define EGL_ALPHA_FORMAT_PRE 0x308C
+#define EGL_ALPHA_MASK_SIZE 0x303E
+#define EGL_BUFFER_PRESERVED 0x3094
+#define EGL_BUFFER_DESTROYED 0x3095
+#define EGL_CLIENT_APIS 0x308D
+#define EGL_COLORSPACE 0x3087
+#define EGL_COLORSPACE_sRGB 0x3089
+#define EGL_COLORSPACE_LINEAR 0x308A
+#define EGL_COLOR_BUFFER_TYPE 0x303F
+#define EGL_CONTEXT_CLIENT_TYPE 0x3097
+#define EGL_DISPLAY_SCALING 10000
+#define EGL_HORIZONTAL_RESOLUTION 0x3090
+#define EGL_LUMINANCE_BUFFER 0x308F
+#define EGL_LUMINANCE_SIZE 0x303D
+#define EGL_OPENGL_ES_BIT 0x0001
+#define EGL_OPENVG_BIT 0x0002
+#define EGL_OPENGL_ES_API 0x30A0
+#define EGL_OPENVG_API 0x30A1
+#define EGL_OPENVG_IMAGE 0x3096
+#define EGL_PIXEL_ASPECT_RATIO 0x3092
+#define EGL_RENDERABLE_TYPE 0x3040
+#define EGL_RENDER_BUFFER 0x3086
+#define EGL_RGB_BUFFER 0x308E
+#define EGL_SINGLE_BUFFER 0x3085
+#define EGL_SWAP_BEHAVIOR 0x3093
+#define EGL_UNKNOWN EGL_CAST(EGLint,-1)
+#define EGL_VERTICAL_RESOLUTION 0x3091
+EGLAPI EGLBoolean EGLAPIENTRY eglBindAPI (EGLenum api);
+EGLAPI EGLenum EGLAPIENTRY eglQueryAPI (void);
+EGLAPI EGLSurface EGLAPIENTRY eglCreatePbufferFromClientBuffer (EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer, EGLConfig config, const EGLint *attrib_list);
+EGLAPI EGLBoolean EGLAPIENTRY eglReleaseThread (void);
+EGLAPI EGLBoolean EGLAPIENTRY eglWaitClient (void);
+#endif /* EGL_VERSION_1_2 */
+
+#ifndef EGL_VERSION_1_3
+#define EGL_VERSION_1_3 1
+#define EGL_CONFORMANT 0x3042
+#define EGL_CONTEXT_CLIENT_VERSION 0x3098
+#define EGL_MATCH_NATIVE_PIXMAP 0x3041
+#define EGL_OPENGL_ES2_BIT 0x0004
+#define EGL_VG_ALPHA_FORMAT 0x3088
+#define EGL_VG_ALPHA_FORMAT_NONPRE 0x308B
+#define EGL_VG_ALPHA_FORMAT_PRE 0x308C
+#define EGL_VG_ALPHA_FORMAT_PRE_BIT 0x0040
+#define EGL_VG_COLORSPACE 0x3087
+#define EGL_VG_COLORSPACE_sRGB 0x3089
+#define EGL_VG_COLORSPACE_LINEAR 0x308A
+#define EGL_VG_COLORSPACE_LINEAR_BIT 0x0020
+#endif /* EGL_VERSION_1_3 */
+
+#ifndef EGL_VERSION_1_4
+#define EGL_VERSION_1_4 1
+#define EGL_DEFAULT_DISPLAY EGL_CAST(EGLNativeDisplayType,0)
+#define EGL_MULTISAMPLE_RESOLVE_BOX_BIT 0x0200
+#define EGL_MULTISAMPLE_RESOLVE 0x3099
+#define EGL_MULTISAMPLE_RESOLVE_DEFAULT 0x309A
+#define EGL_MULTISAMPLE_RESOLVE_BOX 0x309B
+#define EGL_OPENGL_API 0x30A2
+#define EGL_OPENGL_BIT 0x0008
+#define EGL_SWAP_BEHAVIOR_PRESERVED_BIT 0x0400
+EGLAPI EGLContext EGLAPIENTRY eglGetCurrentContext (void);
+#endif /* EGL_VERSION_1_4 */
+
+/* This version of Android does not yet support EGL 1.5, but the following
+ * portion of EGL 1.5 is included in order to support portions of "eglext.h".
+ */
+typedef intptr_t EGLAttrib;
#ifdef __cplusplus
}
#endif
-#endif /* __egl_h_ */
+#endif
diff --git a/opengl/include/EGL/eglext.h b/opengl/include/EGL/eglext.h
index 7de8c62..466768a 100644
--- a/opengl/include/EGL/eglext.h
+++ b/opengl/include/EGL/eglext.h
@@ -1,12 +1,12 @@
#ifndef __eglext_h_
-#define __eglext_h_
+#define __eglext_h_ 1
#ifdef __cplusplus
extern "C" {
#endif
/*
-** Copyright (c) 2007-2013 The Khronos Group Inc.
+** Copyright (c) 2013-2017 The Khronos Group Inc.
**
** Permission is hereby granted, free of charge, to any person obtaining a
** copy of this software and/or associated documentation files (the
@@ -27,161 +27,254 @@
** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
*/
+/*
+** This header is generated from the Khronos OpenGL / OpenGL ES XML
+** API Registry. The current version of the Registry, generator scripts
+** used to make the header, and the header can be found at
+** http://www.khronos.org/registry/egl
+**
+** Khronos $Git commit SHA1: a732b061e7 $ on $Git commit date: 2017-06-17 23:27:53 +0100 $
+*/
#include <EGL/eglplatform.h>
-/*************************************************************/
+#define EGL_EGLEXT_VERSION 20170627
-/* Header file version number */
-/* Current version at http://www.khronos.org/registry/egl/ */
-/* $Revision: 20690 $ on $Date: 2013-02-22 17:15:05 -0800 (Fri, 22 Feb 2013) $ */
-#define EGL_EGLEXT_VERSION 15
+/* Generated C header for:
+ * API: egl
+ * Versions considered: .*
+ * Versions emitted: _nomatch_^
+ * Default extensions included: egl
+ * Additional extensions included: _nomatch_^
+ * Extensions removed: _nomatch_^
+ */
+
+#ifndef EGL_KHR_cl_event
+#define EGL_KHR_cl_event 1
+#define EGL_CL_EVENT_HANDLE_KHR 0x309C
+#define EGL_SYNC_CL_EVENT_KHR 0x30FE
+#define EGL_SYNC_CL_EVENT_COMPLETE_KHR 0x30FF
+#endif /* EGL_KHR_cl_event */
+
+#ifndef EGL_KHR_cl_event2
+#define EGL_KHR_cl_event2 1
+typedef void *EGLSyncKHR;
+typedef intptr_t EGLAttribKHR;
+typedef EGLSyncKHR (EGLAPIENTRYP PFNEGLCREATESYNC64KHRPROC) (EGLDisplay dpy, EGLenum type, const EGLAttribKHR *attrib_list);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLSyncKHR EGLAPIENTRY eglCreateSync64KHR (EGLDisplay dpy, EGLenum type, const EGLAttribKHR *attrib_list);
+#endif
+#endif /* EGL_KHR_cl_event2 */
+
+#ifndef EGL_KHR_client_get_all_proc_addresses
+#define EGL_KHR_client_get_all_proc_addresses 1
+#endif /* EGL_KHR_client_get_all_proc_addresses */
#ifndef EGL_KHR_config_attribs
#define EGL_KHR_config_attribs 1
-#define EGL_CONFORMANT_KHR 0x3042 /* EGLConfig attribute */
-#define EGL_VG_COLORSPACE_LINEAR_BIT_KHR 0x0020 /* EGL_SURFACE_TYPE bitfield */
-#define EGL_VG_ALPHA_FORMAT_PRE_BIT_KHR 0x0040 /* EGL_SURFACE_TYPE bitfield */
-#endif
+#define EGL_CONFORMANT_KHR 0x3042
+#define EGL_VG_COLORSPACE_LINEAR_BIT_KHR 0x0020
+#define EGL_VG_ALPHA_FORMAT_PRE_BIT_KHR 0x0040
+#endif /* EGL_KHR_config_attribs */
-#ifndef EGL_KHR_lock_surface
-#define EGL_KHR_lock_surface 1
-#define EGL_READ_SURFACE_BIT_KHR 0x0001 /* EGL_LOCK_USAGE_HINT_KHR bitfield */
-#define EGL_WRITE_SURFACE_BIT_KHR 0x0002 /* EGL_LOCK_USAGE_HINT_KHR bitfield */
-#define EGL_LOCK_SURFACE_BIT_KHR 0x0080 /* EGL_SURFACE_TYPE bitfield */
-#define EGL_OPTIMAL_FORMAT_BIT_KHR 0x0100 /* EGL_SURFACE_TYPE bitfield */
-#define EGL_MATCH_FORMAT_KHR 0x3043 /* EGLConfig attribute */
-#define EGL_FORMAT_RGB_565_EXACT_KHR 0x30C0 /* EGL_MATCH_FORMAT_KHR value */
-#define EGL_FORMAT_RGB_565_KHR 0x30C1 /* EGL_MATCH_FORMAT_KHR value */
-#define EGL_FORMAT_RGBA_8888_EXACT_KHR 0x30C2 /* EGL_MATCH_FORMAT_KHR value */
-#define EGL_FORMAT_RGBA_8888_KHR 0x30C3 /* EGL_MATCH_FORMAT_KHR value */
-#define EGL_MAP_PRESERVE_PIXELS_KHR 0x30C4 /* eglLockSurfaceKHR attribute */
-#define EGL_LOCK_USAGE_HINT_KHR 0x30C5 /* eglLockSurfaceKHR attribute */
-#define EGL_BITMAP_POINTER_KHR 0x30C6 /* eglQuerySurface attribute */
-#define EGL_BITMAP_PITCH_KHR 0x30C7 /* eglQuerySurface attribute */
-#define EGL_BITMAP_ORIGIN_KHR 0x30C8 /* eglQuerySurface attribute */
-#define EGL_BITMAP_PIXEL_RED_OFFSET_KHR 0x30C9 /* eglQuerySurface attribute */
-#define EGL_BITMAP_PIXEL_GREEN_OFFSET_KHR 0x30CA /* eglQuerySurface attribute */
-#define EGL_BITMAP_PIXEL_BLUE_OFFSET_KHR 0x30CB /* eglQuerySurface attribute */
-#define EGL_BITMAP_PIXEL_ALPHA_OFFSET_KHR 0x30CC /* eglQuerySurface attribute */
-#define EGL_BITMAP_PIXEL_LUMINANCE_OFFSET_KHR 0x30CD /* eglQuerySurface attribute */
-#define EGL_LOWER_LEFT_KHR 0x30CE /* EGL_BITMAP_ORIGIN_KHR value */
-#define EGL_UPPER_LEFT_KHR 0x30CF /* EGL_BITMAP_ORIGIN_KHR value */
+#ifndef EGL_KHR_context_flush_control
+#define EGL_KHR_context_flush_control 1
+#define EGL_CONTEXT_RELEASE_BEHAVIOR_NONE_KHR 0
+#define EGL_CONTEXT_RELEASE_BEHAVIOR_KHR 0x2097
+#define EGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_KHR 0x2098
+#endif /* EGL_KHR_context_flush_control */
+
+#ifndef EGL_KHR_create_context
+#define EGL_KHR_create_context 1
+#define EGL_CONTEXT_MAJOR_VERSION_KHR 0x3098
+#define EGL_CONTEXT_MINOR_VERSION_KHR 0x30FB
+#define EGL_CONTEXT_FLAGS_KHR 0x30FC
+#define EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR 0x30FD
+#define EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR 0x31BD
+#define EGL_NO_RESET_NOTIFICATION_KHR 0x31BE
+#define EGL_LOSE_CONTEXT_ON_RESET_KHR 0x31BF
+#define EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR 0x00000001
+#define EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR 0x00000002
+#define EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR 0x00000004
+#define EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR 0x00000001
+#define EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR 0x00000002
+#define EGL_OPENGL_ES3_BIT_KHR 0x00000040
+#endif /* EGL_KHR_create_context */
+
+#ifndef EGL_KHR_create_context_no_error
+#define EGL_KHR_create_context_no_error 1
+#define EGL_CONTEXT_OPENGL_NO_ERROR_KHR 0x31B3
+#endif /* EGL_KHR_create_context_no_error */
+
+#ifndef EGL_KHR_debug
+#define EGL_KHR_debug 1
+typedef void *EGLLabelKHR;
+typedef void *EGLObjectKHR;
+typedef void (EGLAPIENTRY *EGLDEBUGPROCKHR)(EGLenum error,const char *command,EGLint messageType,EGLLabelKHR threadLabel,EGLLabelKHR objectLabel,const char* message);
+#define EGL_OBJECT_THREAD_KHR 0x33B0
+#define EGL_OBJECT_DISPLAY_KHR 0x33B1
+#define EGL_OBJECT_CONTEXT_KHR 0x33B2
+#define EGL_OBJECT_SURFACE_KHR 0x33B3
+#define EGL_OBJECT_IMAGE_KHR 0x33B4
+#define EGL_OBJECT_SYNC_KHR 0x33B5
+#define EGL_OBJECT_STREAM_KHR 0x33B6
+#define EGL_DEBUG_MSG_CRITICAL_KHR 0x33B9
+#define EGL_DEBUG_MSG_ERROR_KHR 0x33BA
+#define EGL_DEBUG_MSG_WARN_KHR 0x33BB
+#define EGL_DEBUG_MSG_INFO_KHR 0x33BC
+#define EGL_DEBUG_CALLBACK_KHR 0x33B8
+typedef EGLint (EGLAPIENTRYP PFNEGLDEBUGMESSAGECONTROLKHRPROC) (EGLDEBUGPROCKHR callback, const EGLAttrib *attrib_list);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYDEBUGKHRPROC) (EGLint attribute, EGLAttrib *value);
+typedef EGLint (EGLAPIENTRYP PFNEGLLABELOBJECTKHRPROC) (EGLDisplay display, EGLenum objectType, EGLObjectKHR object, EGLLabelKHR label);
#ifdef EGL_EGLEXT_PROTOTYPES
-EGLAPI EGLBoolean EGLAPIENTRY eglLockSurfaceKHR (EGLDisplay display, EGLSurface surface, const EGLint *attrib_list);
-EGLAPI EGLBoolean EGLAPIENTRY eglUnlockSurfaceKHR (EGLDisplay display, EGLSurface surface);
-#endif /* EGL_EGLEXT_PROTOTYPES */
-typedef EGLBoolean (EGLAPIENTRYP PFNEGLLOCKSURFACEKHRPROC) (EGLDisplay display, EGLSurface surface, const EGLint *attrib_list);
-typedef EGLBoolean (EGLAPIENTRYP PFNEGLUNLOCKSURFACEKHRPROC) (EGLDisplay display, EGLSurface surface);
+EGLAPI EGLint EGLAPIENTRY eglDebugMessageControlKHR (EGLDEBUGPROCKHR callback, const EGLAttrib *attrib_list);
+EGLAPI EGLBoolean EGLAPIENTRY eglQueryDebugKHR (EGLint attribute, EGLAttrib *value);
+EGLAPI EGLint EGLAPIENTRY eglLabelObjectKHR (EGLDisplay display, EGLenum objectType, EGLObjectKHR object, EGLLabelKHR label);
#endif
+#endif /* EGL_KHR_debug */
-#ifndef EGL_KHR_image
-#define EGL_KHR_image 1
-#define EGL_NATIVE_PIXMAP_KHR 0x30B0 /* eglCreateImageKHR target */
-typedef void *EGLImageKHR;
-#define EGL_NO_IMAGE_KHR EGL_CAST(EGLImageKHR, 0)
+#ifndef EGL_KHR_display_reference
+#define EGL_KHR_display_reference 1
+#define EGL_TRACK_REFERENCES_KHR 0x3352
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYDISPLAYATTRIBKHRPROC) (EGLDisplay dpy, EGLint name, EGLAttrib *value);
#ifdef EGL_EGLEXT_PROTOTYPES
-EGLAPI EGLImageKHR EGLAPIENTRY eglCreateImageKHR (EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list);
-EGLAPI EGLBoolean EGLAPIENTRY eglDestroyImageKHR (EGLDisplay dpy, EGLImageKHR image);
-#endif /* EGL_EGLEXT_PROTOTYPES */
-typedef EGLImageKHR (EGLAPIENTRYP PFNEGLCREATEIMAGEKHRPROC) (EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list);
-typedef EGLBoolean (EGLAPIENTRYP PFNEGLDESTROYIMAGEKHRPROC) (EGLDisplay dpy, EGLImageKHR image);
+EGLAPI EGLBoolean EGLAPIENTRY eglQueryDisplayAttribKHR (EGLDisplay dpy, EGLint name, EGLAttrib *value);
#endif
+#endif /* EGL_KHR_display_reference */
-#ifndef EGL_KHR_vg_parent_image
-#define EGL_KHR_vg_parent_image 1
-#define EGL_VG_PARENT_IMAGE_KHR 0x30BA /* eglCreateImageKHR target */
+#ifndef EGL_KHR_fence_sync
+#define EGL_KHR_fence_sync 1
+typedef khronos_utime_nanoseconds_t EGLTimeKHR;
+#ifdef KHRONOS_SUPPORT_INT64
+#define EGL_SYNC_PRIOR_COMMANDS_COMPLETE_KHR 0x30F0
+#define EGL_SYNC_CONDITION_KHR 0x30F8
+#define EGL_SYNC_FENCE_KHR 0x30F9
+typedef EGLSyncKHR (EGLAPIENTRYP PFNEGLCREATESYNCKHRPROC) (EGLDisplay dpy, EGLenum type, const EGLint *attrib_list);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLDESTROYSYNCKHRPROC) (EGLDisplay dpy, EGLSyncKHR sync);
+typedef EGLint (EGLAPIENTRYP PFNEGLCLIENTWAITSYNCKHRPROC) (EGLDisplay dpy, EGLSyncKHR sync, EGLint flags, EGLTimeKHR timeout);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLGETSYNCATTRIBKHRPROC) (EGLDisplay dpy, EGLSyncKHR sync, EGLint attribute, EGLint *value);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLSyncKHR EGLAPIENTRY eglCreateSyncKHR (EGLDisplay dpy, EGLenum type, const EGLint *attrib_list);
+EGLAPI EGLBoolean EGLAPIENTRY eglDestroySyncKHR (EGLDisplay dpy, EGLSyncKHR sync);
+EGLAPI EGLint EGLAPIENTRY eglClientWaitSyncKHR (EGLDisplay dpy, EGLSyncKHR sync, EGLint flags, EGLTimeKHR timeout);
+EGLAPI EGLBoolean EGLAPIENTRY eglGetSyncAttribKHR (EGLDisplay dpy, EGLSyncKHR sync, EGLint attribute, EGLint *value);
#endif
+#endif /* KHRONOS_SUPPORT_INT64 */
+#endif /* EGL_KHR_fence_sync */
-#ifndef EGL_KHR_gl_texture_2D_image
-#define EGL_KHR_gl_texture_2D_image 1
-#define EGL_GL_TEXTURE_2D_KHR 0x30B1 /* eglCreateImageKHR target */
-#define EGL_GL_TEXTURE_LEVEL_KHR 0x30BC /* eglCreateImageKHR attribute */
-#endif
-
-#ifndef EGL_KHR_gl_texture_cubemap_image
-#define EGL_KHR_gl_texture_cubemap_image 1
-#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X_KHR 0x30B3 /* eglCreateImageKHR target */
-#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X_KHR 0x30B4 /* eglCreateImageKHR target */
-#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y_KHR 0x30B5 /* eglCreateImageKHR target */
-#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_KHR 0x30B6 /* eglCreateImageKHR target */
-#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z_KHR 0x30B7 /* eglCreateImageKHR target */
-#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_KHR 0x30B8 /* eglCreateImageKHR target */
-#endif
-
-#ifndef EGL_KHR_gl_texture_3D_image
-#define EGL_KHR_gl_texture_3D_image 1
-#define EGL_GL_TEXTURE_3D_KHR 0x30B2 /* eglCreateImageKHR target */
-#define EGL_GL_TEXTURE_ZOFFSET_KHR 0x30BD /* eglCreateImageKHR attribute */
-#endif
+#ifndef EGL_KHR_get_all_proc_addresses
+#define EGL_KHR_get_all_proc_addresses 1
+#endif /* EGL_KHR_get_all_proc_addresses */
#ifndef EGL_KHR_gl_colorspace
#define EGL_KHR_gl_colorspace 1
#define EGL_GL_COLORSPACE_KHR 0x309D
#define EGL_GL_COLORSPACE_SRGB_KHR 0x3089
#define EGL_GL_COLORSPACE_LINEAR_KHR 0x308A
-#endif
+#endif /* EGL_KHR_gl_colorspace */
#ifndef EGL_KHR_gl_renderbuffer_image
#define EGL_KHR_gl_renderbuffer_image 1
-#define EGL_GL_RENDERBUFFER_KHR 0x30B9 /* eglCreateImageKHR target */
-#endif
+#define EGL_GL_RENDERBUFFER_KHR 0x30B9
+#endif /* EGL_KHR_gl_renderbuffer_image */
-#if KHRONOS_SUPPORT_INT64 /* EGLTimeKHR requires 64-bit uint support */
-#ifndef EGL_KHR_reusable_sync
-#define EGL_KHR_reusable_sync 1
+#ifndef EGL_KHR_gl_texture_2D_image
+#define EGL_KHR_gl_texture_2D_image 1
+#define EGL_GL_TEXTURE_2D_KHR 0x30B1
+#define EGL_GL_TEXTURE_LEVEL_KHR 0x30BC
+#endif /* EGL_KHR_gl_texture_2D_image */
-typedef void* EGLSyncKHR;
-typedef khronos_utime_nanoseconds_t EGLTimeKHR;
+#ifndef EGL_KHR_gl_texture_3D_image
+#define EGL_KHR_gl_texture_3D_image 1
+#define EGL_GL_TEXTURE_3D_KHR 0x30B2
+#define EGL_GL_TEXTURE_ZOFFSET_KHR 0x30BD
+#endif /* EGL_KHR_gl_texture_3D_image */
-#define EGL_SYNC_STATUS_KHR 0x30F1
-#define EGL_SIGNALED_KHR 0x30F2
-#define EGL_UNSIGNALED_KHR 0x30F3
-#define EGL_TIMEOUT_EXPIRED_KHR 0x30F5
-#define EGL_CONDITION_SATISFIED_KHR 0x30F6
-#define EGL_SYNC_TYPE_KHR 0x30F7
-#define EGL_SYNC_REUSABLE_KHR 0x30FA
-#define EGL_SYNC_FLUSH_COMMANDS_BIT_KHR 0x0001 /* eglClientWaitSyncKHR <flags> bitfield */
-#define EGL_FOREVER_KHR 0xFFFFFFFFFFFFFFFFull
-#define EGL_NO_SYNC_KHR EGL_CAST(EGLSyncKHR, 0)
+#ifndef EGL_KHR_gl_texture_cubemap_image
+#define EGL_KHR_gl_texture_cubemap_image 1
+#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X_KHR 0x30B3
+#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X_KHR 0x30B4
+#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y_KHR 0x30B5
+#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_KHR 0x30B6
+#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z_KHR 0x30B7
+#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_KHR 0x30B8
+#endif /* EGL_KHR_gl_texture_cubemap_image */
+
+#ifndef EGL_KHR_image
+#define EGL_KHR_image 1
+typedef void *EGLImageKHR;
+#define EGL_NATIVE_PIXMAP_KHR 0x30B0
+#define EGL_NO_IMAGE_KHR EGL_CAST(EGLImageKHR,0)
+typedef EGLImageKHR (EGLAPIENTRYP PFNEGLCREATEIMAGEKHRPROC) (EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLDESTROYIMAGEKHRPROC) (EGLDisplay dpy, EGLImageKHR image);
#ifdef EGL_EGLEXT_PROTOTYPES
-EGLAPI EGLSyncKHR EGLAPIENTRY eglCreateSyncKHR(EGLDisplay dpy, EGLenum type, const EGLint *attrib_list);
-EGLAPI EGLBoolean EGLAPIENTRY eglDestroySyncKHR(EGLDisplay dpy, EGLSyncKHR sync);
-EGLAPI EGLint EGLAPIENTRY eglClientWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags, EGLTimeKHR timeout);
-EGLAPI EGLBoolean EGLAPIENTRY eglSignalSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLenum mode);
-EGLAPI EGLBoolean EGLAPIENTRY eglGetSyncAttribKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint attribute, EGLint *value);
-#endif /* EGL_EGLEXT_PROTOTYPES */
-typedef EGLSyncKHR (EGLAPIENTRYP PFNEGLCREATESYNCKHRPROC) (EGLDisplay dpy, EGLenum type, const EGLint *attrib_list);
-typedef EGLBoolean (EGLAPIENTRYP PFNEGLDESTROYSYNCKHRPROC) (EGLDisplay dpy, EGLSyncKHR sync);
-typedef EGLint (EGLAPIENTRYP PFNEGLCLIENTWAITSYNCKHRPROC) (EGLDisplay dpy, EGLSyncKHR sync, EGLint flags, EGLTimeKHR timeout);
-typedef EGLBoolean (EGLAPIENTRYP PFNEGLSIGNALSYNCKHRPROC) (EGLDisplay dpy, EGLSyncKHR sync, EGLenum mode);
-typedef EGLBoolean (EGLAPIENTRYP PFNEGLGETSYNCATTRIBKHRPROC) (EGLDisplay dpy, EGLSyncKHR sync, EGLint attribute, EGLint *value);
+EGLAPI EGLImageKHR EGLAPIENTRY eglCreateImageKHR (EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list);
+EGLAPI EGLBoolean EGLAPIENTRY eglDestroyImageKHR (EGLDisplay dpy, EGLImageKHR image);
#endif
-#endif
+#endif /* EGL_KHR_image */
#ifndef EGL_KHR_image_base
#define EGL_KHR_image_base 1
-/* Most interfaces defined by EGL_KHR_image_pixmap above */
-#define EGL_IMAGE_PRESERVED_KHR 0x30D2 /* eglCreateImageKHR attribute */
-#endif
+#define EGL_IMAGE_PRESERVED_KHR 0x30D2
+#endif /* EGL_KHR_image_base */
#ifndef EGL_KHR_image_pixmap
#define EGL_KHR_image_pixmap 1
-/* Interfaces defined by EGL_KHR_image above */
-#endif
+#endif /* EGL_KHR_image_pixmap */
-#ifndef EGL_IMG_context_priority
-#define EGL_IMG_context_priority 1
-#define EGL_CONTEXT_PRIORITY_LEVEL_IMG 0x3100
-#define EGL_CONTEXT_PRIORITY_HIGH_IMG 0x3101
-#define EGL_CONTEXT_PRIORITY_MEDIUM_IMG 0x3102
-#define EGL_CONTEXT_PRIORITY_LOW_IMG 0x3103
+#ifndef EGL_KHR_lock_surface
+#define EGL_KHR_lock_surface 1
+#define EGL_READ_SURFACE_BIT_KHR 0x0001
+#define EGL_WRITE_SURFACE_BIT_KHR 0x0002
+#define EGL_LOCK_SURFACE_BIT_KHR 0x0080
+#define EGL_OPTIMAL_FORMAT_BIT_KHR 0x0100
+#define EGL_MATCH_FORMAT_KHR 0x3043
+#define EGL_FORMAT_RGB_565_EXACT_KHR 0x30C0
+#define EGL_FORMAT_RGB_565_KHR 0x30C1
+#define EGL_FORMAT_RGBA_8888_EXACT_KHR 0x30C2
+#define EGL_FORMAT_RGBA_8888_KHR 0x30C3
+#define EGL_MAP_PRESERVE_PIXELS_KHR 0x30C4
+#define EGL_LOCK_USAGE_HINT_KHR 0x30C5
+#define EGL_BITMAP_POINTER_KHR 0x30C6
+#define EGL_BITMAP_PITCH_KHR 0x30C7
+#define EGL_BITMAP_ORIGIN_KHR 0x30C8
+#define EGL_BITMAP_PIXEL_RED_OFFSET_KHR 0x30C9
+#define EGL_BITMAP_PIXEL_GREEN_OFFSET_KHR 0x30CA
+#define EGL_BITMAP_PIXEL_BLUE_OFFSET_KHR 0x30CB
+#define EGL_BITMAP_PIXEL_ALPHA_OFFSET_KHR 0x30CC
+#define EGL_BITMAP_PIXEL_LUMINANCE_OFFSET_KHR 0x30CD
+#define EGL_LOWER_LEFT_KHR 0x30CE
+#define EGL_UPPER_LEFT_KHR 0x30CF
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLLOCKSURFACEKHRPROC) (EGLDisplay dpy, EGLSurface surface, const EGLint *attrib_list);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLUNLOCKSURFACEKHRPROC) (EGLDisplay dpy, EGLSurface surface);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglLockSurfaceKHR (EGLDisplay dpy, EGLSurface surface, const EGLint *attrib_list);
+EGLAPI EGLBoolean EGLAPIENTRY eglUnlockSurfaceKHR (EGLDisplay dpy, EGLSurface surface);
#endif
+#endif /* EGL_KHR_lock_surface */
#ifndef EGL_KHR_lock_surface2
#define EGL_KHR_lock_surface2 1
-#define EGL_BITMAP_PIXEL_SIZE_KHR 0x3110
+#define EGL_BITMAP_PIXEL_SIZE_KHR 0x3110
+#endif /* EGL_KHR_lock_surface2 */
+
+#ifndef EGL_KHR_lock_surface3
+#define EGL_KHR_lock_surface3 1
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYSURFACE64KHRPROC) (EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLAttribKHR *value);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglQuerySurface64KHR (EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLAttribKHR *value);
#endif
+#endif /* EGL_KHR_lock_surface3 */
+
+#ifndef EGL_KHR_mutable_render_buffer
+#define EGL_KHR_mutable_render_buffer 1
+#define EGL_MUTABLE_RENDER_BUFFER_BIT_KHR 0x1000
+#endif /* EGL_KHR_mutable_render_buffer */
+
+#ifndef EGL_KHR_no_config_context
+#define EGL_KHR_no_config_context 1
+#define EGL_NO_CONFIG_KHR EGL_CAST(EGLConfig,0)
+#endif /* EGL_KHR_no_config_context */
#ifndef EGL_KHR_partial_update
#define EGL_KHR_partial_update 1
@@ -192,274 +285,161 @@
#endif
#endif /* EGL_KHR_partial_update */
-#ifndef EGL_NV_coverage_sample
-#define EGL_NV_coverage_sample 1
-#define EGL_COVERAGE_BUFFERS_NV 0x30E0
-#define EGL_COVERAGE_SAMPLES_NV 0x30E1
-#endif
+#ifndef EGL_KHR_platform_android
+#define EGL_KHR_platform_android 1
+#define EGL_PLATFORM_ANDROID_KHR 0x3141
+#endif /* EGL_KHR_platform_android */
-#ifndef EGL_NV_depth_nonlinear
-#define EGL_NV_depth_nonlinear 1
-#define EGL_DEPTH_ENCODING_NV 0x30E2
-#define EGL_DEPTH_ENCODING_NONE_NV 0
-#define EGL_DEPTH_ENCODING_NONLINEAR_NV 0x30E3
-#endif
+#ifndef EGL_KHR_platform_gbm
+#define EGL_KHR_platform_gbm 1
+#define EGL_PLATFORM_GBM_KHR 0x31D7
+#endif /* EGL_KHR_platform_gbm */
-#if KHRONOS_SUPPORT_INT64 /* EGLTimeNV requires 64-bit uint support */
-#ifndef EGL_NV_sync
-#define EGL_NV_sync 1
-#define EGL_SYNC_PRIOR_COMMANDS_COMPLETE_NV 0x30E6
-#define EGL_SYNC_STATUS_NV 0x30E7
-#define EGL_SIGNALED_NV 0x30E8
-#define EGL_UNSIGNALED_NV 0x30E9
-#define EGL_SYNC_FLUSH_COMMANDS_BIT_NV 0x0001
-#define EGL_FOREVER_NV 0xFFFFFFFFFFFFFFFFull
-#define EGL_ALREADY_SIGNALED_NV 0x30EA
-#define EGL_TIMEOUT_EXPIRED_NV 0x30EB
-#define EGL_CONDITION_SATISFIED_NV 0x30EC
-#define EGL_SYNC_TYPE_NV 0x30ED
-#define EGL_SYNC_CONDITION_NV 0x30EE
-#define EGL_SYNC_FENCE_NV 0x30EF
-#define EGL_NO_SYNC_NV EGL_CAST(EGLSyncNV, 0)
-typedef void* EGLSyncNV;
-typedef khronos_utime_nanoseconds_t EGLTimeNV;
+#ifndef EGL_KHR_platform_wayland
+#define EGL_KHR_platform_wayland 1
+#define EGL_PLATFORM_WAYLAND_KHR 0x31D8
+#endif /* EGL_KHR_platform_wayland */
+
+#ifndef EGL_KHR_platform_x11
+#define EGL_KHR_platform_x11 1
+#define EGL_PLATFORM_X11_KHR 0x31D5
+#define EGL_PLATFORM_X11_SCREEN_KHR 0x31D6
+#endif /* EGL_KHR_platform_x11 */
+
+#ifndef EGL_KHR_reusable_sync
+#define EGL_KHR_reusable_sync 1
+#ifdef KHRONOS_SUPPORT_INT64
+#define EGL_SYNC_STATUS_KHR 0x30F1
+#define EGL_SIGNALED_KHR 0x30F2
+#define EGL_UNSIGNALED_KHR 0x30F3
+#define EGL_TIMEOUT_EXPIRED_KHR 0x30F5
+#define EGL_CONDITION_SATISFIED_KHR 0x30F6
+#define EGL_SYNC_TYPE_KHR 0x30F7
+#define EGL_SYNC_REUSABLE_KHR 0x30FA
+#define EGL_SYNC_FLUSH_COMMANDS_BIT_KHR 0x0001
+#define EGL_FOREVER_KHR 0xFFFFFFFFFFFFFFFFull
+#define EGL_NO_SYNC_KHR EGL_CAST(EGLSyncKHR,0)
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLSIGNALSYNCKHRPROC) (EGLDisplay dpy, EGLSyncKHR sync, EGLenum mode);
#ifdef EGL_EGLEXT_PROTOTYPES
-EGLAPI EGLSyncNV EGLAPIENTRY eglCreateFenceSyncNV (EGLDisplay dpy, EGLenum condition, const EGLint *attrib_list);
-EGLAPI EGLBoolean EGLAPIENTRY eglDestroySyncNV (EGLSyncNV sync);
-EGLAPI EGLBoolean EGLAPIENTRY eglFenceNV (EGLSyncNV sync);
-EGLAPI EGLint EGLAPIENTRY eglClientWaitSyncNV (EGLSyncNV sync, EGLint flags, EGLTimeNV timeout);
-EGLAPI EGLBoolean EGLAPIENTRY eglSignalSyncNV (EGLSyncNV sync, EGLenum mode);
-EGLAPI EGLBoolean EGLAPIENTRY eglGetSyncAttribNV (EGLSyncNV sync, EGLint attribute, EGLint *value);
-#endif /* EGL_EGLEXT_PROTOTYPES */
-typedef EGLSyncNV (EGLAPIENTRYP PFNEGLCREATEFENCESYNCNVPROC) (EGLDisplay dpy, EGLenum condition, const EGLint *attrib_list);
-typedef EGLBoolean (EGLAPIENTRYP PFNEGLDESTROYSYNCNVPROC) (EGLSyncNV sync);
-typedef EGLBoolean (EGLAPIENTRYP PFNEGLFENCENVPROC) (EGLSyncNV sync);
-typedef EGLint (EGLAPIENTRYP PFNEGLCLIENTWAITSYNCNVPROC) (EGLSyncNV sync, EGLint flags, EGLTimeNV timeout);
-typedef EGLBoolean (EGLAPIENTRYP PFNEGLSIGNALSYNCNVPROC) (EGLSyncNV sync, EGLenum mode);
-typedef EGLBoolean (EGLAPIENTRYP PFNEGLGETSYNCATTRIBNVPROC) (EGLSyncNV sync, EGLint attribute, EGLint *value);
+EGLAPI EGLBoolean EGLAPIENTRY eglSignalSyncKHR (EGLDisplay dpy, EGLSyncKHR sync, EGLenum mode);
#endif
-#endif
+#endif /* KHRONOS_SUPPORT_INT64 */
+#endif /* EGL_KHR_reusable_sync */
-#if KHRONOS_SUPPORT_INT64 /* Dependent on EGL_KHR_reusable_sync which requires 64-bit uint support */
-#ifndef EGL_KHR_fence_sync
-#define EGL_KHR_fence_sync 1
-/* Reuses most tokens and entry points from EGL_KHR_reusable_sync */
-#define EGL_SYNC_PRIOR_COMMANDS_COMPLETE_KHR 0x30F0
-#define EGL_SYNC_CONDITION_KHR 0x30F8
-#define EGL_SYNC_FENCE_KHR 0x30F9
-#endif
-#endif
-
-#ifndef EGL_HI_clientpixmap
-#define EGL_HI_clientpixmap 1
-
-/* Surface Attribute */
-#define EGL_CLIENT_PIXMAP_POINTER_HI 0x8F74
-/*
- * Structure representing a client pixmap
- * (pixmap's data is in client-space memory).
- */
-struct EGLClientPixmapHI
-{
- void* pData;
- EGLint iWidth;
- EGLint iHeight;
- EGLint iStride;
-};
-#ifdef EGL_EGLEXT_PROTOTYPES
-EGLAPI EGLSurface EGLAPIENTRY eglCreatePixmapSurfaceHI(EGLDisplay dpy, EGLConfig config, struct EGLClientPixmapHI* pixmap);
-#endif /* EGL_EGLEXT_PROTOTYPES */
-typedef EGLSurface (EGLAPIENTRYP PFNEGLCREATEPIXMAPSURFACEHIPROC) (EGLDisplay dpy, EGLConfig config, struct EGLClientPixmapHI* pixmap);
-#endif /* EGL_HI_clientpixmap */
-
-#ifndef EGL_HI_colorformats
-#define EGL_HI_colorformats 1
-/* Config Attribute */
-#define EGL_COLOR_FORMAT_HI 0x8F70
-/* Color Formats */
-#define EGL_COLOR_RGB_HI 0x8F71
-#define EGL_COLOR_RGBA_HI 0x8F72
-#define EGL_COLOR_ARGB_HI 0x8F73
-#endif /* EGL_HI_colorformats */
-
-#ifndef EGL_MESA_drm_image
-#define EGL_MESA_drm_image 1
-#define EGL_DRM_BUFFER_FORMAT_MESA 0x31D0 /* CreateDRMImageMESA attribute */
-#define EGL_DRM_BUFFER_USE_MESA 0x31D1 /* CreateDRMImageMESA attribute */
-#define EGL_DRM_BUFFER_FORMAT_ARGB32_MESA 0x31D2 /* EGL_IMAGE_FORMAT_MESA attribute value */
-#define EGL_DRM_BUFFER_MESA 0x31D3 /* eglCreateImageKHR target */
-#define EGL_DRM_BUFFER_STRIDE_MESA 0x31D4
-#define EGL_DRM_BUFFER_USE_SCANOUT_MESA 0x00000001 /* EGL_DRM_BUFFER_USE_MESA bits */
-#define EGL_DRM_BUFFER_USE_SHARE_MESA 0x00000002 /* EGL_DRM_BUFFER_USE_MESA bits */
-#ifdef EGL_EGLEXT_PROTOTYPES
-EGLAPI EGLImageKHR EGLAPIENTRY eglCreateDRMImageMESA (EGLDisplay dpy, const EGLint *attrib_list);
-EGLAPI EGLBoolean EGLAPIENTRY eglExportDRMImageMESA (EGLDisplay dpy, EGLImageKHR image, EGLint *name, EGLint *handle, EGLint *stride);
-#endif /* EGL_EGLEXT_PROTOTYPES */
-typedef EGLImageKHR (EGLAPIENTRYP PFNEGLCREATEDRMIMAGEMESAPROC) (EGLDisplay dpy, const EGLint *attrib_list);
-typedef EGLBoolean (EGLAPIENTRYP PFNEGLEXPORTDRMIMAGEMESAPROC) (EGLDisplay dpy, EGLImageKHR image, EGLint *name, EGLint *handle, EGLint *stride);
-#endif
-
-#ifndef EGL_NV_post_sub_buffer
-#define EGL_NV_post_sub_buffer 1
-#define EGL_POST_SUB_BUFFER_SUPPORTED_NV 0x30BE
-#ifdef EGL_EGLEXT_PROTOTYPES
-EGLAPI EGLBoolean EGLAPIENTRY eglPostSubBufferNV (EGLDisplay dpy, EGLSurface surface, EGLint x, EGLint y, EGLint width, EGLint height);
-#endif /* EGL_EGLEXT_PROTOTYPES */
-typedef EGLBoolean (EGLAPIENTRYP PFNEGLPOSTSUBBUFFERNVPROC) (EGLDisplay dpy, EGLSurface surface, EGLint x, EGLint y, EGLint width, EGLint height);
-#endif
-
-#ifndef EGL_ANGLE_query_surface_pointer
-#define EGL_ANGLE_query_surface_pointer 1
-#ifdef EGL_EGLEXT_PROTOTYPES
-EGLAPI EGLBoolean eglQuerySurfacePointerANGLE(EGLDisplay dpy, EGLSurface surface, EGLint attribute, void **value);
-#endif
-typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYSURFACEPOINTERANGLEPROC) (EGLDisplay dpy, EGLSurface surface, EGLint attribute, void **value);
-#endif
-
-#ifndef EGL_ANGLE_surface_d3d_texture_2d_share_handle
-#define EGL_ANGLE_surface_d3d_texture_2d_share_handle 1
-#define EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE 0x3200
-#endif
-
-#ifndef EGL_NV_coverage_sample_resolve
-#define EGL_NV_coverage_sample_resolve 1
-#define EGL_COVERAGE_SAMPLE_RESOLVE_NV 0x3131
-#define EGL_COVERAGE_SAMPLE_RESOLVE_DEFAULT_NV 0x3132
-#define EGL_COVERAGE_SAMPLE_RESOLVE_NONE_NV 0x3133
-#endif
-
-#if KHRONOS_SUPPORT_INT64 /* EGLuint64NV requires 64-bit uint support */
-#ifndef EGL_NV_system_time
-#define EGL_NV_system_time 1
-typedef khronos_utime_nanoseconds_t EGLuint64NV;
-#ifdef EGL_EGLEXT_PROTOTYPES
-EGLAPI EGLuint64NV EGLAPIENTRY eglGetSystemTimeFrequencyNV(void);
-EGLAPI EGLuint64NV EGLAPIENTRY eglGetSystemTimeNV(void);
-#endif /* EGL_EGLEXT_PROTOTYPES */
-typedef EGLuint64NV (EGLAPIENTRYP PFNEGLGETSYSTEMTIMEFREQUENCYNVPROC) (void);
-typedef EGLuint64NV (EGLAPIENTRYP PFNEGLGETSYSTEMTIMENVPROC) (void);
-#endif
-#endif
-
-#if KHRONOS_SUPPORT_INT64 /* EGLuint64KHR requires 64-bit uint support */
#ifndef EGL_KHR_stream
#define EGL_KHR_stream 1
-typedef void* EGLStreamKHR;
+typedef void *EGLStreamKHR;
typedef khronos_uint64_t EGLuint64KHR;
-#define EGL_NO_STREAM_KHR EGL_CAST(EGLStreamKHR, 0)
-#define EGL_CONSUMER_LATENCY_USEC_KHR 0x3210
-#define EGL_PRODUCER_FRAME_KHR 0x3212
-#define EGL_CONSUMER_FRAME_KHR 0x3213
-#define EGL_STREAM_STATE_KHR 0x3214
-#define EGL_STREAM_STATE_CREATED_KHR 0x3215
-#define EGL_STREAM_STATE_CONNECTING_KHR 0x3216
-#define EGL_STREAM_STATE_EMPTY_KHR 0x3217
-#define EGL_STREAM_STATE_NEW_FRAME_AVAILABLE_KHR 0x3218
-#define EGL_STREAM_STATE_OLD_FRAME_AVAILABLE_KHR 0x3219
-#define EGL_STREAM_STATE_DISCONNECTED_KHR 0x321A
-#define EGL_BAD_STREAM_KHR 0x321B
-#define EGL_BAD_STATE_KHR 0x321C
+#ifdef KHRONOS_SUPPORT_INT64
+#define EGL_NO_STREAM_KHR EGL_CAST(EGLStreamKHR,0)
+#define EGL_CONSUMER_LATENCY_USEC_KHR 0x3210
+#define EGL_PRODUCER_FRAME_KHR 0x3212
+#define EGL_CONSUMER_FRAME_KHR 0x3213
+#define EGL_STREAM_STATE_KHR 0x3214
+#define EGL_STREAM_STATE_CREATED_KHR 0x3215
+#define EGL_STREAM_STATE_CONNECTING_KHR 0x3216
+#define EGL_STREAM_STATE_EMPTY_KHR 0x3217
+#define EGL_STREAM_STATE_NEW_FRAME_AVAILABLE_KHR 0x3218
+#define EGL_STREAM_STATE_OLD_FRAME_AVAILABLE_KHR 0x3219
+#define EGL_STREAM_STATE_DISCONNECTED_KHR 0x321A
+#define EGL_BAD_STREAM_KHR 0x321B
+#define EGL_BAD_STATE_KHR 0x321C
+typedef EGLStreamKHR (EGLAPIENTRYP PFNEGLCREATESTREAMKHRPROC) (EGLDisplay dpy, const EGLint *attrib_list);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLDESTROYSTREAMKHRPROC) (EGLDisplay dpy, EGLStreamKHR stream);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLSTREAMATTRIBKHRPROC) (EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLint value);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYSTREAMKHRPROC) (EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLint *value);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYSTREAMU64KHRPROC) (EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLuint64KHR *value);
#ifdef EGL_EGLEXT_PROTOTYPES
-EGLAPI EGLStreamKHR EGLAPIENTRY eglCreateStreamKHR(EGLDisplay dpy, const EGLint *attrib_list);
-EGLAPI EGLBoolean EGLAPIENTRY eglDestroyStreamKHR(EGLDisplay dpy, EGLStreamKHR stream);
-EGLAPI EGLBoolean EGLAPIENTRY eglStreamAttribKHR(EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLint value);
-EGLAPI EGLBoolean EGLAPIENTRY eglQueryStreamKHR(EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLint *value);
-EGLAPI EGLBoolean EGLAPIENTRY eglQueryStreamu64KHR(EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLuint64KHR *value);
-#endif /* EGL_EGLEXT_PROTOTYPES */
-typedef EGLStreamKHR (EGLAPIENTRYP PFNEGLCREATESTREAMKHRPROC)(EGLDisplay dpy, const EGLint *attrib_list);
-typedef EGLBoolean (EGLAPIENTRYP PFNEGLDESTROYSTREAMKHRPROC)(EGLDisplay dpy, EGLStreamKHR stream);
-typedef EGLBoolean (EGLAPIENTRYP PFNEGLSTREAMATTRIBKHRPROC)(EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLint value);
-typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYSTREAMKHRPROC)(EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLint *value);
-typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYSTREAMU64KHRPROC)(EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLuint64KHR *value);
+EGLAPI EGLStreamKHR EGLAPIENTRY eglCreateStreamKHR (EGLDisplay dpy, const EGLint *attrib_list);
+EGLAPI EGLBoolean EGLAPIENTRY eglDestroyStreamKHR (EGLDisplay dpy, EGLStreamKHR stream);
+EGLAPI EGLBoolean EGLAPIENTRY eglStreamAttribKHR (EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLint value);
+EGLAPI EGLBoolean EGLAPIENTRY eglQueryStreamKHR (EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLint *value);
+EGLAPI EGLBoolean EGLAPIENTRY eglQueryStreamu64KHR (EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLuint64KHR *value);
#endif
-#endif
+#endif /* KHRONOS_SUPPORT_INT64 */
+#endif /* EGL_KHR_stream */
-#ifdef EGL_KHR_stream /* Requires KHR_stream extension */
+#ifndef EGL_KHR_stream_attrib
+#define EGL_KHR_stream_attrib 1
+#ifdef KHRONOS_SUPPORT_INT64
+typedef EGLStreamKHR (EGLAPIENTRYP PFNEGLCREATESTREAMATTRIBKHRPROC) (EGLDisplay dpy, const EGLAttrib *attrib_list);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLSETSTREAMATTRIBKHRPROC) (EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLAttrib value);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYSTREAMATTRIBKHRPROC) (EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLAttrib *value);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLSTREAMCONSUMERACQUIREATTRIBKHRPROC) (EGLDisplay dpy, EGLStreamKHR stream, const EGLAttrib *attrib_list);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLSTREAMCONSUMERRELEASEATTRIBKHRPROC) (EGLDisplay dpy, EGLStreamKHR stream, const EGLAttrib *attrib_list);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLStreamKHR EGLAPIENTRY eglCreateStreamAttribKHR (EGLDisplay dpy, const EGLAttrib *attrib_list);
+EGLAPI EGLBoolean EGLAPIENTRY eglSetStreamAttribKHR (EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLAttrib value);
+EGLAPI EGLBoolean EGLAPIENTRY eglQueryStreamAttribKHR (EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLAttrib *value);
+EGLAPI EGLBoolean EGLAPIENTRY eglStreamConsumerAcquireAttribKHR (EGLDisplay dpy, EGLStreamKHR stream, const EGLAttrib *attrib_list);
+EGLAPI EGLBoolean EGLAPIENTRY eglStreamConsumerReleaseAttribKHR (EGLDisplay dpy, EGLStreamKHR stream, const EGLAttrib *attrib_list);
+#endif
+#endif /* KHRONOS_SUPPORT_INT64 */
+#endif /* EGL_KHR_stream_attrib */
+
#ifndef EGL_KHR_stream_consumer_gltexture
#define EGL_KHR_stream_consumer_gltexture 1
-#define EGL_CONSUMER_ACQUIRE_TIMEOUT_USEC_KHR 0x321E
+#ifdef EGL_KHR_stream
+#define EGL_CONSUMER_ACQUIRE_TIMEOUT_USEC_KHR 0x321E
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLSTREAMCONSUMERGLTEXTUREEXTERNALKHRPROC) (EGLDisplay dpy, EGLStreamKHR stream);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLSTREAMCONSUMERACQUIREKHRPROC) (EGLDisplay dpy, EGLStreamKHR stream);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLSTREAMCONSUMERRELEASEKHRPROC) (EGLDisplay dpy, EGLStreamKHR stream);
#ifdef EGL_EGLEXT_PROTOTYPES
-EGLAPI EGLBoolean EGLAPIENTRY eglStreamConsumerGLTextureExternalKHR(EGLDisplay dpy, EGLStreamKHR stream);
-EGLAPI EGLBoolean EGLAPIENTRY eglStreamConsumerAcquireKHR(EGLDisplay dpy, EGLStreamKHR stream);
-EGLAPI EGLBoolean EGLAPIENTRY eglStreamConsumerReleaseKHR(EGLDisplay dpy, EGLStreamKHR stream);
-#endif /* EGL_EGLEXT_PROTOTYPES */
-typedef EGLBoolean (EGLAPIENTRYP PFNEGLSTREAMCONSUMERGLTEXTUREEXTERNALKHRPROC)(EGLDisplay dpy, EGLStreamKHR stream);
-typedef EGLBoolean (EGLAPIENTRYP PFNEGLSTREAMCONSUMERACQUIREKHRPROC)(EGLDisplay dpy, EGLStreamKHR stream);
-typedef EGLBoolean (EGLAPIENTRYP PFNEGLSTREAMCONSUMERRELEASEKHRPROC)(EGLDisplay dpy, EGLStreamKHR stream);
+EGLAPI EGLBoolean EGLAPIENTRY eglStreamConsumerGLTextureExternalKHR (EGLDisplay dpy, EGLStreamKHR stream);
+EGLAPI EGLBoolean EGLAPIENTRY eglStreamConsumerAcquireKHR (EGLDisplay dpy, EGLStreamKHR stream);
+EGLAPI EGLBoolean EGLAPIENTRY eglStreamConsumerReleaseKHR (EGLDisplay dpy, EGLStreamKHR stream);
#endif
-#endif
+#endif /* EGL_KHR_stream */
+#endif /* EGL_KHR_stream_consumer_gltexture */
-#ifdef EGL_KHR_stream /* Requires KHR_stream extension */
-#ifndef EGL_KHR_stream_producer_eglsurface
-#define EGL_KHR_stream_producer_eglsurface 1
-#define EGL_STREAM_BIT_KHR 0x0800
+#ifndef EGL_KHR_stream_cross_process_fd
+#define EGL_KHR_stream_cross_process_fd 1
+typedef int EGLNativeFileDescriptorKHR;
+#ifdef EGL_KHR_stream
+#define EGL_NO_FILE_DESCRIPTOR_KHR EGL_CAST(EGLNativeFileDescriptorKHR,-1)
+typedef EGLNativeFileDescriptorKHR (EGLAPIENTRYP PFNEGLGETSTREAMFILEDESCRIPTORKHRPROC) (EGLDisplay dpy, EGLStreamKHR stream);
+typedef EGLStreamKHR (EGLAPIENTRYP PFNEGLCREATESTREAMFROMFILEDESCRIPTORKHRPROC) (EGLDisplay dpy, EGLNativeFileDescriptorKHR file_descriptor);
#ifdef EGL_EGLEXT_PROTOTYPES
-EGLAPI EGLSurface EGLAPIENTRY eglCreateStreamProducerSurfaceKHR(EGLDisplay dpy, EGLConfig config, EGLStreamKHR stream, const EGLint *attrib_list);
-#endif /* EGL_EGLEXT_PROTOTYPES */
-typedef EGLSurface (EGLAPIENTRYP PFNEGLCREATESTREAMPRODUCERSURFACEKHRPROC)(EGLDisplay dpy, EGLConfig config, EGLStreamKHR stream, const EGLint *attrib_list);
+EGLAPI EGLNativeFileDescriptorKHR EGLAPIENTRY eglGetStreamFileDescriptorKHR (EGLDisplay dpy, EGLStreamKHR stream);
+EGLAPI EGLStreamKHR EGLAPIENTRY eglCreateStreamFromFileDescriptorKHR (EGLDisplay dpy, EGLNativeFileDescriptorKHR file_descriptor);
#endif
-#endif
+#endif /* EGL_KHR_stream */
+#endif /* EGL_KHR_stream_cross_process_fd */
-#ifdef EGL_KHR_stream /* Requires KHR_stream extension */
-#ifndef EGL_KHR_stream_producer_aldatalocator
-#define EGL_KHR_stream_producer_aldatalocator 1
-#endif
-#endif
-
-#ifdef EGL_KHR_stream /* Requires KHR_stream extension */
#ifndef EGL_KHR_stream_fifo
#define EGL_KHR_stream_fifo 1
-/* reuse EGLTimeKHR */
-#define EGL_STREAM_FIFO_LENGTH_KHR 0x31FC
-#define EGL_STREAM_TIME_NOW_KHR 0x31FD
-#define EGL_STREAM_TIME_CONSUMER_KHR 0x31FE
-#define EGL_STREAM_TIME_PRODUCER_KHR 0x31FF
+#ifdef EGL_KHR_stream
+#define EGL_STREAM_FIFO_LENGTH_KHR 0x31FC
+#define EGL_STREAM_TIME_NOW_KHR 0x31FD
+#define EGL_STREAM_TIME_CONSUMER_KHR 0x31FE
+#define EGL_STREAM_TIME_PRODUCER_KHR 0x31FF
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYSTREAMTIMEKHRPROC) (EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLTimeKHR *value);
#ifdef EGL_EGLEXT_PROTOTYPES
-EGLAPI EGLBoolean EGLAPIENTRY eglQueryStreamTimeKHR(EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLTimeKHR *value);
-#endif /* EGL_EGLEXT_PROTOTYPES */
-typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYSTREAMTIMEKHRPROC)(EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLTimeKHR *value);
+EGLAPI EGLBoolean EGLAPIENTRY eglQueryStreamTimeKHR (EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLTimeKHR *value);
#endif
-#endif
+#endif /* EGL_KHR_stream */
+#endif /* EGL_KHR_stream_fifo */
-#ifndef EGL_EXT_create_context_robustness
-#define EGL_EXT_create_context_robustness 1
-#define EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT 0x30BF
-#define EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT 0x3138
-#define EGL_NO_RESET_NOTIFICATION_EXT 0x31BE
-#define EGL_LOSE_CONTEXT_ON_RESET_EXT 0x31BF
-#endif
+#ifndef EGL_KHR_stream_producer_aldatalocator
+#define EGL_KHR_stream_producer_aldatalocator 1
+#ifdef EGL_KHR_stream
+#endif /* EGL_KHR_stream */
+#endif /* EGL_KHR_stream_producer_aldatalocator */
-#ifndef EGL_ANGLE_d3d_share_handle_client_buffer
-#define EGL_ANGLE_d3d_share_handle_client_buffer 1
-/* reuse EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE */
+#ifndef EGL_KHR_stream_producer_eglsurface
+#define EGL_KHR_stream_producer_eglsurface 1
+#ifdef EGL_KHR_stream
+#define EGL_STREAM_BIT_KHR 0x0800
+typedef EGLSurface (EGLAPIENTRYP PFNEGLCREATESTREAMPRODUCERSURFACEKHRPROC) (EGLDisplay dpy, EGLConfig config, EGLStreamKHR stream, const EGLint *attrib_list);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLSurface EGLAPIENTRY eglCreateStreamProducerSurfaceKHR (EGLDisplay dpy, EGLConfig config, EGLStreamKHR stream, const EGLint *attrib_list);
#endif
-
-#ifndef EGL_KHR_create_context
-#define EGL_KHR_create_context 1
-#define EGL_CONTEXT_MAJOR_VERSION_KHR EGL_CONTEXT_CLIENT_VERSION
-#define EGL_CONTEXT_MINOR_VERSION_KHR 0x30FB
-#define EGL_CONTEXT_FLAGS_KHR 0x30FC
-#define EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR 0x30FD
-#define EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR 0x31BD
-#define EGL_NO_RESET_NOTIFICATION_KHR 0x31BE
-#define EGL_LOSE_CONTEXT_ON_RESET_KHR 0x31BF
-#define EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR 0x00000001
-#define EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR 0x00000002
-#define EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR 0x00000004
-#define EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR 0x00000001
-#define EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR 0x00000002
-#define EGL_OPENGL_ES3_BIT_KHR 0x00000040
-#endif
-
-#ifndef EGL_KHR_create_context_no_error
-#define EGL_KHR_create_context_no_error 1
-#define EGL_CONTEXT_OPENGL_NO_ERROR_KHR 0x31B3
-#endif /* EGL_KHR_create_context_no_error */
+#endif /* EGL_KHR_stream */
+#endif /* EGL_KHR_stream_producer_eglsurface */
#ifndef EGL_KHR_surfaceless_context
#define EGL_KHR_surfaceless_context 1
-/* No tokens/entry points, just relaxes an error condition */
-#endif
+#endif /* EGL_KHR_surfaceless_context */
#ifndef EGL_KHR_swap_buffers_with_damage
#define EGL_KHR_swap_buffers_with_damage 1
@@ -469,166 +449,90 @@
#endif
#endif /* EGL_KHR_swap_buffers_with_damage */
-#ifdef EGL_KHR_stream /* Requires KHR_stream extension */
-#ifndef EGL_KHR_stream_cross_process_fd
-#define EGL_KHR_stream_cross_process_fd 1
-typedef int EGLNativeFileDescriptorKHR;
-#define EGL_NO_FILE_DESCRIPTOR_KHR EGL_CAST(EGLNativeFileDescriptorKHR, -1)
-#ifdef EGL_EGLEXT_PROTOTYPES
-EGLAPI EGLNativeFileDescriptorKHR EGLAPIENTRY eglGetStreamFileDescriptorKHR(EGLDisplay dpy, EGLStreamKHR stream);
-EGLAPI EGLStreamKHR EGLAPIENTRY eglCreateStreamFromFileDescriptorKHR(EGLDisplay dpy, EGLNativeFileDescriptorKHR file_descriptor);
-#endif /* EGL_EGLEXT_PROTOTYPES */
-typedef EGLNativeFileDescriptorKHR (EGLAPIENTRYP PFNEGLGETSTREAMFILEDESCRIPTORKHRPROC)(EGLDisplay dpy, EGLStreamKHR stream);
-typedef EGLStreamKHR (EGLAPIENTRYP PFNEGLCREATESTREAMFROMFILEDESCRIPTORKHRPROC)(EGLDisplay dpy, EGLNativeFileDescriptorKHR file_descriptor);
-#endif
-#endif
-
-#ifndef EGL_EXT_multiview_window
-#define EGL_EXT_multiview_window 1
-#define EGL_MULTIVIEW_VIEW_COUNT_EXT 0x3134
-#endif
+#ifndef EGL_KHR_vg_parent_image
+#define EGL_KHR_vg_parent_image 1
+#define EGL_VG_PARENT_IMAGE_KHR 0x30BA
+#endif /* EGL_KHR_vg_parent_image */
#ifndef EGL_KHR_wait_sync
#define EGL_KHR_wait_sync 1
+typedef EGLint (EGLAPIENTRYP PFNEGLWAITSYNCKHRPROC) (EGLDisplay dpy, EGLSyncKHR sync, EGLint flags);
#ifdef EGL_EGLEXT_PROTOTYPES
-EGLAPI EGLint EGLAPIENTRY eglWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags);
-#endif /* EGL_EGLEXT_PROTOTYPES */
-typedef EGLint (EGLAPIENTRYP PFNEGLWAITSYNCKHRPROC)(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags);
+EGLAPI EGLint EGLAPIENTRY eglWaitSyncKHR (EGLDisplay dpy, EGLSyncKHR sync, EGLint flags);
#endif
-
-#ifndef EGL_NV_post_convert_rounding
-#define EGL_NV_post_convert_rounding 1
-/* No tokens or entry points, just relaxes behavior of SwapBuffers */
-#endif
-
-#ifndef EGL_NV_native_query
-#define EGL_NV_native_query 1
-#ifdef EGL_EGLEXT_PROTOTYPES
-EGLAPI EGLBoolean EGLAPIENTRY eglQueryNativeDisplayNV( EGLDisplay dpy, EGLNativeDisplayType* display_id);
-EGLAPI EGLBoolean EGLAPIENTRY eglQueryNativeWindowNV( EGLDisplay dpy, EGLSurface surf, EGLNativeWindowType* window);
-EGLAPI EGLBoolean EGLAPIENTRY eglQueryNativePixmapNV( EGLDisplay dpy, EGLSurface surf, EGLNativePixmapType* pixmap);
-#endif /* EGL_EGLEXT_PROTOTYPES */
-typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYNATIVEDISPLAYNVPROC)(EGLDisplay dpy, EGLNativeDisplayType *display_id);
-typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYNATIVEWINDOWNVPROC)(EGLDisplay dpy, EGLSurface surf, EGLNativeWindowType *window);
-typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYNATIVEPIXMAPNVPROC)(EGLDisplay dpy, EGLSurface surf, EGLNativePixmapType *pixmap);
-#endif
-
-#ifndef EGL_NV_3dvision_surface
-#define EGL_NV_3dvision_surface 1
-#define EGL_AUTO_STEREO_NV 0x3136
-#endif
-
-#ifndef EGL_ANDROID_framebuffer_target
-#define EGL_ANDROID_framebuffer_target 1
-#define EGL_FRAMEBUFFER_TARGET_ANDROID 0x3147
-#endif
-
-#ifndef EGL_ANDROID_image_crop
-#define EGL_ANDROID_image_crop 1
-#define EGL_IMAGE_CROP_LEFT_ANDROID 0x3148
-#define EGL_IMAGE_CROP_TOP_ANDROID 0x3149
-#define EGL_IMAGE_CROP_RIGHT_ANDROID 0x314A
-#define EGL_IMAGE_CROP_BOTTOM_ANDROID 0x314B
-#endif
+#endif /* EGL_KHR_wait_sync */
#ifndef EGL_ANDROID_blob_cache
#define EGL_ANDROID_blob_cache 1
typedef khronos_ssize_t EGLsizeiANDROID;
typedef void (*EGLSetBlobFuncANDROID) (const void *key, EGLsizeiANDROID keySize, const void *value, EGLsizeiANDROID valueSize);
typedef EGLsizeiANDROID (*EGLGetBlobFuncANDROID) (const void *key, EGLsizeiANDROID keySize, void *value, EGLsizeiANDROID valueSize);
+typedef void (EGLAPIENTRYP PFNEGLSETBLOBCACHEFUNCSANDROIDPROC) (EGLDisplay dpy, EGLSetBlobFuncANDROID set, EGLGetBlobFuncANDROID get);
#ifdef EGL_EGLEXT_PROTOTYPES
-EGLAPI void EGLAPIENTRY eglSetBlobCacheFuncsANDROID(EGLDisplay dpy, EGLSetBlobFuncANDROID set, EGLGetBlobFuncANDROID get);
-#endif /* EGL_EGLEXT_PROTOTYPES */
-typedef void (EGLAPIENTRYP PFNEGLSETBLOBCACHEFUNCSANDROIDPROC)(EGLDisplay dpy, EGLSetBlobFuncANDROID set, EGLGetBlobFuncANDROID get);
+EGLAPI void EGLAPIENTRY eglSetBlobCacheFuncsANDROID (EGLDisplay dpy, EGLSetBlobFuncANDROID set, EGLGetBlobFuncANDROID get);
#endif
+#endif /* EGL_ANDROID_blob_cache */
-#ifndef EGL_ANDROID_image_native_buffer
-#define EGL_ANDROID_image_native_buffer 1
-#define EGL_NATIVE_BUFFER_ANDROID 0x3140
-#endif
-
-#ifndef EGL_ANDROID_native_fence_sync
-#define EGL_ANDROID_native_fence_sync 1
-#define EGL_SYNC_NATIVE_FENCE_ANDROID 0x3144
-#define EGL_SYNC_NATIVE_FENCE_FD_ANDROID 0x3145
-#define EGL_SYNC_NATIVE_FENCE_SIGNALED_ANDROID 0x3146
-#define EGL_NO_NATIVE_FENCE_FD_ANDROID (-1)
+#ifndef EGL_ANDROID_create_native_client_buffer
+#define EGL_ANDROID_create_native_client_buffer 1
+#define EGL_NATIVE_BUFFER_USAGE_ANDROID 0x3143
+#define EGL_NATIVE_BUFFER_USAGE_PROTECTED_BIT_ANDROID 0x00000001
+#define EGL_NATIVE_BUFFER_USAGE_RENDERBUFFER_BIT_ANDROID 0x00000002
+#define EGL_NATIVE_BUFFER_USAGE_TEXTURE_BIT_ANDROID 0x00000004
+typedef EGLClientBuffer (EGLAPIENTRYP PFNEGLCREATENATIVECLIENTBUFFERANDROIDPROC) (const EGLint *attrib_list);
#ifdef EGL_EGLEXT_PROTOTYPES
-EGLAPI EGLint EGLAPIENTRY eglDupNativeFenceFDANDROID( EGLDisplay dpy, EGLSyncKHR);
-#endif /* EGL_EGLEXT_PROTOTYPES */
-typedef EGLint (EGLAPIENTRYP PFNEGLDUPNATIVEFENCEFDANDROIDPROC)(EGLDisplay dpy, EGLSyncKHR);
+EGLAPI EGLClientBuffer EGLAPIENTRY eglCreateNativeClientBufferANDROID (const EGLint *attrib_list);
#endif
+#endif /* EGL_ANDROID_create_native_client_buffer */
-#ifndef EGL_ANDROID_recordable
-#define EGL_ANDROID_recordable 1
-#define EGL_RECORDABLE_ANDROID 0x3142
-#endif
-
-#ifndef EGL_EXT_buffer_age
-#define EGL_EXT_buffer_age 1
-#define EGL_BUFFER_AGE_EXT 0x313D
-#endif
-
-#ifndef EGL_EXT_image_dma_buf_import
-#define EGL_EXT_image_dma_buf_import 1
-#define EGL_LINUX_DMA_BUF_EXT 0x3270
-#define EGL_LINUX_DRM_FOURCC_EXT 0x3271
-#define EGL_DMA_BUF_PLANE0_FD_EXT 0x3272
-#define EGL_DMA_BUF_PLANE0_OFFSET_EXT 0x3273
-#define EGL_DMA_BUF_PLANE0_PITCH_EXT 0x3274
-#define EGL_DMA_BUF_PLANE1_FD_EXT 0x3275
-#define EGL_DMA_BUF_PLANE1_OFFSET_EXT 0x3276
-#define EGL_DMA_BUF_PLANE1_PITCH_EXT 0x3277
-#define EGL_DMA_BUF_PLANE2_FD_EXT 0x3278
-#define EGL_DMA_BUF_PLANE2_OFFSET_EXT 0x3279
-#define EGL_DMA_BUF_PLANE2_PITCH_EXT 0x327A
-#define EGL_YUV_COLOR_SPACE_HINT_EXT 0x327B
-#define EGL_SAMPLE_RANGE_HINT_EXT 0x327C
-#define EGL_YUV_CHROMA_HORIZONTAL_SITING_HINT_EXT 0x327D
-#define EGL_YUV_CHROMA_VERTICAL_SITING_HINT_EXT 0x327E
-#define EGL_ITU_REC601_EXT 0x327F
-#define EGL_ITU_REC709_EXT 0x3280
-#define EGL_ITU_REC2020_EXT 0x3281
-#define EGL_YUV_FULL_RANGE_EXT 0x3282
-#define EGL_YUV_NARROW_RANGE_EXT 0x3283
-#define EGL_YUV_CHROMA_SITING_0_EXT 0x3284
-#define EGL_YUV_CHROMA_SITING_0_5_EXT 0x3285
-#endif
-
-#ifndef EGL_ANDROID_presentation_time
-#define EGL_ANDROID_presentation_time 1
-typedef khronos_stime_nanoseconds_t EGLnsecsANDROID;
-#ifdef EGL_EGLEXT_PROTOTYPES
-EGLAPI EGLBoolean eglPresentationTimeANDROID(EGLDisplay dpy, EGLSurface sur, EGLnsecsANDROID time);
-#else
-typedef EGLBoolean (EGLAPIENTRYP PFNEGLPRESENTATIONTIMEANDROID) (EGLDisplay dpy, EGLSurface sur, EGLnsecsANDROID time);
-#endif
-#endif
-
-#ifndef EGL_ANDROID_get_native_client_buffer
-#define EGL_ANDROID_get_native_client_buffer 1
-struct AHardwareBuffer;
-#ifdef EGL_EGLEXT_PROTOTYPES
-EGLAPI EGLClientBuffer eglGetNativeClientBufferANDROID (const struct AHardwareBuffer *buffer);
-#else
-typedef EGLClientBuffer (EGLAPIENTRYP PFNEGLGETNATIVECLIENTBUFFERANDROID) (const struct AHardwareBuffer *buffer);
-#endif
-#endif
+#ifndef EGL_ANDROID_framebuffer_target
+#define EGL_ANDROID_framebuffer_target 1
+#define EGL_FRAMEBUFFER_TARGET_ANDROID 0x3147
+#endif /* EGL_ANDROID_framebuffer_target */
#ifndef EGL_ANDROID_front_buffer_auto_refresh
#define EGL_ANDROID_front_buffer_auto_refresh 1
#define EGL_FRONT_BUFFER_AUTO_REFRESH_ANDROID 0x314C
+#endif /* EGL_ANDROID_front_buffer_auto_refresh */
+
+#ifndef EGL_ANDROID_image_crop
+#define EGL_ANDROID_image_crop 1
+#define EGL_IMAGE_CROP_LEFT_ANDROID 0x3148
+#define EGL_IMAGE_CROP_TOP_ANDROID 0x3149
+#define EGL_IMAGE_CROP_RIGHT_ANDROID 0x314A
+#define EGL_IMAGE_CROP_BOTTOM_ANDROID 0x314B
#endif
+#ifndef EGL_ANDROID_image_native_buffer
+#define EGL_ANDROID_image_native_buffer 1
+#define EGL_NATIVE_BUFFER_ANDROID 0x3140
+#endif /* EGL_ANDROID_image_native_buffer */
+
#ifndef EGL_KHR_mutable_render_buffer
#define EGL_KHR_mutable_render_buffer 1
#define EGL_MUTABLE_RENDER_BUFFER_BIT_KHR 0x1000
#endif
-#ifndef EGL_KHR_no_config_context
-#define EGL_KHR_no_config_context 1
-#define EGL_NO_CONFIG_KHR EGL_CAST(EGLConfig,0)
-#endif /* EGL_KHR_no_config_context */
+#ifndef EGL_ANDROID_native_fence_sync
+#define EGL_ANDROID_native_fence_sync 1
+#define EGL_SYNC_NATIVE_FENCE_ANDROID 0x3144
+#define EGL_SYNC_NATIVE_FENCE_FD_ANDROID 0x3145
+#define EGL_SYNC_NATIVE_FENCE_SIGNALED_ANDROID 0x3146
+#define EGL_NO_NATIVE_FENCE_FD_ANDROID -1
+typedef EGLint (EGLAPIENTRYP PFNEGLDUPNATIVEFENCEFDANDROIDPROC) (EGLDisplay dpy, EGLSyncKHR sync);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLint EGLAPIENTRY eglDupNativeFenceFDANDROID (EGLDisplay dpy, EGLSyncKHR sync);
+#endif
+#endif /* EGL_ANDROID_native_fence_sync */
+
+#ifndef EGL_ANDROID_presentation_time
+#define EGL_ANDROID_presentation_time 1
+typedef khronos_stime_nanoseconds_t EGLnsecsANDROID;
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLPRESENTATIONTIMEANDROIDPROC) (EGLDisplay dpy, EGLSurface surface, EGLnsecsANDROID time);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglPresentationTimeANDROID (EGLDisplay dpy, EGLSurface surface, EGLnsecsANDROID time);
+#endif
+#endif /* EGL_ANDROID_presentation_time */
#ifndef EGL_ANDROID_get_frame_timestamps
#define EGL_ANDROID_get_frame_timestamps 1
@@ -662,6 +566,131 @@
#endif
#endif
+#ifndef EGL_ANDROID_recordable
+#define EGL_ANDROID_recordable 1
+#define EGL_RECORDABLE_ANDROID 0x3142
+#endif /* EGL_ANDROID_recordable */
+
+#ifndef EGL_ANGLE_d3d_share_handle_client_buffer
+#define EGL_ANGLE_d3d_share_handle_client_buffer 1
+#define EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE 0x3200
+#endif /* EGL_ANGLE_d3d_share_handle_client_buffer */
+
+#ifndef EGL_ANGLE_device_d3d
+#define EGL_ANGLE_device_d3d 1
+#define EGL_D3D9_DEVICE_ANGLE 0x33A0
+#define EGL_D3D11_DEVICE_ANGLE 0x33A1
+#endif /* EGL_ANGLE_device_d3d */
+
+#ifndef EGL_ANGLE_query_surface_pointer
+#define EGL_ANGLE_query_surface_pointer 1
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYSURFACEPOINTERANGLEPROC) (EGLDisplay dpy, EGLSurface surface, EGLint attribute, void **value);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglQuerySurfacePointerANGLE (EGLDisplay dpy, EGLSurface surface, EGLint attribute, void **value);
+#endif
+#endif /* EGL_ANGLE_query_surface_pointer */
+
+#ifndef EGL_ANGLE_surface_d3d_texture_2d_share_handle
+#define EGL_ANGLE_surface_d3d_texture_2d_share_handle 1
+#endif /* EGL_ANGLE_surface_d3d_texture_2d_share_handle */
+
+#ifndef EGL_ANGLE_window_fixed_size
+#define EGL_ANGLE_window_fixed_size 1
+#define EGL_FIXED_SIZE_ANGLE 0x3201
+#endif /* EGL_ANGLE_window_fixed_size */
+
+#ifndef EGL_ARM_implicit_external_sync
+#define EGL_ARM_implicit_external_sync 1
+#define EGL_SYNC_PRIOR_COMMANDS_IMPLICIT_EXTERNAL_ARM 0x328A
+#endif /* EGL_ARM_implicit_external_sync */
+
+#ifndef EGL_ARM_pixmap_multisample_discard
+#define EGL_ARM_pixmap_multisample_discard 1
+#define EGL_DISCARD_SAMPLES_ARM 0x3286
+#endif /* EGL_ARM_pixmap_multisample_discard */
+
+#ifndef EGL_EXT_bind_to_front
+#define EGL_EXT_bind_to_front 1
+#define EGL_FRONT_BUFFER_EXT 0x3464
+#endif /* EGL_EXT_bind_to_front */
+
+#ifndef EGL_EXT_buffer_age
+#define EGL_EXT_buffer_age 1
+#define EGL_BUFFER_AGE_EXT 0x313D
+#endif /* EGL_EXT_buffer_age */
+
+#ifndef EGL_EXT_client_extensions
+#define EGL_EXT_client_extensions 1
+#endif /* EGL_EXT_client_extensions */
+
+#ifndef EGL_EXT_compositor
+#define EGL_EXT_compositor 1
+#define EGL_PRIMARY_COMPOSITOR_CONTEXT_EXT 0x3460
+#define EGL_EXTERNAL_REF_ID_EXT 0x3461
+#define EGL_COMPOSITOR_DROP_NEWEST_FRAME_EXT 0x3462
+#define EGL_COMPOSITOR_KEEP_NEWEST_FRAME_EXT 0x3463
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLCOMPOSITORSETCONTEXTLISTEXTPROC) (const EGLint *external_ref_ids, EGLint num_entries);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLCOMPOSITORSETCONTEXTATTRIBUTESEXTPROC) (EGLint external_ref_id, const EGLint *context_attributes, EGLint num_entries);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLCOMPOSITORSETWINDOWLISTEXTPROC) (EGLint external_ref_id, const EGLint *external_win_ids, EGLint num_entries);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLCOMPOSITORSETWINDOWATTRIBUTESEXTPROC) (EGLint external_win_id, const EGLint *window_attributes, EGLint num_entries);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLCOMPOSITORBINDTEXWINDOWEXTPROC) (EGLint external_win_id);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLCOMPOSITORSETSIZEEXTPROC) (EGLint external_win_id, EGLint width, EGLint height);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLCOMPOSITORSWAPPOLICYEXTPROC) (EGLint external_win_id, EGLint policy);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglCompositorSetContextListEXT (const EGLint *external_ref_ids, EGLint num_entries);
+EGLAPI EGLBoolean EGLAPIENTRY eglCompositorSetContextAttributesEXT (EGLint external_ref_id, const EGLint *context_attributes, EGLint num_entries);
+EGLAPI EGLBoolean EGLAPIENTRY eglCompositorSetWindowListEXT (EGLint external_ref_id, const EGLint *external_win_ids, EGLint num_entries);
+EGLAPI EGLBoolean EGLAPIENTRY eglCompositorSetWindowAttributesEXT (EGLint external_win_id, const EGLint *window_attributes, EGLint num_entries);
+EGLAPI EGLBoolean EGLAPIENTRY eglCompositorBindTexWindowEXT (EGLint external_win_id);
+EGLAPI EGLBoolean EGLAPIENTRY eglCompositorSetSizeEXT (EGLint external_win_id, EGLint width, EGLint height);
+EGLAPI EGLBoolean EGLAPIENTRY eglCompositorSwapPolicyEXT (EGLint external_win_id, EGLint policy);
+#endif
+#endif /* EGL_EXT_compositor */
+
+#ifndef EGL_EXT_create_context_robustness
+#define EGL_EXT_create_context_robustness 1
+#define EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT 0x30BF
+#define EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT 0x3138
+#define EGL_NO_RESET_NOTIFICATION_EXT 0x31BE
+#define EGL_LOSE_CONTEXT_ON_RESET_EXT 0x31BF
+#endif /* EGL_EXT_create_context_robustness */
+
+#ifndef EGL_EXT_device_base
+#define EGL_EXT_device_base 1
+typedef void *EGLDeviceEXT;
+#define EGL_NO_DEVICE_EXT EGL_CAST(EGLDeviceEXT,0)
+#define EGL_BAD_DEVICE_EXT 0x322B
+#define EGL_DEVICE_EXT 0x322C
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYDEVICEATTRIBEXTPROC) (EGLDeviceEXT device, EGLint attribute, EGLAttrib *value);
+typedef const char *(EGLAPIENTRYP PFNEGLQUERYDEVICESTRINGEXTPROC) (EGLDeviceEXT device, EGLint name);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYDEVICESEXTPROC) (EGLint max_devices, EGLDeviceEXT *devices, EGLint *num_devices);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYDISPLAYATTRIBEXTPROC) (EGLDisplay dpy, EGLint attribute, EGLAttrib *value);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglQueryDeviceAttribEXT (EGLDeviceEXT device, EGLint attribute, EGLAttrib *value);
+EGLAPI const char *EGLAPIENTRY eglQueryDeviceStringEXT (EGLDeviceEXT device, EGLint name);
+EGLAPI EGLBoolean EGLAPIENTRY eglQueryDevicesEXT (EGLint max_devices, EGLDeviceEXT *devices, EGLint *num_devices);
+EGLAPI EGLBoolean EGLAPIENTRY eglQueryDisplayAttribEXT (EGLDisplay dpy, EGLint attribute, EGLAttrib *value);
+#endif
+#endif /* EGL_EXT_device_base */
+
+#ifndef EGL_EXT_device_drm
+#define EGL_EXT_device_drm 1
+#define EGL_DRM_DEVICE_FILE_EXT 0x3233
+#endif /* EGL_EXT_device_drm */
+
+#ifndef EGL_EXT_device_enumeration
+#define EGL_EXT_device_enumeration 1
+#endif /* EGL_EXT_device_enumeration */
+
+#ifndef EGL_EXT_device_openwf
+#define EGL_EXT_device_openwf 1
+#define EGL_OPENWF_DEVICE_ID_EXT 0x3237
+#endif /* EGL_EXT_device_openwf */
+
+#ifndef EGL_EXT_device_query
+#define EGL_EXT_device_query 1
+#endif /* EGL_EXT_device_query */
+
#ifndef EGL_EXT_gl_colorspace_bt2020_linear
#define EGL_EXT_gl_colorspace_bt2020_linear 1
#define EGL_GL_COLORSPACE_BT2020_LINEAR_EXT 0x333F
@@ -674,7 +703,7 @@
#ifndef EGL_EXT_gl_colorspace_display_p3
#define EGL_EXT_gl_colorspace_display_p3 1
-#define EGL_GL_COLORSPACE_DISPLAY_P3_EXT 0x3363
+#define EGL_GL_COLORSPACE_DISPLAY_P3_EXT 0x3363
#endif /* EGL_EXT_gl_colorspace_display_p3 */
#ifndef EGL_EXT_gl_colorspace_display_p3_linear
@@ -682,11 +711,117 @@
#define EGL_GL_COLORSPACE_DISPLAY_P3_LINEAR_EXT 0x3362
#endif /* EGL_EXT_gl_colorspace_display_p3_linear */
+#ifndef EGL_EXT_gl_colorspace_scrgb
+#define EGL_EXT_gl_colorspace_scrgb 1
+#define EGL_GL_COLORSPACE_SCRGB_EXT 0x3351
+#endif /* EGL_EXT_gl_colorspace_scrgb */
+
#ifndef EGL_EXT_gl_colorspace_scrgb_linear
#define EGL_EXT_gl_colorspace_scrgb_linear 1
#define EGL_GL_COLORSPACE_SCRGB_LINEAR_EXT 0x3350
#endif /* EGL_EXT_gl_colorspace_scrgb_linear */
+#ifndef EGL_EXT_image_dma_buf_import
+#define EGL_EXT_image_dma_buf_import 1
+#define EGL_LINUX_DMA_BUF_EXT 0x3270
+#define EGL_LINUX_DRM_FOURCC_EXT 0x3271
+#define EGL_DMA_BUF_PLANE0_FD_EXT 0x3272
+#define EGL_DMA_BUF_PLANE0_OFFSET_EXT 0x3273
+#define EGL_DMA_BUF_PLANE0_PITCH_EXT 0x3274
+#define EGL_DMA_BUF_PLANE1_FD_EXT 0x3275
+#define EGL_DMA_BUF_PLANE1_OFFSET_EXT 0x3276
+#define EGL_DMA_BUF_PLANE1_PITCH_EXT 0x3277
+#define EGL_DMA_BUF_PLANE2_FD_EXT 0x3278
+#define EGL_DMA_BUF_PLANE2_OFFSET_EXT 0x3279
+#define EGL_DMA_BUF_PLANE2_PITCH_EXT 0x327A
+#define EGL_YUV_COLOR_SPACE_HINT_EXT 0x327B
+#define EGL_SAMPLE_RANGE_HINT_EXT 0x327C
+#define EGL_YUV_CHROMA_HORIZONTAL_SITING_HINT_EXT 0x327D
+#define EGL_YUV_CHROMA_VERTICAL_SITING_HINT_EXT 0x327E
+#define EGL_ITU_REC601_EXT 0x327F
+#define EGL_ITU_REC709_EXT 0x3280
+#define EGL_ITU_REC2020_EXT 0x3281
+#define EGL_YUV_FULL_RANGE_EXT 0x3282
+#define EGL_YUV_NARROW_RANGE_EXT 0x3283
+#define EGL_YUV_CHROMA_SITING_0_EXT 0x3284
+#define EGL_YUV_CHROMA_SITING_0_5_EXT 0x3285
+#endif /* EGL_EXT_image_dma_buf_import */
+
+#ifndef EGL_EXT_image_dma_buf_import_modifiers
+#define EGL_EXT_image_dma_buf_import_modifiers 1
+#define EGL_DMA_BUF_PLANE3_FD_EXT 0x3440
+#define EGL_DMA_BUF_PLANE3_OFFSET_EXT 0x3441
+#define EGL_DMA_BUF_PLANE3_PITCH_EXT 0x3442
+#define EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT 0x3443
+#define EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT 0x3444
+#define EGL_DMA_BUF_PLANE1_MODIFIER_LO_EXT 0x3445
+#define EGL_DMA_BUF_PLANE1_MODIFIER_HI_EXT 0x3446
+#define EGL_DMA_BUF_PLANE2_MODIFIER_LO_EXT 0x3447
+#define EGL_DMA_BUF_PLANE2_MODIFIER_HI_EXT 0x3448
+#define EGL_DMA_BUF_PLANE3_MODIFIER_LO_EXT 0x3449
+#define EGL_DMA_BUF_PLANE3_MODIFIER_HI_EXT 0x344A
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYDMABUFFORMATSEXTPROC) (EGLDisplay dpy, EGLint max_formats, EGLint *formats, EGLint *num_formats);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYDMABUFMODIFIERSEXTPROC) (EGLDisplay dpy, EGLint format, EGLint max_modifiers, EGLuint64KHR *modifiers, EGLBoolean *external_only, EGLint *num_modifiers);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglQueryDmaBufFormatsEXT (EGLDisplay dpy, EGLint max_formats, EGLint *formats, EGLint *num_formats);
+EGLAPI EGLBoolean EGLAPIENTRY eglQueryDmaBufModifiersEXT (EGLDisplay dpy, EGLint format, EGLint max_modifiers, EGLuint64KHR *modifiers, EGLBoolean *external_only, EGLint *num_modifiers);
+#endif
+#endif /* EGL_EXT_image_dma_buf_import_modifiers */
+
+#ifndef EGL_EXT_image_implicit_sync_control
+#define EGL_EXT_image_implicit_sync_control 1
+#define EGL_IMPORT_SYNC_TYPE_EXT 0x3470
+#define EGL_IMPORT_IMPLICIT_SYNC_EXT 0x3471
+#define EGL_IMPORT_EXPLICIT_SYNC_EXT 0x3472
+#endif /* EGL_EXT_image_implicit_sync_control */
+
+#ifndef EGL_EXT_multiview_window
+#define EGL_EXT_multiview_window 1
+#define EGL_MULTIVIEW_VIEW_COUNT_EXT 0x3134
+#endif /* EGL_EXT_multiview_window */
+
+#ifndef EGL_EXT_output_base
+#define EGL_EXT_output_base 1
+typedef void *EGLOutputLayerEXT;
+typedef void *EGLOutputPortEXT;
+#define EGL_NO_OUTPUT_LAYER_EXT EGL_CAST(EGLOutputLayerEXT,0)
+#define EGL_NO_OUTPUT_PORT_EXT EGL_CAST(EGLOutputPortEXT,0)
+#define EGL_BAD_OUTPUT_LAYER_EXT 0x322D
+#define EGL_BAD_OUTPUT_PORT_EXT 0x322E
+#define EGL_SWAP_INTERVAL_EXT 0x322F
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLGETOUTPUTLAYERSEXTPROC) (EGLDisplay dpy, const EGLAttrib *attrib_list, EGLOutputLayerEXT *layers, EGLint max_layers, EGLint *num_layers);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLGETOUTPUTPORTSEXTPROC) (EGLDisplay dpy, const EGLAttrib *attrib_list, EGLOutputPortEXT *ports, EGLint max_ports, EGLint *num_ports);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLOUTPUTLAYERATTRIBEXTPROC) (EGLDisplay dpy, EGLOutputLayerEXT layer, EGLint attribute, EGLAttrib value);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYOUTPUTLAYERATTRIBEXTPROC) (EGLDisplay dpy, EGLOutputLayerEXT layer, EGLint attribute, EGLAttrib *value);
+typedef const char *(EGLAPIENTRYP PFNEGLQUERYOUTPUTLAYERSTRINGEXTPROC) (EGLDisplay dpy, EGLOutputLayerEXT layer, EGLint name);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLOUTPUTPORTATTRIBEXTPROC) (EGLDisplay dpy, EGLOutputPortEXT port, EGLint attribute, EGLAttrib value);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYOUTPUTPORTATTRIBEXTPROC) (EGLDisplay dpy, EGLOutputPortEXT port, EGLint attribute, EGLAttrib *value);
+typedef const char *(EGLAPIENTRYP PFNEGLQUERYOUTPUTPORTSTRINGEXTPROC) (EGLDisplay dpy, EGLOutputPortEXT port, EGLint name);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglGetOutputLayersEXT (EGLDisplay dpy, const EGLAttrib *attrib_list, EGLOutputLayerEXT *layers, EGLint max_layers, EGLint *num_layers);
+EGLAPI EGLBoolean EGLAPIENTRY eglGetOutputPortsEXT (EGLDisplay dpy, const EGLAttrib *attrib_list, EGLOutputPortEXT *ports, EGLint max_ports, EGLint *num_ports);
+EGLAPI EGLBoolean EGLAPIENTRY eglOutputLayerAttribEXT (EGLDisplay dpy, EGLOutputLayerEXT layer, EGLint attribute, EGLAttrib value);
+EGLAPI EGLBoolean EGLAPIENTRY eglQueryOutputLayerAttribEXT (EGLDisplay dpy, EGLOutputLayerEXT layer, EGLint attribute, EGLAttrib *value);
+EGLAPI const char *EGLAPIENTRY eglQueryOutputLayerStringEXT (EGLDisplay dpy, EGLOutputLayerEXT layer, EGLint name);
+EGLAPI EGLBoolean EGLAPIENTRY eglOutputPortAttribEXT (EGLDisplay dpy, EGLOutputPortEXT port, EGLint attribute, EGLAttrib value);
+EGLAPI EGLBoolean EGLAPIENTRY eglQueryOutputPortAttribEXT (EGLDisplay dpy, EGLOutputPortEXT port, EGLint attribute, EGLAttrib *value);
+EGLAPI const char *EGLAPIENTRY eglQueryOutputPortStringEXT (EGLDisplay dpy, EGLOutputPortEXT port, EGLint name);
+#endif
+#endif /* EGL_EXT_output_base */
+
+#ifndef EGL_EXT_output_drm
+#define EGL_EXT_output_drm 1
+#define EGL_DRM_CRTC_EXT 0x3234
+#define EGL_DRM_PLANE_EXT 0x3235
+#define EGL_DRM_CONNECTOR_EXT 0x3236
+#endif /* EGL_EXT_output_drm */
+
+#ifndef EGL_EXT_output_openwf
+#define EGL_EXT_output_openwf 1
+#define EGL_OPENWF_PIPELINE_ID_EXT 0x3238
+#define EGL_OPENWF_PORT_ID_EXT 0x3239
+#endif /* EGL_EXT_output_openwf */
+
#ifndef EGL_EXT_pixel_format_float
#define EGL_EXT_pixel_format_float 1
#define EGL_COLOR_COMPONENT_TYPE_EXT 0x3339
@@ -694,6 +829,57 @@
#define EGL_COLOR_COMPONENT_TYPE_FLOAT_EXT 0x333B
#endif /* EGL_EXT_pixel_format_float */
+#ifndef EGL_EXT_platform_base
+#define EGL_EXT_platform_base 1
+typedef EGLDisplay (EGLAPIENTRYP PFNEGLGETPLATFORMDISPLAYEXTPROC) (EGLenum platform, void *native_display, const EGLint *attrib_list);
+typedef EGLSurface (EGLAPIENTRYP PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC) (EGLDisplay dpy, EGLConfig config, void *native_window, const EGLint *attrib_list);
+typedef EGLSurface (EGLAPIENTRYP PFNEGLCREATEPLATFORMPIXMAPSURFACEEXTPROC) (EGLDisplay dpy, EGLConfig config, void *native_pixmap, const EGLint *attrib_list);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLDisplay EGLAPIENTRY eglGetPlatformDisplayEXT (EGLenum platform, void *native_display, const EGLint *attrib_list);
+EGLAPI EGLSurface EGLAPIENTRY eglCreatePlatformWindowSurfaceEXT (EGLDisplay dpy, EGLConfig config, void *native_window, const EGLint *attrib_list);
+EGLAPI EGLSurface EGLAPIENTRY eglCreatePlatformPixmapSurfaceEXT (EGLDisplay dpy, EGLConfig config, void *native_pixmap, const EGLint *attrib_list);
+#endif
+#endif /* EGL_EXT_platform_base */
+
+#ifndef EGL_EXT_platform_device
+#define EGL_EXT_platform_device 1
+#define EGL_PLATFORM_DEVICE_EXT 0x313F
+#endif /* EGL_EXT_platform_device */
+
+#ifndef EGL_EXT_platform_wayland
+#define EGL_EXT_platform_wayland 1
+#define EGL_PLATFORM_WAYLAND_EXT 0x31D8
+#endif /* EGL_EXT_platform_wayland */
+
+#ifndef EGL_EXT_platform_x11
+#define EGL_EXT_platform_x11 1
+#define EGL_PLATFORM_X11_EXT 0x31D5
+#define EGL_PLATFORM_X11_SCREEN_EXT 0x31D6
+#endif /* EGL_EXT_platform_x11 */
+
+#ifndef EGL_EXT_protected_content
+#define EGL_EXT_protected_content 1
+#define EGL_PROTECTED_CONTENT_EXT 0x32C0
+#endif /* EGL_EXT_protected_content */
+
+#ifndef EGL_EXT_protected_surface
+#define EGL_EXT_protected_surface 1
+#endif /* EGL_EXT_protected_surface */
+
+#ifndef EGL_EXT_stream_consumer_egloutput
+#define EGL_EXT_stream_consumer_egloutput 1
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLSTREAMCONSUMEROUTPUTEXTPROC) (EGLDisplay dpy, EGLStreamKHR stream, EGLOutputLayerEXT layer);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglStreamConsumerOutputEXT (EGLDisplay dpy, EGLStreamKHR stream, EGLOutputLayerEXT layer);
+#endif
+#endif /* EGL_EXT_stream_consumer_egloutput */
+
+#ifndef EGL_EXT_surface_CTA861_3_metadata
+#define EGL_EXT_surface_CTA861_3_metadata 1
+#define EGL_CTA861_3_MAX_CONTENT_LIGHT_LEVEL_EXT 0x3360
+#define EGL_CTA861_3_MAX_FRAME_AVERAGE_LEVEL_EXT 0x3361
+#endif /* EGL_EXT_surface_CTA861_3_metadata */
+
#ifndef EGL_EXT_surface_SMPTE2086_metadata
#define EGL_EXT_surface_SMPTE2086_metadata 1
#define EGL_SMPTE2086_DISPLAY_PRIMARY_RX_EXT 0x3341
@@ -709,8 +895,402 @@
#define EGL_METADATA_SCALING_EXT 50000
#endif /* EGL_EXT_surface_SMPTE2086_metadata */
+#ifndef EGL_EXT_swap_buffers_with_damage
+#define EGL_EXT_swap_buffers_with_damage 1
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLSWAPBUFFERSWITHDAMAGEEXTPROC) (EGLDisplay dpy, EGLSurface surface, EGLint *rects, EGLint n_rects);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglSwapBuffersWithDamageEXT (EGLDisplay dpy, EGLSurface surface, EGLint *rects, EGLint n_rects);
+#endif
+#endif /* EGL_EXT_swap_buffers_with_damage */
+
+#ifndef EGL_EXT_yuv_surface
+#define EGL_EXT_yuv_surface 1
+#define EGL_YUV_ORDER_EXT 0x3301
+#define EGL_YUV_NUMBER_OF_PLANES_EXT 0x3311
+#define EGL_YUV_SUBSAMPLE_EXT 0x3312
+#define EGL_YUV_DEPTH_RANGE_EXT 0x3317
+#define EGL_YUV_CSC_STANDARD_EXT 0x330A
+#define EGL_YUV_PLANE_BPP_EXT 0x331A
+#define EGL_YUV_BUFFER_EXT 0x3300
+#define EGL_YUV_ORDER_YUV_EXT 0x3302
+#define EGL_YUV_ORDER_YVU_EXT 0x3303
+#define EGL_YUV_ORDER_YUYV_EXT 0x3304
+#define EGL_YUV_ORDER_UYVY_EXT 0x3305
+#define EGL_YUV_ORDER_YVYU_EXT 0x3306
+#define EGL_YUV_ORDER_VYUY_EXT 0x3307
+#define EGL_YUV_ORDER_AYUV_EXT 0x3308
+#define EGL_YUV_SUBSAMPLE_4_2_0_EXT 0x3313
+#define EGL_YUV_SUBSAMPLE_4_2_2_EXT 0x3314
+#define EGL_YUV_SUBSAMPLE_4_4_4_EXT 0x3315
+#define EGL_YUV_DEPTH_RANGE_LIMITED_EXT 0x3318
+#define EGL_YUV_DEPTH_RANGE_FULL_EXT 0x3319
+#define EGL_YUV_CSC_STANDARD_601_EXT 0x330B
+#define EGL_YUV_CSC_STANDARD_709_EXT 0x330C
+#define EGL_YUV_CSC_STANDARD_2020_EXT 0x330D
+#define EGL_YUV_PLANE_BPP_0_EXT 0x331B
+#define EGL_YUV_PLANE_BPP_8_EXT 0x331C
+#define EGL_YUV_PLANE_BPP_10_EXT 0x331D
+#endif /* EGL_EXT_yuv_surface */
+
+#ifndef EGL_HI_clientpixmap
+#define EGL_HI_clientpixmap 1
+struct EGLClientPixmapHI {
+ void *pData;
+ EGLint iWidth;
+ EGLint iHeight;
+ EGLint iStride;
+};
+#define EGL_CLIENT_PIXMAP_POINTER_HI 0x8F74
+typedef EGLSurface (EGLAPIENTRYP PFNEGLCREATEPIXMAPSURFACEHIPROC) (EGLDisplay dpy, EGLConfig config, struct EGLClientPixmapHI *pixmap);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLSurface EGLAPIENTRY eglCreatePixmapSurfaceHI (EGLDisplay dpy, EGLConfig config, struct EGLClientPixmapHI *pixmap);
+#endif
+#endif /* EGL_HI_clientpixmap */
+
+#ifndef EGL_HI_colorformats
+#define EGL_HI_colorformats 1
+#define EGL_COLOR_FORMAT_HI 0x8F70
+#define EGL_COLOR_RGB_HI 0x8F71
+#define EGL_COLOR_RGBA_HI 0x8F72
+#define EGL_COLOR_ARGB_HI 0x8F73
+#endif /* EGL_HI_colorformats */
+
+#ifndef EGL_IMG_context_priority
+#define EGL_IMG_context_priority 1
+#define EGL_CONTEXT_PRIORITY_LEVEL_IMG 0x3100
+#define EGL_CONTEXT_PRIORITY_HIGH_IMG 0x3101
+#define EGL_CONTEXT_PRIORITY_MEDIUM_IMG 0x3102
+#define EGL_CONTEXT_PRIORITY_LOW_IMG 0x3103
+#endif /* EGL_IMG_context_priority */
+
+#ifndef EGL_IMG_image_plane_attribs
+#define EGL_IMG_image_plane_attribs 1
+#define EGL_NATIVE_BUFFER_MULTIPLANE_SEPARATE_IMG 0x3105
+#define EGL_NATIVE_BUFFER_PLANE_OFFSET_IMG 0x3106
+#endif /* EGL_IMG_image_plane_attribs */
+
+#ifndef EGL_MESA_drm_image
+#define EGL_MESA_drm_image 1
+#define EGL_DRM_BUFFER_FORMAT_MESA 0x31D0
+#define EGL_DRM_BUFFER_USE_MESA 0x31D1
+#define EGL_DRM_BUFFER_FORMAT_ARGB32_MESA 0x31D2
+#define EGL_DRM_BUFFER_MESA 0x31D3
+#define EGL_DRM_BUFFER_STRIDE_MESA 0x31D4
+#define EGL_DRM_BUFFER_USE_SCANOUT_MESA 0x00000001
+#define EGL_DRM_BUFFER_USE_SHARE_MESA 0x00000002
+typedef EGLImageKHR (EGLAPIENTRYP PFNEGLCREATEDRMIMAGEMESAPROC) (EGLDisplay dpy, const EGLint *attrib_list);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLEXPORTDRMIMAGEMESAPROC) (EGLDisplay dpy, EGLImageKHR image, EGLint *name, EGLint *handle, EGLint *stride);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLImageKHR EGLAPIENTRY eglCreateDRMImageMESA (EGLDisplay dpy, const EGLint *attrib_list);
+EGLAPI EGLBoolean EGLAPIENTRY eglExportDRMImageMESA (EGLDisplay dpy, EGLImageKHR image, EGLint *name, EGLint *handle, EGLint *stride);
+#endif
+#endif /* EGL_MESA_drm_image */
+
+#ifndef EGL_ANDROID_get_native_client_buffer
+#define EGL_ANDROID_get_native_client_buffer 1
+struct AHardwareBuffer;
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLClientBuffer eglGetNativeClientBufferANDROID (const struct AHardwareBuffer *buffer);
+#else
+typedef EGLClientBuffer (EGLAPIENTRYP PFNEGLGETNATIVECLIENTBUFFERANDROID) (const struct AHardwareBuffer *buffer);
+#endif
+#endif
+
+#ifndef EGL_MESA_image_dma_buf_export
+#define EGL_MESA_image_dma_buf_export 1
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLEXPORTDMABUFIMAGEQUERYMESAPROC) (EGLDisplay dpy, EGLImageKHR image, int *fourcc, int *num_planes, EGLuint64KHR *modifiers);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLEXPORTDMABUFIMAGEMESAPROC) (EGLDisplay dpy, EGLImageKHR image, int *fds, EGLint *strides, EGLint *offsets);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglExportDMABUFImageQueryMESA (EGLDisplay dpy, EGLImageKHR image, int *fourcc, int *num_planes, EGLuint64KHR *modifiers);
+EGLAPI EGLBoolean EGLAPIENTRY eglExportDMABUFImageMESA (EGLDisplay dpy, EGLImageKHR image, int *fds, EGLint *strides, EGLint *offsets);
+#endif
+#endif /* EGL_MESA_image_dma_buf_export */
+
+#ifndef EGL_MESA_platform_gbm
+#define EGL_MESA_platform_gbm 1
+#define EGL_PLATFORM_GBM_MESA 0x31D7
+#endif /* EGL_MESA_platform_gbm */
+
+#ifndef EGL_MESA_platform_surfaceless
+#define EGL_MESA_platform_surfaceless 1
+#define EGL_PLATFORM_SURFACELESS_MESA 0x31DD
+#endif /* EGL_MESA_platform_surfaceless */
+
+#ifndef EGL_NOK_swap_region
+#define EGL_NOK_swap_region 1
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLSWAPBUFFERSREGIONNOKPROC) (EGLDisplay dpy, EGLSurface surface, EGLint numRects, const EGLint *rects);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglSwapBuffersRegionNOK (EGLDisplay dpy, EGLSurface surface, EGLint numRects, const EGLint *rects);
+#endif
+#endif /* EGL_NOK_swap_region */
+
+#ifndef EGL_NOK_swap_region2
+#define EGL_NOK_swap_region2 1
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLSWAPBUFFERSREGION2NOKPROC) (EGLDisplay dpy, EGLSurface surface, EGLint numRects, const EGLint *rects);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglSwapBuffersRegion2NOK (EGLDisplay dpy, EGLSurface surface, EGLint numRects, const EGLint *rects);
+#endif
+#endif /* EGL_NOK_swap_region2 */
+
+#ifndef EGL_NOK_texture_from_pixmap
+#define EGL_NOK_texture_from_pixmap 1
+#define EGL_Y_INVERTED_NOK 0x307F
+#endif /* EGL_NOK_texture_from_pixmap */
+
+#ifndef EGL_NV_3dvision_surface
+#define EGL_NV_3dvision_surface 1
+#define EGL_AUTO_STEREO_NV 0x3136
+#endif /* EGL_NV_3dvision_surface */
+
+#ifndef EGL_NV_coverage_sample
+#define EGL_NV_coverage_sample 1
+#define EGL_COVERAGE_BUFFERS_NV 0x30E0
+#define EGL_COVERAGE_SAMPLES_NV 0x30E1
+#endif /* EGL_NV_coverage_sample */
+
+#ifndef EGL_NV_coverage_sample_resolve
+#define EGL_NV_coverage_sample_resolve 1
+#define EGL_COVERAGE_SAMPLE_RESOLVE_NV 0x3131
+#define EGL_COVERAGE_SAMPLE_RESOLVE_DEFAULT_NV 0x3132
+#define EGL_COVERAGE_SAMPLE_RESOLVE_NONE_NV 0x3133
+#endif /* EGL_NV_coverage_sample_resolve */
+
+#ifndef EGL_NV_cuda_event
+#define EGL_NV_cuda_event 1
+#define EGL_CUDA_EVENT_HANDLE_NV 0x323B
+#define EGL_SYNC_CUDA_EVENT_NV 0x323C
+#define EGL_SYNC_CUDA_EVENT_COMPLETE_NV 0x323D
+#endif /* EGL_NV_cuda_event */
+
+#ifndef EGL_NV_depth_nonlinear
+#define EGL_NV_depth_nonlinear 1
+#define EGL_DEPTH_ENCODING_NV 0x30E2
+#define EGL_DEPTH_ENCODING_NONE_NV 0
+#define EGL_DEPTH_ENCODING_NONLINEAR_NV 0x30E3
+#endif /* EGL_NV_depth_nonlinear */
+
+#ifndef EGL_NV_device_cuda
+#define EGL_NV_device_cuda 1
+#define EGL_CUDA_DEVICE_NV 0x323A
+#endif /* EGL_NV_device_cuda */
+
+#ifndef EGL_NV_native_query
+#define EGL_NV_native_query 1
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYNATIVEDISPLAYNVPROC) (EGLDisplay dpy, EGLNativeDisplayType *display_id);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYNATIVEWINDOWNVPROC) (EGLDisplay dpy, EGLSurface surf, EGLNativeWindowType *window);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYNATIVEPIXMAPNVPROC) (EGLDisplay dpy, EGLSurface surf, EGLNativePixmapType *pixmap);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglQueryNativeDisplayNV (EGLDisplay dpy, EGLNativeDisplayType *display_id);
+EGLAPI EGLBoolean EGLAPIENTRY eglQueryNativeWindowNV (EGLDisplay dpy, EGLSurface surf, EGLNativeWindowType *window);
+EGLAPI EGLBoolean EGLAPIENTRY eglQueryNativePixmapNV (EGLDisplay dpy, EGLSurface surf, EGLNativePixmapType *pixmap);
+#endif
+#endif /* EGL_NV_native_query */
+
+#ifndef EGL_NV_post_convert_rounding
+#define EGL_NV_post_convert_rounding 1
+#endif /* EGL_NV_post_convert_rounding */
+
+#ifndef EGL_NV_post_sub_buffer
+#define EGL_NV_post_sub_buffer 1
+#define EGL_POST_SUB_BUFFER_SUPPORTED_NV 0x30BE
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLPOSTSUBBUFFERNVPROC) (EGLDisplay dpy, EGLSurface surface, EGLint x, EGLint y, EGLint width, EGLint height);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglPostSubBufferNV (EGLDisplay dpy, EGLSurface surface, EGLint x, EGLint y, EGLint width, EGLint height);
+#endif
+#endif /* EGL_NV_post_sub_buffer */
+
+#ifndef EGL_NV_robustness_video_memory_purge
+#define EGL_NV_robustness_video_memory_purge 1
+#define EGL_GENERATE_RESET_ON_VIDEO_MEMORY_PURGE_NV 0x334C
+#endif /* EGL_NV_robustness_video_memory_purge */
+
+#ifndef EGL_NV_stream_consumer_gltexture_yuv
+#define EGL_NV_stream_consumer_gltexture_yuv 1
+#define EGL_YUV_PLANE0_TEXTURE_UNIT_NV 0x332C
+#define EGL_YUV_PLANE1_TEXTURE_UNIT_NV 0x332D
+#define EGL_YUV_PLANE2_TEXTURE_UNIT_NV 0x332E
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLSTREAMCONSUMERGLTEXTUREEXTERNALATTRIBSNVPROC) (EGLDisplay dpy, EGLStreamKHR stream, EGLAttrib *attrib_list);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglStreamConsumerGLTextureExternalAttribsNV (EGLDisplay dpy, EGLStreamKHR stream, EGLAttrib *attrib_list);
+#endif
+#endif /* EGL_NV_stream_consumer_gltexture_yuv */
+
+#ifndef EGL_NV_stream_cross_display
+#define EGL_NV_stream_cross_display 1
+#define EGL_STREAM_CROSS_DISPLAY_NV 0x334E
+#endif /* EGL_NV_stream_cross_display */
+
+#ifndef EGL_NV_stream_cross_object
+#define EGL_NV_stream_cross_object 1
+#define EGL_STREAM_CROSS_OBJECT_NV 0x334D
+#endif /* EGL_NV_stream_cross_object */
+
+#ifndef EGL_NV_stream_cross_partition
+#define EGL_NV_stream_cross_partition 1
+#define EGL_STREAM_CROSS_PARTITION_NV 0x323F
+#endif /* EGL_NV_stream_cross_partition */
+
+#ifndef EGL_NV_stream_cross_process
+#define EGL_NV_stream_cross_process 1
+#define EGL_STREAM_CROSS_PROCESS_NV 0x3245
+#endif /* EGL_NV_stream_cross_process */
+
+#ifndef EGL_NV_stream_cross_system
+#define EGL_NV_stream_cross_system 1
+#define EGL_STREAM_CROSS_SYSTEM_NV 0x334F
+#endif /* EGL_NV_stream_cross_system */
+
+#ifndef EGL_NV_stream_fifo_next
+#define EGL_NV_stream_fifo_next 1
+#define EGL_PENDING_FRAME_NV 0x3329
+#define EGL_STREAM_TIME_PENDING_NV 0x332A
+#endif /* EGL_NV_stream_fifo_next */
+
+#ifndef EGL_NV_stream_fifo_synchronous
+#define EGL_NV_stream_fifo_synchronous 1
+#define EGL_STREAM_FIFO_SYNCHRONOUS_NV 0x3336
+#endif /* EGL_NV_stream_fifo_synchronous */
+
+#ifndef EGL_NV_stream_frame_limits
+#define EGL_NV_stream_frame_limits 1
+#define EGL_PRODUCER_MAX_FRAME_HINT_NV 0x3337
+#define EGL_CONSUMER_MAX_FRAME_HINT_NV 0x3338
+#endif /* EGL_NV_stream_frame_limits */
+
+#ifndef EGL_NV_stream_metadata
+#define EGL_NV_stream_metadata 1
+#define EGL_MAX_STREAM_METADATA_BLOCKS_NV 0x3250
+#define EGL_MAX_STREAM_METADATA_BLOCK_SIZE_NV 0x3251
+#define EGL_MAX_STREAM_METADATA_TOTAL_SIZE_NV 0x3252
+#define EGL_PRODUCER_METADATA_NV 0x3253
+#define EGL_CONSUMER_METADATA_NV 0x3254
+#define EGL_PENDING_METADATA_NV 0x3328
+#define EGL_METADATA0_SIZE_NV 0x3255
+#define EGL_METADATA1_SIZE_NV 0x3256
+#define EGL_METADATA2_SIZE_NV 0x3257
+#define EGL_METADATA3_SIZE_NV 0x3258
+#define EGL_METADATA0_TYPE_NV 0x3259
+#define EGL_METADATA1_TYPE_NV 0x325A
+#define EGL_METADATA2_TYPE_NV 0x325B
+#define EGL_METADATA3_TYPE_NV 0x325C
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYDISPLAYATTRIBNVPROC) (EGLDisplay dpy, EGLint attribute, EGLAttrib *value);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLSETSTREAMMETADATANVPROC) (EGLDisplay dpy, EGLStreamKHR stream, EGLint n, EGLint offset, EGLint size, const void *data);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYSTREAMMETADATANVPROC) (EGLDisplay dpy, EGLStreamKHR stream, EGLenum name, EGLint n, EGLint offset, EGLint size, void *data);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglQueryDisplayAttribNV (EGLDisplay dpy, EGLint attribute, EGLAttrib *value);
+EGLAPI EGLBoolean EGLAPIENTRY eglSetStreamMetadataNV (EGLDisplay dpy, EGLStreamKHR stream, EGLint n, EGLint offset, EGLint size, const void *data);
+EGLAPI EGLBoolean EGLAPIENTRY eglQueryStreamMetadataNV (EGLDisplay dpy, EGLStreamKHR stream, EGLenum name, EGLint n, EGLint offset, EGLint size, void *data);
+#endif
+#endif /* EGL_NV_stream_metadata */
+
+#ifndef EGL_NV_stream_remote
+#define EGL_NV_stream_remote 1
+#define EGL_STREAM_STATE_INITIALIZING_NV 0x3240
+#define EGL_STREAM_TYPE_NV 0x3241
+#define EGL_STREAM_PROTOCOL_NV 0x3242
+#define EGL_STREAM_ENDPOINT_NV 0x3243
+#define EGL_STREAM_LOCAL_NV 0x3244
+#define EGL_STREAM_PRODUCER_NV 0x3247
+#define EGL_STREAM_CONSUMER_NV 0x3248
+#define EGL_STREAM_PROTOCOL_FD_NV 0x3246
+#endif /* EGL_NV_stream_remote */
+
+#ifndef EGL_NV_stream_reset
+#define EGL_NV_stream_reset 1
+#define EGL_SUPPORT_RESET_NV 0x3334
+#define EGL_SUPPORT_REUSE_NV 0x3335
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLRESETSTREAMNVPROC) (EGLDisplay dpy, EGLStreamKHR stream);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglResetStreamNV (EGLDisplay dpy, EGLStreamKHR stream);
+#endif
+#endif /* EGL_NV_stream_reset */
+
+#ifndef EGL_NV_stream_socket
+#define EGL_NV_stream_socket 1
+#define EGL_STREAM_PROTOCOL_SOCKET_NV 0x324B
+#define EGL_SOCKET_HANDLE_NV 0x324C
+#define EGL_SOCKET_TYPE_NV 0x324D
+#endif /* EGL_NV_stream_socket */
+
+#ifndef EGL_NV_stream_socket_inet
+#define EGL_NV_stream_socket_inet 1
+#define EGL_SOCKET_TYPE_INET_NV 0x324F
+#endif /* EGL_NV_stream_socket_inet */
+
+#ifndef EGL_NV_stream_socket_unix
+#define EGL_NV_stream_socket_unix 1
+#define EGL_SOCKET_TYPE_UNIX_NV 0x324E
+#endif /* EGL_NV_stream_socket_unix */
+
+#ifndef EGL_NV_stream_sync
+#define EGL_NV_stream_sync 1
+#define EGL_SYNC_NEW_FRAME_NV 0x321F
+typedef EGLSyncKHR (EGLAPIENTRYP PFNEGLCREATESTREAMSYNCNVPROC) (EGLDisplay dpy, EGLStreamKHR stream, EGLenum type, const EGLint *attrib_list);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLSyncKHR EGLAPIENTRY eglCreateStreamSyncNV (EGLDisplay dpy, EGLStreamKHR stream, EGLenum type, const EGLint *attrib_list);
+#endif
+#endif /* EGL_NV_stream_sync */
+
+#ifndef EGL_NV_sync
+#define EGL_NV_sync 1
+typedef void *EGLSyncNV;
+typedef khronos_utime_nanoseconds_t EGLTimeNV;
+#ifdef KHRONOS_SUPPORT_INT64
+#define EGL_SYNC_PRIOR_COMMANDS_COMPLETE_NV 0x30E6
+#define EGL_SYNC_STATUS_NV 0x30E7
+#define EGL_SIGNALED_NV 0x30E8
+#define EGL_UNSIGNALED_NV 0x30E9
+#define EGL_SYNC_FLUSH_COMMANDS_BIT_NV 0x0001
+#define EGL_FOREVER_NV 0xFFFFFFFFFFFFFFFFull
+#define EGL_ALREADY_SIGNALED_NV 0x30EA
+#define EGL_TIMEOUT_EXPIRED_NV 0x30EB
+#define EGL_CONDITION_SATISFIED_NV 0x30EC
+#define EGL_SYNC_TYPE_NV 0x30ED
+#define EGL_SYNC_CONDITION_NV 0x30EE
+#define EGL_SYNC_FENCE_NV 0x30EF
+#define EGL_NO_SYNC_NV EGL_CAST(EGLSyncNV,0)
+typedef EGLSyncNV (EGLAPIENTRYP PFNEGLCREATEFENCESYNCNVPROC) (EGLDisplay dpy, EGLenum condition, const EGLint *attrib_list);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLDESTROYSYNCNVPROC) (EGLSyncNV sync);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLFENCENVPROC) (EGLSyncNV sync);
+typedef EGLint (EGLAPIENTRYP PFNEGLCLIENTWAITSYNCNVPROC) (EGLSyncNV sync, EGLint flags, EGLTimeNV timeout);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLSIGNALSYNCNVPROC) (EGLSyncNV sync, EGLenum mode);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLGETSYNCATTRIBNVPROC) (EGLSyncNV sync, EGLint attribute, EGLint *value);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLSyncNV EGLAPIENTRY eglCreateFenceSyncNV (EGLDisplay dpy, EGLenum condition, const EGLint *attrib_list);
+EGLAPI EGLBoolean EGLAPIENTRY eglDestroySyncNV (EGLSyncNV sync);
+EGLAPI EGLBoolean EGLAPIENTRY eglFenceNV (EGLSyncNV sync);
+EGLAPI EGLint EGLAPIENTRY eglClientWaitSyncNV (EGLSyncNV sync, EGLint flags, EGLTimeNV timeout);
+EGLAPI EGLBoolean EGLAPIENTRY eglSignalSyncNV (EGLSyncNV sync, EGLenum mode);
+EGLAPI EGLBoolean EGLAPIENTRY eglGetSyncAttribNV (EGLSyncNV sync, EGLint attribute, EGLint *value);
+#endif
+#endif /* KHRONOS_SUPPORT_INT64 */
+#endif /* EGL_NV_sync */
+
+#ifndef EGL_NV_system_time
+#define EGL_NV_system_time 1
+typedef khronos_utime_nanoseconds_t EGLuint64NV;
+#ifdef KHRONOS_SUPPORT_INT64
+typedef EGLuint64NV (EGLAPIENTRYP PFNEGLGETSYSTEMTIMEFREQUENCYNVPROC) (void);
+typedef EGLuint64NV (EGLAPIENTRYP PFNEGLGETSYSTEMTIMENVPROC) (void);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLuint64NV EGLAPIENTRY eglGetSystemTimeFrequencyNV (void);
+EGLAPI EGLuint64NV EGLAPIENTRY eglGetSystemTimeNV (void);
+#endif
+#endif /* KHRONOS_SUPPORT_INT64 */
+#endif /* EGL_NV_system_time */
+
+#ifndef EGL_TIZEN_image_native_buffer
+#define EGL_TIZEN_image_native_buffer 1
+#define EGL_NATIVE_BUFFER_TIZEN 0x32A0
+#endif /* EGL_TIZEN_image_native_buffer */
+
+#ifndef EGL_TIZEN_image_native_surface
+#define EGL_TIZEN_image_native_surface 1
+#define EGL_NATIVE_SURFACE_TIZEN 0x32A1
+#endif /* EGL_TIZEN_image_native_surface */
+
#ifdef __cplusplus
}
#endif
-#endif /* __eglext_h_ */
+#endif
diff --git a/opengl/include/EGL/eglplatform.h b/opengl/include/EGL/eglplatform.h
index 54011c8..c77c333 100644
--- a/opengl/include/EGL/eglplatform.h
+++ b/opengl/include/EGL/eglplatform.h
@@ -2,7 +2,7 @@
#define __eglplatform_h_
/*
-** Copyright (c) 2007-2009 The Khronos Group Inc.
+** Copyright (c) 2007-2016 The Khronos Group Inc.
**
** Permission is hereby granted, free of charge, to any person obtaining a
** copy of this software and/or associated documentation files (the
@@ -25,7 +25,7 @@
*/
/* Platform-specific types and definitions for egl.h
- * $Revision: 12306 $ on $Date: 2010-08-25 09:51:28 -0700 (Wed, 25 Aug 2010) $
+ * $Revision: 30994 $ on $Date: 2015-04-30 13:36:48 -0700 (Thu, 30 Apr 2015) $
*
* Adopters may modify khrplatform.h and this file to suit their platform.
* You are encouraged to submit all modifications to the Khronos group so that
@@ -77,7 +77,7 @@
typedef HBITMAP EGLNativePixmapType;
typedef HWND EGLNativeWindowType;
-#elif defined(__WINSCW__) || defined(__SYMBIAN32__) /* Symbian */
+#elif defined(__APPLE__) || defined(__WINSCW__) || defined(__SYMBIAN32__) /* Symbian */
typedef int EGLNativeDisplayType;
typedef void *EGLNativeWindowType;
@@ -121,6 +121,8 @@
*/
typedef khronos_int32_t EGLint;
+
+/* C++ / C typecast macros for special EGL handle values */
#if defined(__cplusplus)
#define EGL_CAST(type, value) (static_cast<type>(value))
#else
diff --git a/opengl/include/GLES/NOTICE b/opengl/include/GLES/NOTICE
index 4dc6614..710388f 100644
--- a/opengl/include/GLES/NOTICE
+++ b/opengl/include/GLES/NOTICE
@@ -1,2 +1,35 @@
-This document is licensed under the SGI Free Software B License Version 2.0.
-For details, see http://oss.sgi.com/projects/FreeB/ .
+Copyright (c) 2017 The Khronos Group Inc.
+
+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.
+
+Copyright (c) 2013-2017 The Khronos Group Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and/or associated documentation files (the
+"Materials"), to deal in the Materials without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Materials, and to
+permit persons to whom the Materials are furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Materials.
+
+THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+
diff --git a/opengl/include/GLES/egl.h b/opengl/include/GLES/egl.h
index 5778e00..86f644c 100644
--- a/opengl/include/GLES/egl.h
+++ b/opengl/include/GLES/egl.h
@@ -1,9 +1,23 @@
/*
+** Copyright (c) 2008-2017 The Khronos Group Inc.
+**
+** 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.
+*/
+
+/*
* Skeleton egl.h to provide compatibility for early GLES 1.0
* applications. Several early implementations included gl.h
* in egl.h leading applications to include only egl.h
- *
- * $Revision: 6252 $ on $Date:: 2008-08-06 16:35:08 -0700 #$
*/
#ifndef __legacy_egl_h_
diff --git a/opengl/include/GLES/gl.h b/opengl/include/GLES/gl.h
index 5b8d85a..25033f2 100644
--- a/opengl/include/GLES/gl.h
+++ b/opengl/include/GLES/gl.h
@@ -1,58 +1,82 @@
#ifndef __gl_h_
-#define __gl_h_
-
-/* $Revision: 10601 $ on $Date:: 2010-03-04 22:15:27 -0800 #$ */
-
-#include <GLES/glplatform.h>
+#define __gl_h_ 1
#ifdef __cplusplus
extern "C" {
#endif
/*
- * This document is licensed under the SGI Free Software B License Version
- * 2.0. For details, see http://oss.sgi.com/projects/FreeB/ .
+** Copyright (c) 2013-2017 The Khronos Group Inc.
+**
+** Permission is hereby granted, free of charge, to any person obtaining a
+** copy of this software and/or associated documentation files (the
+** "Materials"), to deal in the Materials without restriction, including
+** without limitation the rights to use, copy, modify, merge, publish,
+** distribute, sublicense, and/or sell copies of the Materials, and to
+** permit persons to whom the Materials are furnished to do so, subject to
+** the following conditions:
+**
+** The above copyright notice and this permission notice shall be included
+** in all copies or substantial portions of the Materials.
+**
+** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+*/
+/*
+** This header is generated from the Khronos OpenGL / OpenGL ES XML
+** API Registry. The current version of the Registry, generator scripts
+** used to make the header, and the header can be found at
+** https://github.com/KhronosGroup/OpenGL-Registry
+*/
+
+#include <GLES/glplatform.h>
+
+/* Generated on date 20170613 */
+
+/* Generated C header for:
+ * API: gles1
+ * Profile: common
+ * Versions considered: .*
+ * Versions emitted: .*
+ * Default extensions included: None
+ * Additional extensions included: ^(GL_OES_read_format|GL_OES_compressed_paletted_texture|GL_OES_point_size_array|GL_OES_point_sprite)$
+ * Extensions removed: _nomatch_^
*/
-typedef void GLvoid;
-typedef char GLchar;
-typedef unsigned int GLenum;
-typedef unsigned char GLboolean;
-typedef unsigned int GLbitfield;
-typedef khronos_int8_t GLbyte;
-typedef short GLshort;
-typedef int GLint;
-typedef int GLsizei;
-typedef khronos_uint8_t GLubyte;
-typedef unsigned short GLushort;
-typedef unsigned int GLuint;
-typedef khronos_float_t GLfloat;
-typedef khronos_float_t GLclampf;
-typedef khronos_int32_t GLfixed;
-typedef khronos_int32_t GLclampx;
-
+#ifndef GL_VERSION_ES_CM_1_0
+#define GL_VERSION_ES_CM_1_0 1
+typedef void GLvoid;
+typedef char GLchar;
+typedef unsigned int GLenum;
+#include <KHR/khrplatform.h>
+typedef khronos_float_t GLfloat;
+typedef khronos_int32_t GLfixed;
+typedef unsigned int GLuint;
+typedef khronos_ssize_t GLsizeiptr;
typedef khronos_intptr_t GLintptr;
-typedef khronos_ssize_t GLsizeiptr;
-
-
-/*************************************************************/
-
-/* OpenGL ES core versions */
-#define GL_VERSION_ES_CM_1_0 1
-#define GL_VERSION_ES_CL_1_0 1
-#define GL_VERSION_ES_CM_1_1 1
-#define GL_VERSION_ES_CL_1_1 1
-
-/* ClearBufferMask */
+typedef unsigned int GLbitfield;
+typedef int GLint;
+typedef unsigned short GLushort;
+typedef short GLshort;
+typedef khronos_int8_t GLbyte;
+typedef khronos_uint8_t GLubyte;
+typedef unsigned char GLboolean;
+typedef int GLsizei;
+typedef khronos_float_t GLclampf;
+typedef khronos_int32_t GLclampx;
+#define GL_VERSION_ES_CL_1_0 1
+#define GL_VERSION_ES_CM_1_1 1
+#define GL_VERSION_ES_CL_1_1 1
#define GL_DEPTH_BUFFER_BIT 0x00000100
#define GL_STENCIL_BUFFER_BIT 0x00000400
#define GL_COLOR_BUFFER_BIT 0x00004000
-
-/* Boolean */
#define GL_FALSE 0
#define GL_TRUE 1
-
-/* BeginMode */
#define GL_POINTS 0x0000
#define GL_LINES 0x0001
#define GL_LINE_LOOP 0x0002
@@ -60,8 +84,6 @@
#define GL_TRIANGLES 0x0004
#define GL_TRIANGLE_STRIP 0x0005
#define GL_TRIANGLE_FAN 0x0006
-
-/* AlphaFunction */
#define GL_NEVER 0x0200
#define GL_LESS 0x0201
#define GL_EQUAL 0x0202
@@ -70,8 +92,6 @@
#define GL_NOTEQUAL 0x0205
#define GL_GEQUAL 0x0206
#define GL_ALWAYS 0x0207
-
-/* BlendingFactorDest */
#define GL_ZERO 0
#define GL_ONE 1
#define GL_SRC_COLOR 0x0300
@@ -80,53 +100,18 @@
#define GL_ONE_MINUS_SRC_ALPHA 0x0303
#define GL_DST_ALPHA 0x0304
#define GL_ONE_MINUS_DST_ALPHA 0x0305
-
-/* BlendingFactorSrc */
-/* GL_ZERO */
-/* GL_ONE */
#define GL_DST_COLOR 0x0306
#define GL_ONE_MINUS_DST_COLOR 0x0307
#define GL_SRC_ALPHA_SATURATE 0x0308
-/* GL_SRC_ALPHA */
-/* GL_ONE_MINUS_SRC_ALPHA */
-/* GL_DST_ALPHA */
-/* GL_ONE_MINUS_DST_ALPHA */
-
-/* ClipPlaneName */
#define GL_CLIP_PLANE0 0x3000
#define GL_CLIP_PLANE1 0x3001
#define GL_CLIP_PLANE2 0x3002
#define GL_CLIP_PLANE3 0x3003
#define GL_CLIP_PLANE4 0x3004
#define GL_CLIP_PLANE5 0x3005
-
-/* ColorMaterialFace */
-/* GL_FRONT_AND_BACK */
-
-/* ColorMaterialParameter */
-/* GL_AMBIENT_AND_DIFFUSE */
-
-/* ColorPointerType */
-/* GL_UNSIGNED_BYTE */
-/* GL_FLOAT */
-/* GL_FIXED */
-
-/* CullFaceMode */
#define GL_FRONT 0x0404
#define GL_BACK 0x0405
#define GL_FRONT_AND_BACK 0x0408
-
-/* DepthFunction */
-/* GL_NEVER */
-/* GL_LESS */
-/* GL_EQUAL */
-/* GL_LEQUAL */
-/* GL_GREATER */
-/* GL_NOTEQUAL */
-/* GL_GEQUAL */
-/* GL_ALWAYS */
-
-/* EnableCap */
#define GL_FOG 0x0B60
#define GL_LIGHTING 0x0B50
#define GL_TEXTURE_2D 0x0DE1
@@ -137,21 +122,12 @@
#define GL_DITHER 0x0BD0
#define GL_STENCIL_TEST 0x0B90
#define GL_DEPTH_TEST 0x0B71
-/* GL_LIGHT0 */
-/* GL_LIGHT1 */
-/* GL_LIGHT2 */
-/* GL_LIGHT3 */
-/* GL_LIGHT4 */
-/* GL_LIGHT5 */
-/* GL_LIGHT6 */
-/* GL_LIGHT7 */
#define GL_POINT_SMOOTH 0x0B10
#define GL_LINE_SMOOTH 0x0B20
#define GL_SCISSOR_TEST 0x0C11
#define GL_COLOR_MATERIAL 0x0B57
#define GL_NORMALIZE 0x0BA1
#define GL_RESCALE_NORMAL 0x803A
-#define GL_POLYGON_OFFSET_FILL 0x8037
#define GL_VERTEX_ARRAY 0x8074
#define GL_NORMAL_ARRAY 0x8075
#define GL_COLOR_ARRAY 0x8076
@@ -160,8 +136,6 @@
#define GL_SAMPLE_ALPHA_TO_COVERAGE 0x809E
#define GL_SAMPLE_ALPHA_TO_ONE 0x809F
#define GL_SAMPLE_COVERAGE 0x80A0
-
-/* ErrorCode */
#define GL_NO_ERROR 0
#define GL_INVALID_ENUM 0x0500
#define GL_INVALID_VALUE 0x0501
@@ -169,24 +143,15 @@
#define GL_STACK_OVERFLOW 0x0503
#define GL_STACK_UNDERFLOW 0x0504
#define GL_OUT_OF_MEMORY 0x0505
-
-/* FogMode */
-/* GL_LINEAR */
#define GL_EXP 0x0800
#define GL_EXP2 0x0801
-
-/* FogParameter */
#define GL_FOG_DENSITY 0x0B62
#define GL_FOG_START 0x0B63
#define GL_FOG_END 0x0B64
#define GL_FOG_MODE 0x0B65
#define GL_FOG_COLOR 0x0B66
-
-/* FrontFaceDirection */
#define GL_CW 0x0900
#define GL_CCW 0x0901
-
-/* GetPName */
#define GL_CURRENT_COLOR 0x0B00
#define GL_CURRENT_NORMAL 0x0B02
#define GL_CURRENT_TEXTURE_COORDS 0x0B03
@@ -229,11 +194,8 @@
#define GL_BLEND_SRC 0x0BE1
#define GL_LOGIC_OP_MODE 0x0BF0
#define GL_SCISSOR_BOX 0x0C10
-#define GL_SCISSOR_TEST 0x0C11
#define GL_COLOR_CLEAR_VALUE 0x0C22
#define GL_COLOR_WRITEMASK 0x0C23
-#define GL_UNPACK_ALIGNMENT 0x0CF5
-#define GL_PACK_ALIGNMENT 0x0D05
#define GL_MAX_LIGHTS 0x0D31
#define GL_MAX_CLIP_PLANES 0x0D32
#define GL_MAX_TEXTURE_SIZE 0x0D33
@@ -272,33 +234,18 @@
#define GL_SAMPLES 0x80A9
#define GL_SAMPLE_COVERAGE_VALUE 0x80AA
#define GL_SAMPLE_COVERAGE_INVERT 0x80AB
-
-/* GetTextureParameter */
-/* GL_TEXTURE_MAG_FILTER */
-/* GL_TEXTURE_MIN_FILTER */
-/* GL_TEXTURE_WRAP_S */
-/* GL_TEXTURE_WRAP_T */
-
#define GL_NUM_COMPRESSED_TEXTURE_FORMATS 0x86A2
#define GL_COMPRESSED_TEXTURE_FORMATS 0x86A3
-
-/* HintMode */
#define GL_DONT_CARE 0x1100
#define GL_FASTEST 0x1101
#define GL_NICEST 0x1102
-
-/* HintTarget */
#define GL_PERSPECTIVE_CORRECTION_HINT 0x0C50
#define GL_POINT_SMOOTH_HINT 0x0C51
#define GL_LINE_SMOOTH_HINT 0x0C52
#define GL_FOG_HINT 0x0C54
#define GL_GENERATE_MIPMAP_HINT 0x8192
-
-/* LightModelParameter */
#define GL_LIGHT_MODEL_AMBIENT 0x0B53
#define GL_LIGHT_MODEL_TWO_SIDE 0x0B52
-
-/* LightParameter */
#define GL_AMBIENT 0x1200
#define GL_DIFFUSE 0x1201
#define GL_SPECULAR 0x1202
@@ -309,16 +256,12 @@
#define GL_CONSTANT_ATTENUATION 0x1207
#define GL_LINEAR_ATTENUATION 0x1208
#define GL_QUADRATIC_ATTENUATION 0x1209
-
-/* DataType */
#define GL_BYTE 0x1400
#define GL_UNSIGNED_BYTE 0x1401
#define GL_SHORT 0x1402
#define GL_UNSIGNED_SHORT 0x1403
#define GL_FLOAT 0x1406
#define GL_FIXED 0x140C
-
-/* LogicOp */
#define GL_CLEAR 0x1500
#define GL_AND 0x1501
#define GL_AND_REVERSE 0x1502
@@ -335,117 +278,49 @@
#define GL_OR_INVERTED 0x150D
#define GL_NAND 0x150E
#define GL_SET 0x150F
-
-/* MaterialFace */
-/* GL_FRONT_AND_BACK */
-
-/* MaterialParameter */
#define GL_EMISSION 0x1600
#define GL_SHININESS 0x1601
#define GL_AMBIENT_AND_DIFFUSE 0x1602
-/* GL_AMBIENT */
-/* GL_DIFFUSE */
-/* GL_SPECULAR */
-
-/* MatrixMode */
#define GL_MODELVIEW 0x1700
#define GL_PROJECTION 0x1701
#define GL_TEXTURE 0x1702
-
-/* NormalPointerType */
-/* GL_BYTE */
-/* GL_SHORT */
-/* GL_FLOAT */
-/* GL_FIXED */
-
-/* PixelFormat */
#define GL_ALPHA 0x1906
#define GL_RGB 0x1907
#define GL_RGBA 0x1908
#define GL_LUMINANCE 0x1909
#define GL_LUMINANCE_ALPHA 0x190A
-
-/* PixelStoreParameter */
#define GL_UNPACK_ALIGNMENT 0x0CF5
#define GL_PACK_ALIGNMENT 0x0D05
-
-/* PixelType */
-/* GL_UNSIGNED_BYTE */
#define GL_UNSIGNED_SHORT_4_4_4_4 0x8033
#define GL_UNSIGNED_SHORT_5_5_5_1 0x8034
#define GL_UNSIGNED_SHORT_5_6_5 0x8363
-
-/* ShadingModel */
#define GL_FLAT 0x1D00
#define GL_SMOOTH 0x1D01
-
-/* StencilFunction */
-/* GL_NEVER */
-/* GL_LESS */
-/* GL_EQUAL */
-/* GL_LEQUAL */
-/* GL_GREATER */
-/* GL_NOTEQUAL */
-/* GL_GEQUAL */
-/* GL_ALWAYS */
-
-/* StencilOp */
-/* GL_ZERO */
#define GL_KEEP 0x1E00
#define GL_REPLACE 0x1E01
#define GL_INCR 0x1E02
#define GL_DECR 0x1E03
-/* GL_INVERT */
-
-/* StringName */
#define GL_VENDOR 0x1F00
#define GL_RENDERER 0x1F01
#define GL_VERSION 0x1F02
#define GL_EXTENSIONS 0x1F03
-
-/* TexCoordPointerType */
-/* GL_SHORT */
-/* GL_FLOAT */
-/* GL_FIXED */
-/* GL_BYTE */
-
-/* TextureEnvMode */
#define GL_MODULATE 0x2100
#define GL_DECAL 0x2101
-/* GL_BLEND */
#define GL_ADD 0x0104
-/* GL_REPLACE */
-
-/* TextureEnvParameter */
#define GL_TEXTURE_ENV_MODE 0x2200
#define GL_TEXTURE_ENV_COLOR 0x2201
-
-/* TextureEnvTarget */
#define GL_TEXTURE_ENV 0x2300
-
-/* TextureMagFilter */
#define GL_NEAREST 0x2600
#define GL_LINEAR 0x2601
-
-/* TextureMinFilter */
-/* GL_NEAREST */
-/* GL_LINEAR */
#define GL_NEAREST_MIPMAP_NEAREST 0x2700
#define GL_LINEAR_MIPMAP_NEAREST 0x2701
#define GL_NEAREST_MIPMAP_LINEAR 0x2702
#define GL_LINEAR_MIPMAP_LINEAR 0x2703
-
-/* TextureParameterName */
#define GL_TEXTURE_MAG_FILTER 0x2800
#define GL_TEXTURE_MIN_FILTER 0x2801
#define GL_TEXTURE_WRAP_S 0x2802
#define GL_TEXTURE_WRAP_T 0x2803
#define GL_GENERATE_MIPMAP 0x8191
-
-/* TextureTarget */
-/* GL_TEXTURE_2D */
-
-/* TextureUnit */
#define GL_TEXTURE0 0x84C0
#define GL_TEXTURE1 0x84C1
#define GL_TEXTURE2 0x84C2
@@ -480,18 +355,8 @@
#define GL_TEXTURE31 0x84DF
#define GL_ACTIVE_TEXTURE 0x84E0
#define GL_CLIENT_ACTIVE_TEXTURE 0x84E1
-
-/* TextureWrapMode */
#define GL_REPEAT 0x2901
#define GL_CLAMP_TO_EDGE 0x812F
-
-/* VertexPointerType */
-/* GL_SHORT */
-/* GL_FLOAT */
-/* GL_FIXED */
-/* GL_BYTE */
-
-/* LightName */
#define GL_LIGHT0 0x4000
#define GL_LIGHT1 0x4001
#define GL_LIGHT2 0x4002
@@ -500,25 +365,18 @@
#define GL_LIGHT5 0x4005
#define GL_LIGHT6 0x4006
#define GL_LIGHT7 0x4007
-
-/* Buffer Objects */
#define GL_ARRAY_BUFFER 0x8892
#define GL_ELEMENT_ARRAY_BUFFER 0x8893
-
-#define GL_ARRAY_BUFFER_BINDING 0x8894
-#define GL_ELEMENT_ARRAY_BUFFER_BINDING 0x8895
-#define GL_VERTEX_ARRAY_BUFFER_BINDING 0x8896
-#define GL_NORMAL_ARRAY_BUFFER_BINDING 0x8897
-#define GL_COLOR_ARRAY_BUFFER_BINDING 0x8898
+#define GL_ARRAY_BUFFER_BINDING 0x8894
+#define GL_ELEMENT_ARRAY_BUFFER_BINDING 0x8895
+#define GL_VERTEX_ARRAY_BUFFER_BINDING 0x8896
+#define GL_NORMAL_ARRAY_BUFFER_BINDING 0x8897
+#define GL_COLOR_ARRAY_BUFFER_BINDING 0x8898
#define GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING 0x889A
-
#define GL_STATIC_DRAW 0x88E4
#define GL_DYNAMIC_DRAW 0x88E8
-
#define GL_BUFFER_SIZE 0x8764
#define GL_BUFFER_USAGE 0x8765
-
-/* Texture combine + dot3 */
#define GL_SUBTRACT 0x84E7
#define GL_COMBINE 0x8570
#define GL_COMBINE_RGB 0x8571
@@ -535,75 +393,29 @@
#define GL_OPERAND0_ALPHA 0x8598
#define GL_OPERAND1_ALPHA 0x8599
#define GL_OPERAND2_ALPHA 0x859A
-
#define GL_ALPHA_SCALE 0x0D1C
-
#define GL_SRC0_RGB 0x8580
#define GL_SRC1_RGB 0x8581
#define GL_SRC2_RGB 0x8582
#define GL_SRC0_ALPHA 0x8588
#define GL_SRC1_ALPHA 0x8589
#define GL_SRC2_ALPHA 0x858A
-
#define GL_DOT3_RGB 0x86AE
#define GL_DOT3_RGBA 0x86AF
-
-/*------------------------------------------------------------------------*
- * required OES extension tokens
- *------------------------------------------------------------------------*/
-
-/* OES_read_format */
-#ifndef GL_OES_read_format
-#define GL_IMPLEMENTATION_COLOR_READ_TYPE_OES 0x8B9A
-#define GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES 0x8B9B
-#endif
-
-/* GL_OES_compressed_paletted_texture */
-#ifndef GL_OES_compressed_paletted_texture
-#define GL_PALETTE4_RGB8_OES 0x8B90
-#define GL_PALETTE4_RGBA8_OES 0x8B91
-#define GL_PALETTE4_R5_G6_B5_OES 0x8B92
-#define GL_PALETTE4_RGBA4_OES 0x8B93
-#define GL_PALETTE4_RGB5_A1_OES 0x8B94
-#define GL_PALETTE8_RGB8_OES 0x8B95
-#define GL_PALETTE8_RGBA8_OES 0x8B96
-#define GL_PALETTE8_R5_G6_B5_OES 0x8B97
-#define GL_PALETTE8_RGBA4_OES 0x8B98
-#define GL_PALETTE8_RGB5_A1_OES 0x8B99
-#endif
-
-/* OES_point_size_array */
-#ifndef GL_OES_point_size_array
-#define GL_POINT_SIZE_ARRAY_OES 0x8B9C
-#define GL_POINT_SIZE_ARRAY_TYPE_OES 0x898A
-#define GL_POINT_SIZE_ARRAY_STRIDE_OES 0x898B
-#define GL_POINT_SIZE_ARRAY_POINTER_OES 0x898C
-#define GL_POINT_SIZE_ARRAY_BUFFER_BINDING_OES 0x8B9F
-#endif
-
-/* GL_OES_point_sprite */
-#ifndef GL_OES_point_sprite
-#define GL_POINT_SPRITE_OES 0x8861
-#define GL_COORD_REPLACE_OES 0x8862
-#endif
-
-/*************************************************************/
-
-/* Available only in Common profile */
-GL_API void GL_APIENTRY glAlphaFunc (GLenum func, GLclampf ref);
-GL_API void GL_APIENTRY glClearColor (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
-GL_API void GL_APIENTRY glClearDepthf (GLclampf depth);
-GL_API void GL_APIENTRY glClipPlanef (GLenum plane, const GLfloat *equation);
+GL_API void GL_APIENTRY glAlphaFunc (GLenum func, GLfloat ref);
+GL_API void GL_APIENTRY glClearColor (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
+GL_API void GL_APIENTRY glClearDepthf (GLfloat d);
+GL_API void GL_APIENTRY glClipPlanef (GLenum p, const GLfloat *eqn);
GL_API void GL_APIENTRY glColor4f (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
-GL_API void GL_APIENTRY glDepthRangef (GLclampf zNear, GLclampf zFar);
+GL_API void GL_APIENTRY glDepthRangef (GLfloat n, GLfloat f);
GL_API void GL_APIENTRY glFogf (GLenum pname, GLfloat param);
GL_API void GL_APIENTRY glFogfv (GLenum pname, const GLfloat *params);
-GL_API void GL_APIENTRY glFrustumf (GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar);
-GL_API void GL_APIENTRY glGetClipPlanef (GLenum pname, GLfloat eqn[4]);
-GL_API void GL_APIENTRY glGetFloatv (GLenum pname, GLfloat *params);
+GL_API void GL_APIENTRY glFrustumf (GLfloat l, GLfloat r, GLfloat b, GLfloat t, GLfloat n, GLfloat f);
+GL_API void GL_APIENTRY glGetClipPlanef (GLenum plane, GLfloat *equation);
+GL_API void GL_APIENTRY glGetFloatv (GLenum pname, GLfloat *data);
GL_API void GL_APIENTRY glGetLightfv (GLenum light, GLenum pname, GLfloat *params);
GL_API void GL_APIENTRY glGetMaterialfv (GLenum face, GLenum pname, GLfloat *params);
-GL_API void GL_APIENTRY glGetTexEnvfv (GLenum env, GLenum pname, GLfloat *params);
+GL_API void GL_APIENTRY glGetTexEnvfv (GLenum target, GLenum pname, GLfloat *params);
GL_API void GL_APIENTRY glGetTexParameterfv (GLenum target, GLenum pname, GLfloat *params);
GL_API void GL_APIENTRY glLightModelf (GLenum pname, GLfloat param);
GL_API void GL_APIENTRY glLightModelfv (GLenum pname, const GLfloat *params);
@@ -616,7 +428,7 @@
GL_API void GL_APIENTRY glMultMatrixf (const GLfloat *m);
GL_API void GL_APIENTRY glMultiTexCoord4f (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q);
GL_API void GL_APIENTRY glNormal3f (GLfloat nx, GLfloat ny, GLfloat nz);
-GL_API void GL_APIENTRY glOrthof (GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar);
+GL_API void GL_APIENTRY glOrthof (GLfloat l, GLfloat r, GLfloat b, GLfloat t, GLfloat n, GLfloat f);
GL_API void GL_APIENTRY glPointParameterf (GLenum pname, GLfloat param);
GL_API void GL_APIENTRY glPointParameterfv (GLenum pname, const GLfloat *params);
GL_API void GL_APIENTRY glPointSize (GLfloat size);
@@ -628,27 +440,25 @@
GL_API void GL_APIENTRY glTexParameterf (GLenum target, GLenum pname, GLfloat param);
GL_API void GL_APIENTRY glTexParameterfv (GLenum target, GLenum pname, const GLfloat *params);
GL_API void GL_APIENTRY glTranslatef (GLfloat x, GLfloat y, GLfloat z);
-
-/* Available in both Common and Common-Lite profiles */
GL_API void GL_APIENTRY glActiveTexture (GLenum texture);
-GL_API void GL_APIENTRY glAlphaFuncx (GLenum func, GLclampx ref);
+GL_API void GL_APIENTRY glAlphaFuncx (GLenum func, GLfixed ref);
GL_API void GL_APIENTRY glBindBuffer (GLenum target, GLuint buffer);
GL_API void GL_APIENTRY glBindTexture (GLenum target, GLuint texture);
GL_API void GL_APIENTRY glBlendFunc (GLenum sfactor, GLenum dfactor);
-GL_API void GL_APIENTRY glBufferData (GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage);
-GL_API void GL_APIENTRY glBufferSubData (GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid *data);
+GL_API void GL_APIENTRY glBufferData (GLenum target, GLsizeiptr size, const void *data, GLenum usage);
+GL_API void GL_APIENTRY glBufferSubData (GLenum target, GLintptr offset, GLsizeiptr size, const void *data);
GL_API void GL_APIENTRY glClear (GLbitfield mask);
-GL_API void GL_APIENTRY glClearColorx (GLclampx red, GLclampx green, GLclampx blue, GLclampx alpha);
-GL_API void GL_APIENTRY glClearDepthx (GLclampx depth);
+GL_API void GL_APIENTRY glClearColorx (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha);
+GL_API void GL_APIENTRY glClearDepthx (GLfixed depth);
GL_API void GL_APIENTRY glClearStencil (GLint s);
GL_API void GL_APIENTRY glClientActiveTexture (GLenum texture);
GL_API void GL_APIENTRY glClipPlanex (GLenum plane, const GLfixed *equation);
GL_API void GL_APIENTRY glColor4ub (GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha);
GL_API void GL_APIENTRY glColor4x (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha);
GL_API void GL_APIENTRY glColorMask (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha);
-GL_API void GL_APIENTRY glColorPointer (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
-GL_API void GL_APIENTRY glCompressedTexImage2D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data);
-GL_API void GL_APIENTRY glCompressedTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data);
+GL_API void GL_APIENTRY glColorPointer (GLint size, GLenum type, GLsizei stride, const void *pointer);
+GL_API void GL_APIENTRY glCompressedTexImage2D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data);
+GL_API void GL_APIENTRY glCompressedTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data);
GL_API void GL_APIENTRY glCopyTexImage2D (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border);
GL_API void GL_APIENTRY glCopyTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height);
GL_API void GL_APIENTRY glCullFace (GLenum mode);
@@ -656,33 +466,33 @@
GL_API void GL_APIENTRY glDeleteTextures (GLsizei n, const GLuint *textures);
GL_API void GL_APIENTRY glDepthFunc (GLenum func);
GL_API void GL_APIENTRY glDepthMask (GLboolean flag);
-GL_API void GL_APIENTRY glDepthRangex (GLclampx zNear, GLclampx zFar);
+GL_API void GL_APIENTRY glDepthRangex (GLfixed n, GLfixed f);
GL_API void GL_APIENTRY glDisable (GLenum cap);
GL_API void GL_APIENTRY glDisableClientState (GLenum array);
GL_API void GL_APIENTRY glDrawArrays (GLenum mode, GLint first, GLsizei count);
-GL_API void GL_APIENTRY glDrawElements (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices);
+GL_API void GL_APIENTRY glDrawElements (GLenum mode, GLsizei count, GLenum type, const void *indices);
GL_API void GL_APIENTRY glEnable (GLenum cap);
GL_API void GL_APIENTRY glEnableClientState (GLenum array);
GL_API void GL_APIENTRY glFinish (void);
GL_API void GL_APIENTRY glFlush (void);
GL_API void GL_APIENTRY glFogx (GLenum pname, GLfixed param);
-GL_API void GL_APIENTRY glFogxv (GLenum pname, const GLfixed *params);
+GL_API void GL_APIENTRY glFogxv (GLenum pname, const GLfixed *param);
GL_API void GL_APIENTRY glFrontFace (GLenum mode);
-GL_API void GL_APIENTRY glFrustumx (GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar);
-GL_API void GL_APIENTRY glGetBooleanv (GLenum pname, GLboolean *params);
+GL_API void GL_APIENTRY glFrustumx (GLfixed l, GLfixed r, GLfixed b, GLfixed t, GLfixed n, GLfixed f);
+GL_API void GL_APIENTRY glGetBooleanv (GLenum pname, GLboolean *data);
GL_API void GL_APIENTRY glGetBufferParameteriv (GLenum target, GLenum pname, GLint *params);
-GL_API void GL_APIENTRY glGetClipPlanex (GLenum pname, GLfixed eqn[4]);
+GL_API void GL_APIENTRY glGetClipPlanex (GLenum plane, GLfixed *equation);
GL_API void GL_APIENTRY glGenBuffers (GLsizei n, GLuint *buffers);
GL_API void GL_APIENTRY glGenTextures (GLsizei n, GLuint *textures);
GL_API GLenum GL_APIENTRY glGetError (void);
GL_API void GL_APIENTRY glGetFixedv (GLenum pname, GLfixed *params);
-GL_API void GL_APIENTRY glGetIntegerv (GLenum pname, GLint *params);
+GL_API void GL_APIENTRY glGetIntegerv (GLenum pname, GLint *data);
GL_API void GL_APIENTRY glGetLightxv (GLenum light, GLenum pname, GLfixed *params);
GL_API void GL_APIENTRY glGetMaterialxv (GLenum face, GLenum pname, GLfixed *params);
-GL_API void GL_APIENTRY glGetPointerv (GLenum pname, GLvoid **params);
-GL_API const GLubyte * GL_APIENTRY glGetString (GLenum name);
-GL_API void GL_APIENTRY glGetTexEnviv (GLenum env, GLenum pname, GLint *params);
-GL_API void GL_APIENTRY glGetTexEnvxv (GLenum env, GLenum pname, GLfixed *params);
+GL_API void GL_APIENTRY glGetPointerv (GLenum pname, void **params);
+GL_API const GLubyte *GL_APIENTRY glGetString (GLenum name);
+GL_API void GL_APIENTRY glGetTexEnviv (GLenum target, GLenum pname, GLint *params);
+GL_API void GL_APIENTRY glGetTexEnvxv (GLenum target, GLenum pname, GLfixed *params);
GL_API void GL_APIENTRY glGetTexParameteriv (GLenum target, GLenum pname, GLint *params);
GL_API void GL_APIENTRY glGetTexParameterxv (GLenum target, GLenum pname, GLfixed *params);
GL_API void GL_APIENTRY glHint (GLenum target, GLenum mode);
@@ -690,7 +500,7 @@
GL_API GLboolean GL_APIENTRY glIsEnabled (GLenum cap);
GL_API GLboolean GL_APIENTRY glIsTexture (GLuint texture);
GL_API void GL_APIENTRY glLightModelx (GLenum pname, GLfixed param);
-GL_API void GL_APIENTRY glLightModelxv (GLenum pname, const GLfixed *params);
+GL_API void GL_APIENTRY glLightModelxv (GLenum pname, const GLfixed *param);
GL_API void GL_APIENTRY glLightx (GLenum light, GLenum pname, GLfixed param);
GL_API void GL_APIENTRY glLightxv (GLenum light, GLenum pname, const GLfixed *params);
GL_API void GL_APIENTRY glLineWidthx (GLfixed width);
@@ -698,13 +508,13 @@
GL_API void GL_APIENTRY glLoadMatrixx (const GLfixed *m);
GL_API void GL_APIENTRY glLogicOp (GLenum opcode);
GL_API void GL_APIENTRY glMaterialx (GLenum face, GLenum pname, GLfixed param);
-GL_API void GL_APIENTRY glMaterialxv (GLenum face, GLenum pname, const GLfixed *params);
+GL_API void GL_APIENTRY glMaterialxv (GLenum face, GLenum pname, const GLfixed *param);
GL_API void GL_APIENTRY glMatrixMode (GLenum mode);
GL_API void GL_APIENTRY glMultMatrixx (const GLfixed *m);
-GL_API void GL_APIENTRY glMultiTexCoord4x (GLenum target, GLfixed s, GLfixed t, GLfixed r, GLfixed q);
+GL_API void GL_APIENTRY glMultiTexCoord4x (GLenum texture, GLfixed s, GLfixed t, GLfixed r, GLfixed q);
GL_API void GL_APIENTRY glNormal3x (GLfixed nx, GLfixed ny, GLfixed nz);
-GL_API void GL_APIENTRY glNormalPointer (GLenum type, GLsizei stride, const GLvoid *pointer);
-GL_API void GL_APIENTRY glOrthox (GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar);
+GL_API void GL_APIENTRY glNormalPointer (GLenum type, GLsizei stride, const void *pointer);
+GL_API void GL_APIENTRY glOrthox (GLfixed l, GLfixed r, GLfixed b, GLfixed t, GLfixed n, GLfixed f);
GL_API void GL_APIENTRY glPixelStorei (GLenum pname, GLint param);
GL_API void GL_APIENTRY glPointParameterx (GLenum pname, GLfixed param);
GL_API void GL_APIENTRY glPointParameterxv (GLenum pname, const GLfixed *params);
@@ -712,9 +522,9 @@
GL_API void GL_APIENTRY glPolygonOffsetx (GLfixed factor, GLfixed units);
GL_API void GL_APIENTRY glPopMatrix (void);
GL_API void GL_APIENTRY glPushMatrix (void);
-GL_API void GL_APIENTRY glReadPixels (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels);
+GL_API void GL_APIENTRY glReadPixels (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *pixels);
GL_API void GL_APIENTRY glRotatex (GLfixed angle, GLfixed x, GLfixed y, GLfixed z);
-GL_API void GL_APIENTRY glSampleCoverage (GLclampf value, GLboolean invert);
+GL_API void GL_APIENTRY glSampleCoverage (GLfloat value, GLboolean invert);
GL_API void GL_APIENTRY glSampleCoveragex (GLclampx value, GLboolean invert);
GL_API void GL_APIENTRY glScalex (GLfixed x, GLfixed y, GLfixed z);
GL_API void GL_APIENTRY glScissor (GLint x, GLint y, GLsizei width, GLsizei height);
@@ -722,49 +532,60 @@
GL_API void GL_APIENTRY glStencilFunc (GLenum func, GLint ref, GLuint mask);
GL_API void GL_APIENTRY glStencilMask (GLuint mask);
GL_API void GL_APIENTRY glStencilOp (GLenum fail, GLenum zfail, GLenum zpass);
-GL_API void GL_APIENTRY glTexCoordPointer (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
+GL_API void GL_APIENTRY glTexCoordPointer (GLint size, GLenum type, GLsizei stride, const void *pointer);
GL_API void GL_APIENTRY glTexEnvi (GLenum target, GLenum pname, GLint param);
GL_API void GL_APIENTRY glTexEnvx (GLenum target, GLenum pname, GLfixed param);
GL_API void GL_APIENTRY glTexEnviv (GLenum target, GLenum pname, const GLint *params);
GL_API void GL_APIENTRY glTexEnvxv (GLenum target, GLenum pname, const GLfixed *params);
-GL_API void GL_APIENTRY glTexImage2D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels);
+GL_API void GL_APIENTRY glTexImage2D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels);
GL_API void GL_APIENTRY glTexParameteri (GLenum target, GLenum pname, GLint param);
GL_API void GL_APIENTRY glTexParameterx (GLenum target, GLenum pname, GLfixed param);
GL_API void GL_APIENTRY glTexParameteriv (GLenum target, GLenum pname, const GLint *params);
GL_API void GL_APIENTRY glTexParameterxv (GLenum target, GLenum pname, const GLfixed *params);
-GL_API void GL_APIENTRY glTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels);
+GL_API void GL_APIENTRY glTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels);
GL_API void GL_APIENTRY glTranslatex (GLfixed x, GLfixed y, GLfixed z);
-GL_API void GL_APIENTRY glVertexPointer (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
+GL_API void GL_APIENTRY glVertexPointer (GLint size, GLenum type, GLsizei stride, const void *pointer);
GL_API void GL_APIENTRY glViewport (GLint x, GLint y, GLsizei width, GLsizei height);
+#endif /* GL_VERSION_ES_CM_1_0 */
-/*------------------------------------------------------------------------*
- * Required OES extension functions
- *------------------------------------------------------------------------*/
-
-/* GL_OES_read_format */
-#ifndef GL_OES_read_format
-#define GL_OES_read_format 1
-#endif
-
-/* GL_OES_compressed_paletted_texture */
#ifndef GL_OES_compressed_paletted_texture
#define GL_OES_compressed_paletted_texture 1
-#endif
+#define GL_PALETTE4_RGB8_OES 0x8B90
+#define GL_PALETTE4_RGBA8_OES 0x8B91
+#define GL_PALETTE4_R5_G6_B5_OES 0x8B92
+#define GL_PALETTE4_RGBA4_OES 0x8B93
+#define GL_PALETTE4_RGB5_A1_OES 0x8B94
+#define GL_PALETTE8_RGB8_OES 0x8B95
+#define GL_PALETTE8_RGBA8_OES 0x8B96
+#define GL_PALETTE8_R5_G6_B5_OES 0x8B97
+#define GL_PALETTE8_RGBA4_OES 0x8B98
+#define GL_PALETTE8_RGB5_A1_OES 0x8B99
+#endif /* GL_OES_compressed_paletted_texture */
-/* GL_OES_point_size_array */
#ifndef GL_OES_point_size_array
#define GL_OES_point_size_array 1
-GL_API void GL_APIENTRY glPointSizePointerOES (GLenum type, GLsizei stride, const GLvoid *pointer);
-#endif
+#define GL_POINT_SIZE_ARRAY_OES 0x8B9C
+#define GL_POINT_SIZE_ARRAY_TYPE_OES 0x898A
+#define GL_POINT_SIZE_ARRAY_STRIDE_OES 0x898B
+#define GL_POINT_SIZE_ARRAY_POINTER_OES 0x898C
+#define GL_POINT_SIZE_ARRAY_BUFFER_BINDING_OES 0x8B9F
+GL_API void GL_APIENTRY glPointSizePointerOES (GLenum type, GLsizei stride, const void *pointer);
+#endif /* GL_OES_point_size_array */
-/* GL_OES_point_sprite */
#ifndef GL_OES_point_sprite
#define GL_OES_point_sprite 1
-#endif
+#define GL_POINT_SPRITE_OES 0x8861
+#define GL_COORD_REPLACE_OES 0x8862
+#endif /* GL_OES_point_sprite */
+
+#ifndef GL_OES_read_format
+#define GL_OES_read_format 1
+#define GL_IMPLEMENTATION_COLOR_READ_TYPE_OES 0x8B9A
+#define GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES 0x8B9B
+#endif /* GL_OES_read_format */
#ifdef __cplusplus
}
#endif
-#endif /* __gl_h_ */
-
+#endif
diff --git a/opengl/include/GLES/glext.h b/opengl/include/GLES/glext.h
index 5843d5e..1a150e3 100644
--- a/opengl/include/GLES/glext.h
+++ b/opengl/include/GLES/glext.h
@@ -1,613 +1,141 @@
#ifndef __glext_h_
-#define __glext_h_
-
-/* $Revision: 20798 $ on $Date:: 2013-03-07 01:19:34 -0800 #$ */
+#define __glext_h_ 1
#ifdef __cplusplus
extern "C" {
#endif
/*
- * This document is licensed under the SGI Free Software B License Version
- * 2.0. For details, see http://oss.sgi.com/projects/FreeB/ .
- */
+** Copyright (c) 2013-2017 The Khronos Group Inc.
+**
+** Permission is hereby granted, free of charge, to any person obtaining a
+** copy of this software and/or associated documentation files (the
+** "Materials"), to deal in the Materials without restriction, including
+** without limitation the rights to use, copy, modify, merge, publish,
+** distribute, sublicense, and/or sell copies of the Materials, and to
+** permit persons to whom the Materials are furnished to do so, subject to
+** the following conditions:
+**
+** The above copyright notice and this permission notice shall be included
+** in all copies or substantial portions of the Materials.
+**
+** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+*/
+/*
+** This header is generated from the Khronos OpenGL / OpenGL ES XML
+** API Registry. The current version of the Registry, generator scripts
+** used to make the header, and the header can be found at
+** https://github.com/KhronosGroup/OpenGL-Registry
+*/
#ifndef GL_APIENTRYP
-# define GL_APIENTRYP GL_APIENTRY*
+#define GL_APIENTRYP GL_APIENTRY*
#endif
-/*------------------------------------------------------------------------*
- * OES extension tokens
- *------------------------------------------------------------------------*/
+/* Generated on date 20170613 */
-/* GL_OES_blend_equation_separate */
-#ifndef GL_OES_blend_equation_separate
-/* BLEND_EQUATION_RGB_OES same as BLEND_EQUATION_OES */
-#define GL_BLEND_EQUATION_RGB_OES 0x8009
-#define GL_BLEND_EQUATION_ALPHA_OES 0x883D
-#endif
-
-/* GL_OES_blend_func_separate */
-#ifndef GL_OES_blend_func_separate
-#define GL_BLEND_DST_RGB_OES 0x80C8
-#define GL_BLEND_SRC_RGB_OES 0x80C9
-#define GL_BLEND_DST_ALPHA_OES 0x80CA
-#define GL_BLEND_SRC_ALPHA_OES 0x80CB
-#endif
-
-/* GL_OES_blend_subtract */
-#ifndef GL_OES_blend_subtract
-#define GL_BLEND_EQUATION_OES 0x8009
-#define GL_FUNC_ADD_OES 0x8006
-#define GL_FUNC_SUBTRACT_OES 0x800A
-#define GL_FUNC_REVERSE_SUBTRACT_OES 0x800B
-#endif
-
-/* GL_OES_compressed_ETC1_RGB8_texture */
-#ifndef GL_OES_compressed_ETC1_RGB8_texture
-#define GL_ETC1_RGB8_OES 0x8D64
-#endif
-
-/* GL_OES_depth24 */
-#ifndef GL_OES_depth24
-#define GL_DEPTH_COMPONENT24_OES 0x81A6
-#endif
-
-/* GL_OES_depth32 */
-#ifndef GL_OES_depth32
-#define GL_DEPTH_COMPONENT32_OES 0x81A7
-#endif
-
-/* GL_OES_draw_texture */
-#ifndef GL_OES_draw_texture
-#define GL_TEXTURE_CROP_RECT_OES 0x8B9D
-#endif
-
-/* GL_OES_EGL_image */
-#ifndef GL_OES_EGL_image
-typedef void* GLeglImageOES;
-#endif
-
-/* GL_OES_EGL_image_external */
-#ifndef GL_OES_EGL_image_external
-/* GLeglImageOES defined in GL_OES_EGL_image already. */
-#define GL_TEXTURE_EXTERNAL_OES 0x8D65
-#define GL_TEXTURE_BINDING_EXTERNAL_OES 0x8D67
-#define GL_REQUIRED_TEXTURE_IMAGE_UNITS_OES 0x8D68
-#endif
-
-/* GL_OES_element_index_uint */
-#ifndef GL_OES_element_index_uint
-#define GL_UNSIGNED_INT 0x1405
-#endif
-
-/* GL_OES_fixed_point */
-#ifndef GL_OES_fixed_point
-#define GL_FIXED_OES 0x140C
-#endif
-
-/* GL_OES_framebuffer_object */
-#ifndef GL_OES_framebuffer_object
-#define GL_NONE_OES 0
-#define GL_FRAMEBUFFER_OES 0x8D40
-#define GL_RENDERBUFFER_OES 0x8D41
-#define GL_RGBA4_OES 0x8056
-#define GL_RGB5_A1_OES 0x8057
-#define GL_RGB565_OES 0x8D62
-#define GL_DEPTH_COMPONENT16_OES 0x81A5
-#define GL_RENDERBUFFER_WIDTH_OES 0x8D42
-#define GL_RENDERBUFFER_HEIGHT_OES 0x8D43
-#define GL_RENDERBUFFER_INTERNAL_FORMAT_OES 0x8D44
-#define GL_RENDERBUFFER_RED_SIZE_OES 0x8D50
-#define GL_RENDERBUFFER_GREEN_SIZE_OES 0x8D51
-#define GL_RENDERBUFFER_BLUE_SIZE_OES 0x8D52
-#define GL_RENDERBUFFER_ALPHA_SIZE_OES 0x8D53
-#define GL_RENDERBUFFER_DEPTH_SIZE_OES 0x8D54
-#define GL_RENDERBUFFER_STENCIL_SIZE_OES 0x8D55
-#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_OES 0x8CD0
-#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_OES 0x8CD1
-#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_OES 0x8CD2
-#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_OES 0x8CD3
-#define GL_COLOR_ATTACHMENT0_OES 0x8CE0
-#define GL_DEPTH_ATTACHMENT_OES 0x8D00
-#define GL_STENCIL_ATTACHMENT_OES 0x8D20
-#define GL_FRAMEBUFFER_COMPLETE_OES 0x8CD5
-#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES 0x8CD6
-#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_OES 0x8CD7
-#define GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_OES 0x8CD9
-#define GL_FRAMEBUFFER_INCOMPLETE_FORMATS_OES 0x8CDA
-#define GL_FRAMEBUFFER_UNSUPPORTED_OES 0x8CDD
-#define GL_FRAMEBUFFER_BINDING_OES 0x8CA6
-#define GL_RENDERBUFFER_BINDING_OES 0x8CA7
-#define GL_MAX_RENDERBUFFER_SIZE_OES 0x84E8
-#define GL_INVALID_FRAMEBUFFER_OPERATION_OES 0x0506
-#endif
-
-/* GL_OES_mapbuffer */
-#ifndef GL_OES_mapbuffer
-#define GL_WRITE_ONLY_OES 0x88B9
-#define GL_BUFFER_ACCESS_OES 0x88BB
-#define GL_BUFFER_MAPPED_OES 0x88BC
-#define GL_BUFFER_MAP_POINTER_OES 0x88BD
-#endif
-
-/* GL_OES_matrix_get */
-#ifndef GL_OES_matrix_get
-#define GL_MODELVIEW_MATRIX_FLOAT_AS_INT_BITS_OES 0x898D
-#define GL_PROJECTION_MATRIX_FLOAT_AS_INT_BITS_OES 0x898E
-#define GL_TEXTURE_MATRIX_FLOAT_AS_INT_BITS_OES 0x898F
-#endif
-
-/* GL_OES_matrix_palette */
-#ifndef GL_OES_matrix_palette
-#define GL_MAX_VERTEX_UNITS_OES 0x86A4
-#define GL_MAX_PALETTE_MATRICES_OES 0x8842
-#define GL_MATRIX_PALETTE_OES 0x8840
-#define GL_MATRIX_INDEX_ARRAY_OES 0x8844
-#define GL_WEIGHT_ARRAY_OES 0x86AD
-#define GL_CURRENT_PALETTE_MATRIX_OES 0x8843
-#define GL_MATRIX_INDEX_ARRAY_SIZE_OES 0x8846
-#define GL_MATRIX_INDEX_ARRAY_TYPE_OES 0x8847
-#define GL_MATRIX_INDEX_ARRAY_STRIDE_OES 0x8848
-#define GL_MATRIX_INDEX_ARRAY_POINTER_OES 0x8849
-#define GL_MATRIX_INDEX_ARRAY_BUFFER_BINDING_OES 0x8B9E
-#define GL_WEIGHT_ARRAY_SIZE_OES 0x86AB
-#define GL_WEIGHT_ARRAY_TYPE_OES 0x86A9
-#define GL_WEIGHT_ARRAY_STRIDE_OES 0x86AA
-#define GL_WEIGHT_ARRAY_POINTER_OES 0x86AC
-#define GL_WEIGHT_ARRAY_BUFFER_BINDING_OES 0x889E
-#endif
-
-/* GL_OES_packed_depth_stencil */
-#ifndef GL_OES_packed_depth_stencil
-#define GL_DEPTH_STENCIL_OES 0x84F9
-#define GL_UNSIGNED_INT_24_8_OES 0x84FA
-#define GL_DEPTH24_STENCIL8_OES 0x88F0
-#endif
-
-/* GL_OES_required_internalformat */
-/* No new tokens introduced by this extension. */
-
-/* GL_OES_rgb8_rgba8 */
-#ifndef GL_OES_rgb8_rgba8
-#define GL_RGB8_OES 0x8051
-#define GL_RGBA8_OES 0x8058
-#endif
-
-/* GL_OES_stencil1 */
-#ifndef GL_OES_stencil1
-#define GL_STENCIL_INDEX1_OES 0x8D46
-#endif
-
-/* GL_OES_stencil4 */
-#ifndef GL_OES_stencil4
-#define GL_STENCIL_INDEX4_OES 0x8D47
-#endif
-
-/* GL_OES_stencil8 */
-#ifndef GL_OES_stencil8
-#define GL_STENCIL_INDEX8_OES 0x8D48
-#endif
-
-/* GL_OES_stencil_wrap */
-#ifndef GL_OES_stencil_wrap
-#define GL_INCR_WRAP_OES 0x8507
-#define GL_DECR_WRAP_OES 0x8508
-#endif
-
-/* GL_OES_texture_cube_map */
-#ifndef GL_OES_texture_cube_map
-#define GL_NORMAL_MAP_OES 0x8511
-#define GL_REFLECTION_MAP_OES 0x8512
-#define GL_TEXTURE_CUBE_MAP_OES 0x8513
-#define GL_TEXTURE_BINDING_CUBE_MAP_OES 0x8514
-#define GL_TEXTURE_CUBE_MAP_POSITIVE_X_OES 0x8515
-#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X_OES 0x8516
-#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y_OES 0x8517
-#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_OES 0x8518
-#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z_OES 0x8519
-#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_OES 0x851A
-#define GL_MAX_CUBE_MAP_TEXTURE_SIZE_OES 0x851C
-#define GL_TEXTURE_GEN_MODE_OES 0x2500
-#define GL_TEXTURE_GEN_STR_OES 0x8D60
-#endif
-
-/* GL_OES_texture_mirrored_repeat */
-#ifndef GL_OES_texture_mirrored_repeat
-#define GL_MIRRORED_REPEAT_OES 0x8370
-#endif
-
-/* GL_OES_vertex_array_object */
-#ifndef GL_OES_vertex_array_object
-#define GL_VERTEX_ARRAY_BINDING_OES 0x85B5
-#endif
-
-/*------------------------------------------------------------------------*
- * AMD extension tokens
- *------------------------------------------------------------------------*/
-
-/* GL_AMD_compressed_3DC_texture */
-#ifndef GL_AMD_compressed_3DC_texture
-#define GL_3DC_X_AMD 0x87F9
-#define GL_3DC_XY_AMD 0x87FA
-#endif
-
-/* GL_AMD_compressed_ATC_texture */
-#ifndef GL_AMD_compressed_ATC_texture
-#define GL_ATC_RGB_AMD 0x8C92
-#define GL_ATC_RGBA_EXPLICIT_ALPHA_AMD 0x8C93
-#define GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD 0x87EE
-#endif
-
-/*------------------------------------------------------------------------*
- * APPLE extension tokens
- *------------------------------------------------------------------------*/
-
-/* GL_APPLE_copy_texture_levels */
-/* No new tokens introduced by this extension. */
-
-/* GL_APPLE_framebuffer_multisample */
-#ifndef GL_APPLE_framebuffer_multisample
-#define GL_RENDERBUFFER_SAMPLES_APPLE 0x8CAB
-#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_APPLE 0x8D56
-#define GL_MAX_SAMPLES_APPLE 0x8D57
-#define GL_READ_FRAMEBUFFER_APPLE 0x8CA8
-#define GL_DRAW_FRAMEBUFFER_APPLE 0x8CA9
-#define GL_DRAW_FRAMEBUFFER_BINDING_APPLE 0x8CA6
-#define GL_READ_FRAMEBUFFER_BINDING_APPLE 0x8CAA
-#endif
-
-/* GL_APPLE_sync */
-#ifndef GL_APPLE_sync
-
-/* These types are defined with reference to <inttypes.h>
- * in the Apple extension spec, but here we use the Khronos
- * portable types in khrplatform.h, and assume those types
- * are always defined.
- * If any other extensions using these types are defined,
- * the typedefs must move out of this block and be shared.
+/* Generated C header for:
+ * API: gles1
+ * Profile: common
+ * Versions considered: .*
+ * Versions emitted: _nomatch_^
+ * Default extensions included: gles1
+ * Additional extensions included: _nomatch_^
+ * Extensions removed: ^(GL_OES_read_format|GL_OES_compressed_paletted_texture|GL_OES_point_size_array|GL_OES_point_sprite)$
*/
-typedef khronos_int64_t GLint64;
-typedef khronos_uint64_t GLuint64;
-typedef struct __GLsync *GLsync;
-#define GL_SYNC_OBJECT_APPLE 0x8A53
-#define GL_MAX_SERVER_WAIT_TIMEOUT_APPLE 0x9111
-#define GL_OBJECT_TYPE_APPLE 0x9112
-#define GL_SYNC_CONDITION_APPLE 0x9113
-#define GL_SYNC_STATUS_APPLE 0x9114
-#define GL_SYNC_FLAGS_APPLE 0x9115
-#define GL_SYNC_FENCE_APPLE 0x9116
-#define GL_SYNC_GPU_COMMANDS_COMPLETE_APPLE 0x9117
-#define GL_UNSIGNALED_APPLE 0x9118
-#define GL_SIGNALED_APPLE 0x9119
-#define GL_ALREADY_SIGNALED_APPLE 0x911A
-#define GL_TIMEOUT_EXPIRED_APPLE 0x911B
-#define GL_CONDITION_SATISFIED_APPLE 0x911C
-#define GL_WAIT_FAILED_APPLE 0x911D
-#define GL_SYNC_FLUSH_COMMANDS_BIT_APPLE 0x00000001
-#define GL_TIMEOUT_IGNORED_APPLE 0xFFFFFFFFFFFFFFFFull
+#ifndef GL_OES_EGL_image
+#define GL_OES_EGL_image 1
+typedef void *GLeglImageOES;
+typedef void (GL_APIENTRYP PFNGLEGLIMAGETARGETTEXTURE2DOESPROC) (GLenum target, GLeglImageOES image);
+typedef void (GL_APIENTRYP PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC) (GLenum target, GLeglImageOES image);
+#ifdef GL_GLEXT_PROTOTYPES
+GL_API void GL_APIENTRY glEGLImageTargetTexture2DOES (GLenum target, GLeglImageOES image);
+GL_API void GL_APIENTRY glEGLImageTargetRenderbufferStorageOES (GLenum target, GLeglImageOES image);
#endif
+#endif /* GL_OES_EGL_image */
-/* GL_APPLE_texture_2D_limited_npot */
-/* No new tokens introduced by this extension. */
+#ifndef GL_OES_EGL_image_external
+#define GL_OES_EGL_image_external 1
+#define GL_TEXTURE_EXTERNAL_OES 0x8D65
+#define GL_TEXTURE_BINDING_EXTERNAL_OES 0x8D67
+#define GL_REQUIRED_TEXTURE_IMAGE_UNITS_OES 0x8D68
+#endif /* GL_OES_EGL_image_external */
-/* GL_APPLE_texture_format_BGRA8888 */
-#ifndef GL_APPLE_texture_format_BGRA8888
-#define GL_BGRA_EXT 0x80E1
-#endif
-
-/* GL_APPLE_texture_max_level */
-#ifndef GL_APPLE_texture_max_level
-#define GL_TEXTURE_MAX_LEVEL_APPLE 0x813D
-#endif
-
-/*------------------------------------------------------------------------*
- * ARM extension tokens
- *------------------------------------------------------------------------*/
-
-/* GL_ARM_rgba8 */
-/* No new tokens introduced by this extension. */
-
-/*------------------------------------------------------------------------*
- * EXT extension tokens
- *------------------------------------------------------------------------*/
-
-/* GL_EXT_blend_minmax */
-#ifndef GL_EXT_blend_minmax
-#define GL_MIN_EXT 0x8007
-#define GL_MAX_EXT 0x8008
-#endif
-
-/* GL_EXT_discard_framebuffer */
-#ifndef GL_EXT_discard_framebuffer
-#define GL_COLOR_EXT 0x1800
-#define GL_DEPTH_EXT 0x1801
-#define GL_STENCIL_EXT 0x1802
-#endif
-
-/* GL_EXT_map_buffer_range */
-#ifndef GL_EXT_map_buffer_range
-#define GL_MAP_READ_BIT_EXT 0x0001
-#define GL_MAP_WRITE_BIT_EXT 0x0002
-#define GL_MAP_INVALIDATE_RANGE_BIT_EXT 0x0004
-#define GL_MAP_INVALIDATE_BUFFER_BIT_EXT 0x0008
-#define GL_MAP_FLUSH_EXPLICIT_BIT_EXT 0x0010
-#define GL_MAP_UNSYNCHRONIZED_BIT_EXT 0x0020
-#endif
-
-/* GL_EXT_multisampled_render_to_texture */
-#ifndef GL_EXT_multisampled_render_to_texture
-#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_SAMPLES_EXT 0x8D6C
-/* reuse values from GL_EXT_framebuffer_multisample (desktop extension) */
-#define GL_RENDERBUFFER_SAMPLES_EXT 0x8CAB
-#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT 0x8D56
-#define GL_MAX_SAMPLES_EXT 0x8D57
-#endif
-
-/* GL_EXT_multi_draw_arrays */
-/* No new tokens introduced by this extension. */
-
-/* GL_EXT_read_format_bgra */
-#ifndef GL_EXT_read_format_bgra
-#define GL_BGRA_EXT 0x80E1
-#define GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT 0x8365
-#define GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT 0x8366
-#endif
-
-/* GL_EXT_robustness */
-#ifndef GL_EXT_robustness
-/* reuse GL_NO_ERROR */
-#define GL_GUILTY_CONTEXT_RESET_EXT 0x8253
-#define GL_INNOCENT_CONTEXT_RESET_EXT 0x8254
-#define GL_UNKNOWN_CONTEXT_RESET_EXT 0x8255
-#define GL_CONTEXT_ROBUST_ACCESS_EXT 0x90F3
-#define GL_RESET_NOTIFICATION_STRATEGY_EXT 0x8256
-#define GL_LOSE_CONTEXT_ON_RESET_EXT 0x8252
-#define GL_NO_RESET_NOTIFICATION_EXT 0x8261
-#endif
-
-/* GL_EXT_sRGB */
-#ifndef GL_EXT_sRGB
-#define GL_SRGB_EXT 0x8C40
-#define GL_SRGB_ALPHA_EXT 0x8C42
-#define GL_SRGB8_ALPHA8_EXT 0x8C43
-#define GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT 0x8210
-#endif
-
-/* GL_EXT_texture_compression_dxt1 */
-#ifndef GL_EXT_texture_compression_dxt1
-#define GL_COMPRESSED_RGB_S3TC_DXT1_EXT 0x83F0
-#define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1
-#endif
-
-/* GL_EXT_texture_filter_anisotropic */
-#ifndef GL_EXT_texture_filter_anisotropic
-#define GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE
-#define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF
-#endif
-
-/* GL_EXT_texture_format_BGRA8888 */
-#ifndef GL_EXT_texture_format_BGRA8888
-#define GL_BGRA_EXT 0x80E1
-#endif
-
-/* GL_EXT_texture_lod_bias */
-#ifndef GL_EXT_texture_lod_bias
-#define GL_MAX_TEXTURE_LOD_BIAS_EXT 0x84FD
-#define GL_TEXTURE_FILTER_CONTROL_EXT 0x8500
-#define GL_TEXTURE_LOD_BIAS_EXT 0x8501
-#endif
-
-/* GL_EXT_texture_storage */
-#ifndef GL_EXT_texture_storage
-#define GL_TEXTURE_IMMUTABLE_FORMAT_EXT 0x912F
-#define GL_ALPHA8_EXT 0x803C
-#define GL_LUMINANCE8_EXT 0x8040
-#define GL_LUMINANCE8_ALPHA8_EXT 0x8045
-#define GL_RGBA32F_EXT 0x8814
-#define GL_RGB32F_EXT 0x8815
-#define GL_ALPHA32F_EXT 0x8816
-#define GL_LUMINANCE32F_EXT 0x8818
-#define GL_LUMINANCE_ALPHA32F_EXT 0x8819
-/* reuse GL_RGBA16F_EXT */
-#define GL_RGB16F_EXT 0x881B
-#define GL_ALPHA16F_EXT 0x881C
-#define GL_LUMINANCE16F_EXT 0x881E
-#define GL_LUMINANCE_ALPHA16F_EXT 0x881F
-#define GL_RGB10_A2_EXT 0x8059
-#define GL_RGB10_EXT 0x8052
-#define GL_BGRA8_EXT 0x93A1
-#endif
-
-/*------------------------------------------------------------------------*
- * IMG extension tokens
- *------------------------------------------------------------------------*/
-
-/* GL_IMG_read_format */
-#ifndef GL_IMG_read_format
-#define GL_BGRA_IMG 0x80E1
-#define GL_UNSIGNED_SHORT_4_4_4_4_REV_IMG 0x8365
-#endif
-
-/* GL_IMG_texture_compression_pvrtc */
-#ifndef GL_IMG_texture_compression_pvrtc
-#define GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG 0x8C00
-#define GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG 0x8C01
-#define GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG 0x8C02
-#define GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG 0x8C03
-#endif
-
-/* GL_IMG_texture_env_enhanced_fixed_function */
-#ifndef GL_IMG_texture_env_enhanced_fixed_function
-#define GL_MODULATE_COLOR_IMG 0x8C04
-#define GL_RECIP_ADD_SIGNED_ALPHA_IMG 0x8C05
-#define GL_TEXTURE_ALPHA_MODULATE_IMG 0x8C06
-#define GL_FACTOR_ALPHA_MODULATE_IMG 0x8C07
-#define GL_FRAGMENT_ALPHA_MODULATE_IMG 0x8C08
-#define GL_ADD_BLEND_IMG 0x8C09
-#define GL_DOT3_RGBA_IMG 0x86AF
-#endif
-
-/* GL_IMG_user_clip_plane */
-#ifndef GL_IMG_user_clip_plane
-#define GL_CLIP_PLANE0_IMG 0x3000
-#define GL_CLIP_PLANE1_IMG 0x3001
-#define GL_CLIP_PLANE2_IMG 0x3002
-#define GL_CLIP_PLANE3_IMG 0x3003
-#define GL_CLIP_PLANE4_IMG 0x3004
-#define GL_CLIP_PLANE5_IMG 0x3005
-#define GL_MAX_CLIP_PLANES_IMG 0x0D32
-#endif
-
-/* GL_IMG_multisampled_render_to_texture */
-#ifndef GL_IMG_multisampled_render_to_texture
-#define GL_RENDERBUFFER_SAMPLES_IMG 0x9133
-#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_IMG 0x9134
-#define GL_MAX_SAMPLES_IMG 0x9135
-#define GL_TEXTURE_SAMPLES_IMG 0x9136
-#endif
-
-/*------------------------------------------------------------------------*
- * NV extension tokens
- *------------------------------------------------------------------------*/
-
-/* GL_NV_fence */
-#ifndef GL_NV_fence
-#define GL_ALL_COMPLETED_NV 0x84F2
-#define GL_FENCE_STATUS_NV 0x84F3
-#define GL_FENCE_CONDITION_NV 0x84F4
-#endif
-
-/*------------------------------------------------------------------------*
- * QCOM extension tokens
- *------------------------------------------------------------------------*/
-
-/* GL_QCOM_driver_control */
-/* No new tokens introduced by this extension. */
-
-/* GL_QCOM_extended_get */
-#ifndef GL_QCOM_extended_get
-#define GL_TEXTURE_WIDTH_QCOM 0x8BD2
-#define GL_TEXTURE_HEIGHT_QCOM 0x8BD3
-#define GL_TEXTURE_DEPTH_QCOM 0x8BD4
-#define GL_TEXTURE_INTERNAL_FORMAT_QCOM 0x8BD5
-#define GL_TEXTURE_FORMAT_QCOM 0x8BD6
-#define GL_TEXTURE_TYPE_QCOM 0x8BD7
-#define GL_TEXTURE_IMAGE_VALID_QCOM 0x8BD8
-#define GL_TEXTURE_NUM_LEVELS_QCOM 0x8BD9
-#define GL_TEXTURE_TARGET_QCOM 0x8BDA
-#define GL_TEXTURE_OBJECT_VALID_QCOM 0x8BDB
-#define GL_STATE_RESTORE 0x8BDC
-#endif
-
-/* GL_QCOM_extended_get2 */
-/* No new tokens introduced by this extension. */
-
-/* GL_QCOM_perfmon_global_mode */
-#ifndef GL_QCOM_perfmon_global_mode
-#define GL_PERFMON_GLOBAL_MODE_QCOM 0x8FA0
-#endif
-
-/* GL_QCOM_writeonly_rendering */
-#ifndef GL_QCOM_writeonly_rendering
-#define GL_WRITEONLY_RENDERING_QCOM 0x8823
-#endif
-
-/* GL_QCOM_tiled_rendering */
-#ifndef GL_QCOM_tiled_rendering
-#define GL_COLOR_BUFFER_BIT0_QCOM 0x00000001
-#define GL_COLOR_BUFFER_BIT1_QCOM 0x00000002
-#define GL_COLOR_BUFFER_BIT2_QCOM 0x00000004
-#define GL_COLOR_BUFFER_BIT3_QCOM 0x00000008
-#define GL_COLOR_BUFFER_BIT4_QCOM 0x00000010
-#define GL_COLOR_BUFFER_BIT5_QCOM 0x00000020
-#define GL_COLOR_BUFFER_BIT6_QCOM 0x00000040
-#define GL_COLOR_BUFFER_BIT7_QCOM 0x00000080
-#define GL_DEPTH_BUFFER_BIT0_QCOM 0x00000100
-#define GL_DEPTH_BUFFER_BIT1_QCOM 0x00000200
-#define GL_DEPTH_BUFFER_BIT2_QCOM 0x00000400
-#define GL_DEPTH_BUFFER_BIT3_QCOM 0x00000800
-#define GL_DEPTH_BUFFER_BIT4_QCOM 0x00001000
-#define GL_DEPTH_BUFFER_BIT5_QCOM 0x00002000
-#define GL_DEPTH_BUFFER_BIT6_QCOM 0x00004000
-#define GL_DEPTH_BUFFER_BIT7_QCOM 0x00008000
-#define GL_STENCIL_BUFFER_BIT0_QCOM 0x00010000
-#define GL_STENCIL_BUFFER_BIT1_QCOM 0x00020000
-#define GL_STENCIL_BUFFER_BIT2_QCOM 0x00040000
-#define GL_STENCIL_BUFFER_BIT3_QCOM 0x00080000
-#define GL_STENCIL_BUFFER_BIT4_QCOM 0x00100000
-#define GL_STENCIL_BUFFER_BIT5_QCOM 0x00200000
-#define GL_STENCIL_BUFFER_BIT6_QCOM 0x00400000
-#define GL_STENCIL_BUFFER_BIT7_QCOM 0x00800000
-#define GL_MULTISAMPLE_BUFFER_BIT0_QCOM 0x01000000
-#define GL_MULTISAMPLE_BUFFER_BIT1_QCOM 0x02000000
-#define GL_MULTISAMPLE_BUFFER_BIT2_QCOM 0x04000000
-#define GL_MULTISAMPLE_BUFFER_BIT3_QCOM 0x08000000
-#define GL_MULTISAMPLE_BUFFER_BIT4_QCOM 0x10000000
-#define GL_MULTISAMPLE_BUFFER_BIT5_QCOM 0x20000000
-#define GL_MULTISAMPLE_BUFFER_BIT6_QCOM 0x40000000
-#define GL_MULTISAMPLE_BUFFER_BIT7_QCOM 0x80000000
-#endif
-
-/*------------------------------------------------------------------------*
- * End of extension tokens, start of corresponding extension functions
- *------------------------------------------------------------------------*/
-
-/*------------------------------------------------------------------------*
- * OES extension functions
- *------------------------------------------------------------------------*/
-
-/* GL_OES_blend_equation_separate */
#ifndef GL_OES_blend_equation_separate
#define GL_OES_blend_equation_separate 1
+#define GL_BLEND_EQUATION_RGB_OES 0x8009
+#define GL_BLEND_EQUATION_ALPHA_OES 0x883D
+typedef void (GL_APIENTRYP PFNGLBLENDEQUATIONSEPARATEOESPROC) (GLenum modeRGB, GLenum modeAlpha);
#ifdef GL_GLEXT_PROTOTYPES
GL_API void GL_APIENTRY glBlendEquationSeparateOES (GLenum modeRGB, GLenum modeAlpha);
#endif
-typedef void (GL_APIENTRYP PFNGLBLENDEQUATIONSEPARATEOESPROC) (GLenum modeRGB, GLenum modeAlpha);
-#endif
+#endif /* GL_OES_blend_equation_separate */
-/* GL_OES_blend_func_separate */
#ifndef GL_OES_blend_func_separate
#define GL_OES_blend_func_separate 1
+#define GL_BLEND_DST_RGB_OES 0x80C8
+#define GL_BLEND_SRC_RGB_OES 0x80C9
+#define GL_BLEND_DST_ALPHA_OES 0x80CA
+#define GL_BLEND_SRC_ALPHA_OES 0x80CB
+typedef void (GL_APIENTRYP PFNGLBLENDFUNCSEPARATEOESPROC) (GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);
#ifdef GL_GLEXT_PROTOTYPES
GL_API void GL_APIENTRY glBlendFuncSeparateOES (GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);
#endif
-typedef void (GL_APIENTRYP PFNGLBLENDFUNCSEPARATEOESPROC) (GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);
-#endif
+#endif /* GL_OES_blend_func_separate */
-/* GL_OES_blend_subtract */
#ifndef GL_OES_blend_subtract
#define GL_OES_blend_subtract 1
+#define GL_BLEND_EQUATION_OES 0x8009
+#define GL_FUNC_ADD_OES 0x8006
+#define GL_FUNC_SUBTRACT_OES 0x800A
+#define GL_FUNC_REVERSE_SUBTRACT_OES 0x800B
+typedef void (GL_APIENTRYP PFNGLBLENDEQUATIONOESPROC) (GLenum mode);
#ifdef GL_GLEXT_PROTOTYPES
GL_API void GL_APIENTRY glBlendEquationOES (GLenum mode);
#endif
-typedef void (GL_APIENTRYP PFNGLBLENDEQUATIONOESPROC) (GLenum mode);
-#endif
+#endif /* GL_OES_blend_subtract */
-/* GL_OES_byte_coordinates */
#ifndef GL_OES_byte_coordinates
#define GL_OES_byte_coordinates 1
-#endif
+#endif /* GL_OES_byte_coordinates */
-/* GL_OES_compressed_ETC1_RGB8_texture */
+#ifndef GL_OES_compressed_ETC1_RGB8_sub_texture
+#define GL_OES_compressed_ETC1_RGB8_sub_texture 1
+#endif /* GL_OES_compressed_ETC1_RGB8_sub_texture */
+
#ifndef GL_OES_compressed_ETC1_RGB8_texture
#define GL_OES_compressed_ETC1_RGB8_texture 1
-#endif
+#define GL_ETC1_RGB8_OES 0x8D64
+#endif /* GL_OES_compressed_ETC1_RGB8_texture */
-/* GL_OES_depth24 */
#ifndef GL_OES_depth24
#define GL_OES_depth24 1
-#endif
+#define GL_DEPTH_COMPONENT24_OES 0x81A6
+#endif /* GL_OES_depth24 */
-/* GL_OES_depth32 */
#ifndef GL_OES_depth32
#define GL_OES_depth32 1
-#endif
+#define GL_DEPTH_COMPONENT32_OES 0x81A7
+#endif /* GL_OES_depth32 */
-/* GL_OES_draw_texture */
#ifndef GL_OES_draw_texture
#define GL_OES_draw_texture 1
+#define GL_TEXTURE_CROP_RECT_OES 0x8B9D
+typedef void (GL_APIENTRYP PFNGLDRAWTEXSOESPROC) (GLshort x, GLshort y, GLshort z, GLshort width, GLshort height);
+typedef void (GL_APIENTRYP PFNGLDRAWTEXIOESPROC) (GLint x, GLint y, GLint z, GLint width, GLint height);
+typedef void (GL_APIENTRYP PFNGLDRAWTEXXOESPROC) (GLfixed x, GLfixed y, GLfixed z, GLfixed width, GLfixed height);
+typedef void (GL_APIENTRYP PFNGLDRAWTEXSVOESPROC) (const GLshort *coords);
+typedef void (GL_APIENTRYP PFNGLDRAWTEXIVOESPROC) (const GLint *coords);
+typedef void (GL_APIENTRYP PFNGLDRAWTEXXVOESPROC) (const GLfixed *coords);
+typedef void (GL_APIENTRYP PFNGLDRAWTEXFOESPROC) (GLfloat x, GLfloat y, GLfloat z, GLfloat width, GLfloat height);
+typedef void (GL_APIENTRYP PFNGLDRAWTEXFVOESPROC) (const GLfloat *coords);
#ifdef GL_GLEXT_PROTOTYPES
GL_API void GL_APIENTRY glDrawTexsOES (GLshort x, GLshort y, GLshort z, GLshort width, GLshort height);
GL_API void GL_APIENTRY glDrawTexiOES (GLint x, GLint y, GLint z, GLint width, GLint height);
@@ -618,357 +146,425 @@
GL_API void GL_APIENTRY glDrawTexfOES (GLfloat x, GLfloat y, GLfloat z, GLfloat width, GLfloat height);
GL_API void GL_APIENTRY glDrawTexfvOES (const GLfloat *coords);
#endif
-typedef void (GL_APIENTRYP PFNGLDRAWTEXSOESPROC) (GLshort x, GLshort y, GLshort z, GLshort width, GLshort height);
-typedef void (GL_APIENTRYP PFNGLDRAWTEXIOESPROC) (GLint x, GLint y, GLint z, GLint width, GLint height);
-typedef void (GL_APIENTRYP PFNGLDRAWTEXXOESPROC) (GLfixed x, GLfixed y, GLfixed z, GLfixed width, GLfixed height);
-typedef void (GL_APIENTRYP PFNGLDRAWTEXSVOESPROC) (const GLshort *coords);
-typedef void (GL_APIENTRYP PFNGLDRAWTEXIVOESPROC) (const GLint *coords);
-typedef void (GL_APIENTRYP PFNGLDRAWTEXXVOESPROC) (const GLfixed *coords);
-typedef void (GL_APIENTRYP PFNGLDRAWTEXFOESPROC) (GLfloat x, GLfloat y, GLfloat z, GLfloat width, GLfloat height);
-typedef void (GL_APIENTRYP PFNGLDRAWTEXFVOESPROC) (const GLfloat *coords);
-#endif
+#endif /* GL_OES_draw_texture */
-/* GL_OES_EGL_image */
-#ifndef GL_OES_EGL_image
-#define GL_OES_EGL_image 1
-#ifdef GL_GLEXT_PROTOTYPES
-GL_API void GL_APIENTRY glEGLImageTargetTexture2DOES (GLenum target, GLeglImageOES image);
-GL_API void GL_APIENTRY glEGLImageTargetRenderbufferStorageOES (GLenum target, GLeglImageOES image);
-#endif
-typedef void (GL_APIENTRYP PFNGLEGLIMAGETARGETTEXTURE2DOESPROC) (GLenum target, GLeglImageOES image);
-typedef void (GL_APIENTRYP PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC) (GLenum target, GLeglImageOES image);
-#endif
-
-/* GL_OES_EGL_image_external */
-#ifndef GL_OES_EGL_image_external
-#define GL_OES_EGL_image_external 1
-/* glEGLImageTargetTexture2DOES defined in GL_OES_EGL_image already. */
-#endif
-
-/* GL_OES_element_index_uint */
#ifndef GL_OES_element_index_uint
#define GL_OES_element_index_uint 1
-#endif
+#define GL_UNSIGNED_INT 0x1405
+#endif /* GL_OES_element_index_uint */
-/* GL_OES_extended_matrix_palette */
#ifndef GL_OES_extended_matrix_palette
#define GL_OES_extended_matrix_palette 1
-#endif
+#endif /* GL_OES_extended_matrix_palette */
-/* GL_OES_fbo_render_mipmap */
#ifndef GL_OES_fbo_render_mipmap
#define GL_OES_fbo_render_mipmap 1
-#endif
+#endif /* GL_OES_fbo_render_mipmap */
-/* GL_OES_fixed_point */
#ifndef GL_OES_fixed_point
#define GL_OES_fixed_point 1
-#ifdef GL_GLEXT_PROTOTYPES
-GL_API void GL_APIENTRY glAlphaFuncxOES (GLenum func, GLclampx ref);
-GL_API void GL_APIENTRY glClearColorxOES (GLclampx red, GLclampx green, GLclampx blue, GLclampx alpha);
-GL_API void GL_APIENTRY glClearDepthxOES (GLclampx depth);
-GL_API void GL_APIENTRY glClipPlanexOES (GLenum plane, const GLfixed *equation);
-GL_API void GL_APIENTRY glColor4xOES (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha);
-GL_API void GL_APIENTRY glDepthRangexOES (GLclampx zNear, GLclampx zFar);
-GL_API void GL_APIENTRY glFogxOES (GLenum pname, GLfixed param);
-GL_API void GL_APIENTRY glFogxvOES (GLenum pname, const GLfixed *params);
-GL_API void GL_APIENTRY glFrustumxOES (GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar);
-GL_API void GL_APIENTRY glGetClipPlanexOES (GLenum pname, GLfixed eqn[4]);
-GL_API void GL_APIENTRY glGetFixedvOES (GLenum pname, GLfixed *params);
-GL_API void GL_APIENTRY glGetLightxvOES (GLenum light, GLenum pname, GLfixed *params);
-GL_API void GL_APIENTRY glGetMaterialxvOES (GLenum face, GLenum pname, GLfixed *params);
-GL_API void GL_APIENTRY glGetTexEnvxvOES (GLenum env, GLenum pname, GLfixed *params);
-GL_API void GL_APIENTRY glGetTexParameterxvOES (GLenum target, GLenum pname, GLfixed *params);
-GL_API void GL_APIENTRY glLightModelxOES (GLenum pname, GLfixed param);
-GL_API void GL_APIENTRY glLightModelxvOES (GLenum pname, const GLfixed *params);
-GL_API void GL_APIENTRY glLightxOES (GLenum light, GLenum pname, GLfixed param);
-GL_API void GL_APIENTRY glLightxvOES (GLenum light, GLenum pname, const GLfixed *params);
-GL_API void GL_APIENTRY glLineWidthxOES (GLfixed width);
-GL_API void GL_APIENTRY glLoadMatrixxOES (const GLfixed *m);
-GL_API void GL_APIENTRY glMaterialxOES (GLenum face, GLenum pname, GLfixed param);
-GL_API void GL_APIENTRY glMaterialxvOES (GLenum face, GLenum pname, const GLfixed *params);
-GL_API void GL_APIENTRY glMultMatrixxOES (const GLfixed *m);
-GL_API void GL_APIENTRY glMultiTexCoord4xOES (GLenum target, GLfixed s, GLfixed t, GLfixed r, GLfixed q);
-GL_API void GL_APIENTRY glNormal3xOES (GLfixed nx, GLfixed ny, GLfixed nz);
-GL_API void GL_APIENTRY glOrthoxOES (GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar);
-GL_API void GL_APIENTRY glPointParameterxOES (GLenum pname, GLfixed param);
-GL_API void GL_APIENTRY glPointParameterxvOES (GLenum pname, const GLfixed *params);
-GL_API void GL_APIENTRY glPointSizexOES (GLfixed size);
-GL_API void GL_APIENTRY glPolygonOffsetxOES (GLfixed factor, GLfixed units);
-GL_API void GL_APIENTRY glRotatexOES (GLfixed angle, GLfixed x, GLfixed y, GLfixed z);
-GL_API void GL_APIENTRY glSampleCoveragexOES (GLclampx value, GLboolean invert);
-GL_API void GL_APIENTRY glScalexOES (GLfixed x, GLfixed y, GLfixed z);
-GL_API void GL_APIENTRY glTexEnvxOES (GLenum target, GLenum pname, GLfixed param);
-GL_API void GL_APIENTRY glTexEnvxvOES (GLenum target, GLenum pname, const GLfixed *params);
-GL_API void GL_APIENTRY glTexParameterxOES (GLenum target, GLenum pname, GLfixed param);
-GL_API void GL_APIENTRY glTexParameterxvOES (GLenum target, GLenum pname, const GLfixed *params);
-GL_API void GL_APIENTRY glTranslatexOES (GLfixed x, GLfixed y, GLfixed z);
-#endif
-typedef void (GL_APIENTRYP PFNGLALPHAFUNCXOESPROC) (GLenum func, GLclampx ref);
-typedef void (GL_APIENTRYP PFNGLCLEARCOLORXOESPROC) (GLclampx red, GLclampx green, GLclampx blue, GLclampx alpha);
-typedef void (GL_APIENTRYP PFNGLCLEARDEPTHXOESPROC) (GLclampx depth);
+#define GL_FIXED_OES 0x140C
+typedef void (GL_APIENTRYP PFNGLALPHAFUNCXOESPROC) (GLenum func, GLfixed ref);
+typedef void (GL_APIENTRYP PFNGLCLEARCOLORXOESPROC) (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha);
+typedef void (GL_APIENTRYP PFNGLCLEARDEPTHXOESPROC) (GLfixed depth);
typedef void (GL_APIENTRYP PFNGLCLIPPLANEXOESPROC) (GLenum plane, const GLfixed *equation);
typedef void (GL_APIENTRYP PFNGLCOLOR4XOESPROC) (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha);
-typedef void (GL_APIENTRYP PFNGLDEPTHRANGEXOESPROC) (GLclampx zNear, GLclampx zFar);
+typedef void (GL_APIENTRYP PFNGLDEPTHRANGEXOESPROC) (GLfixed n, GLfixed f);
typedef void (GL_APIENTRYP PFNGLFOGXOESPROC) (GLenum pname, GLfixed param);
-typedef void (GL_APIENTRYP PFNGLFOGXVOESPROC) (GLenum pname, const GLfixed *params);
-typedef void (GL_APIENTRYP PFNGLFRUSTUMXOESPROC) (GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar);
-typedef void (GL_APIENTRYP PFNGLGETCLIPPLANEXOESPROC) (GLenum pname, GLfixed eqn[4]);
+typedef void (GL_APIENTRYP PFNGLFOGXVOESPROC) (GLenum pname, const GLfixed *param);
+typedef void (GL_APIENTRYP PFNGLFRUSTUMXOESPROC) (GLfixed l, GLfixed r, GLfixed b, GLfixed t, GLfixed n, GLfixed f);
+typedef void (GL_APIENTRYP PFNGLGETCLIPPLANEXOESPROC) (GLenum plane, GLfixed *equation);
typedef void (GL_APIENTRYP PFNGLGETFIXEDVOESPROC) (GLenum pname, GLfixed *params);
-typedef void (GL_APIENTRYP PFNGLGETLIGHTXVOESPROC) (GLenum light, GLenum pname, GLfixed *params);
-typedef void (GL_APIENTRYP PFNGLGETMATERIALXVOESPROC) (GLenum face, GLenum pname, GLfixed *params);
-typedef void (GL_APIENTRYP PFNGLGETTEXENVXVOESPROC) (GLenum env, GLenum pname, GLfixed *params);
+typedef void (GL_APIENTRYP PFNGLGETTEXENVXVOESPROC) (GLenum target, GLenum pname, GLfixed *params);
typedef void (GL_APIENTRYP PFNGLGETTEXPARAMETERXVOESPROC) (GLenum target, GLenum pname, GLfixed *params);
typedef void (GL_APIENTRYP PFNGLLIGHTMODELXOESPROC) (GLenum pname, GLfixed param);
-typedef void (GL_APIENTRYP PFNGLLIGHTMODELXVOESPROC) (GLenum pname, const GLfixed *params);
+typedef void (GL_APIENTRYP PFNGLLIGHTMODELXVOESPROC) (GLenum pname, const GLfixed *param);
typedef void (GL_APIENTRYP PFNGLLIGHTXOESPROC) (GLenum light, GLenum pname, GLfixed param);
typedef void (GL_APIENTRYP PFNGLLIGHTXVOESPROC) (GLenum light, GLenum pname, const GLfixed *params);
typedef void (GL_APIENTRYP PFNGLLINEWIDTHXOESPROC) (GLfixed width);
typedef void (GL_APIENTRYP PFNGLLOADMATRIXXOESPROC) (const GLfixed *m);
typedef void (GL_APIENTRYP PFNGLMATERIALXOESPROC) (GLenum face, GLenum pname, GLfixed param);
-typedef void (GL_APIENTRYP PFNGLMATERIALXVOESPROC) (GLenum face, GLenum pname, const GLfixed *params);
+typedef void (GL_APIENTRYP PFNGLMATERIALXVOESPROC) (GLenum face, GLenum pname, const GLfixed *param);
typedef void (GL_APIENTRYP PFNGLMULTMATRIXXOESPROC) (const GLfixed *m);
-typedef void (GL_APIENTRYP PFNGLMULTITEXCOORD4XOESPROC) (GLenum target, GLfixed s, GLfixed t, GLfixed r, GLfixed q);
+typedef void (GL_APIENTRYP PFNGLMULTITEXCOORD4XOESPROC) (GLenum texture, GLfixed s, GLfixed t, GLfixed r, GLfixed q);
typedef void (GL_APIENTRYP PFNGLNORMAL3XOESPROC) (GLfixed nx, GLfixed ny, GLfixed nz);
-typedef void (GL_APIENTRYP PFNGLORTHOXOESPROC) (GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar);
-typedef void (GL_APIENTRYP PFNGLPOINTPARAMETERXOESPROC) (GLenum pname, GLfixed param);
+typedef void (GL_APIENTRYP PFNGLORTHOXOESPROC) (GLfixed l, GLfixed r, GLfixed b, GLfixed t, GLfixed n, GLfixed f);
typedef void (GL_APIENTRYP PFNGLPOINTPARAMETERXVOESPROC) (GLenum pname, const GLfixed *params);
typedef void (GL_APIENTRYP PFNGLPOINTSIZEXOESPROC) (GLfixed size);
typedef void (GL_APIENTRYP PFNGLPOLYGONOFFSETXOESPROC) (GLfixed factor, GLfixed units);
typedef void (GL_APIENTRYP PFNGLROTATEXOESPROC) (GLfixed angle, GLfixed x, GLfixed y, GLfixed z);
-typedef void (GL_APIENTRYP PFNGLSAMPLECOVERAGEXOESPROC) (GLclampx value, GLboolean invert);
typedef void (GL_APIENTRYP PFNGLSCALEXOESPROC) (GLfixed x, GLfixed y, GLfixed z);
typedef void (GL_APIENTRYP PFNGLTEXENVXOESPROC) (GLenum target, GLenum pname, GLfixed param);
typedef void (GL_APIENTRYP PFNGLTEXENVXVOESPROC) (GLenum target, GLenum pname, const GLfixed *params);
typedef void (GL_APIENTRYP PFNGLTEXPARAMETERXOESPROC) (GLenum target, GLenum pname, GLfixed param);
typedef void (GL_APIENTRYP PFNGLTEXPARAMETERXVOESPROC) (GLenum target, GLenum pname, const GLfixed *params);
typedef void (GL_APIENTRYP PFNGLTRANSLATEXOESPROC) (GLfixed x, GLfixed y, GLfixed z);
+typedef void (GL_APIENTRYP PFNGLGETLIGHTXVOESPROC) (GLenum light, GLenum pname, GLfixed *params);
+typedef void (GL_APIENTRYP PFNGLGETMATERIALXVOESPROC) (GLenum face, GLenum pname, GLfixed *params);
+typedef void (GL_APIENTRYP PFNGLPOINTPARAMETERXOESPROC) (GLenum pname, GLfixed param);
+typedef void (GL_APIENTRYP PFNGLSAMPLECOVERAGEXOESPROC) (GLclampx value, GLboolean invert);
+typedef void (GL_APIENTRYP PFNGLGETTEXGENXVOESPROC) (GLenum coord, GLenum pname, GLfixed *params);
+typedef void (GL_APIENTRYP PFNGLTEXGENXOESPROC) (GLenum coord, GLenum pname, GLfixed param);
+typedef void (GL_APIENTRYP PFNGLTEXGENXVOESPROC) (GLenum coord, GLenum pname, const GLfixed *params);
+#ifdef GL_GLEXT_PROTOTYPES
+GL_API void GL_APIENTRY glAlphaFuncxOES (GLenum func, GLfixed ref);
+GL_API void GL_APIENTRY glClearColorxOES (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha);
+GL_API void GL_APIENTRY glClearDepthxOES (GLfixed depth);
+GL_API void GL_APIENTRY glClipPlanexOES (GLenum plane, const GLfixed *equation);
+GL_API void GL_APIENTRY glColor4xOES (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha);
+GL_API void GL_APIENTRY glDepthRangexOES (GLfixed n, GLfixed f);
+GL_API void GL_APIENTRY glFogxOES (GLenum pname, GLfixed param);
+GL_API void GL_APIENTRY glFogxvOES (GLenum pname, const GLfixed *param);
+GL_API void GL_APIENTRY glFrustumxOES (GLfixed l, GLfixed r, GLfixed b, GLfixed t, GLfixed n, GLfixed f);
+GL_API void GL_APIENTRY glGetClipPlanexOES (GLenum plane, GLfixed *equation);
+GL_API void GL_APIENTRY glGetFixedvOES (GLenum pname, GLfixed *params);
+GL_API void GL_APIENTRY glGetTexEnvxvOES (GLenum target, GLenum pname, GLfixed *params);
+GL_API void GL_APIENTRY glGetTexParameterxvOES (GLenum target, GLenum pname, GLfixed *params);
+GL_API void GL_APIENTRY glLightModelxOES (GLenum pname, GLfixed param);
+GL_API void GL_APIENTRY glLightModelxvOES (GLenum pname, const GLfixed *param);
+GL_API void GL_APIENTRY glLightxOES (GLenum light, GLenum pname, GLfixed param);
+GL_API void GL_APIENTRY glLightxvOES (GLenum light, GLenum pname, const GLfixed *params);
+GL_API void GL_APIENTRY glLineWidthxOES (GLfixed width);
+GL_API void GL_APIENTRY glLoadMatrixxOES (const GLfixed *m);
+GL_API void GL_APIENTRY glMaterialxOES (GLenum face, GLenum pname, GLfixed param);
+GL_API void GL_APIENTRY glMaterialxvOES (GLenum face, GLenum pname, const GLfixed *param);
+GL_API void GL_APIENTRY glMultMatrixxOES (const GLfixed *m);
+GL_API void GL_APIENTRY glMultiTexCoord4xOES (GLenum texture, GLfixed s, GLfixed t, GLfixed r, GLfixed q);
+GL_API void GL_APIENTRY glNormal3xOES (GLfixed nx, GLfixed ny, GLfixed nz);
+GL_API void GL_APIENTRY glOrthoxOES (GLfixed l, GLfixed r, GLfixed b, GLfixed t, GLfixed n, GLfixed f);
+GL_API void GL_APIENTRY glPointParameterxvOES (GLenum pname, const GLfixed *params);
+GL_API void GL_APIENTRY glPointSizexOES (GLfixed size);
+GL_API void GL_APIENTRY glPolygonOffsetxOES (GLfixed factor, GLfixed units);
+GL_API void GL_APIENTRY glRotatexOES (GLfixed angle, GLfixed x, GLfixed y, GLfixed z);
+GL_API void GL_APIENTRY glScalexOES (GLfixed x, GLfixed y, GLfixed z);
+GL_API void GL_APIENTRY glTexEnvxOES (GLenum target, GLenum pname, GLfixed param);
+GL_API void GL_APIENTRY glTexEnvxvOES (GLenum target, GLenum pname, const GLfixed *params);
+GL_API void GL_APIENTRY glTexParameterxOES (GLenum target, GLenum pname, GLfixed param);
+GL_API void GL_APIENTRY glTexParameterxvOES (GLenum target, GLenum pname, const GLfixed *params);
+GL_API void GL_APIENTRY glTranslatexOES (GLfixed x, GLfixed y, GLfixed z);
+GL_API void GL_APIENTRY glGetLightxvOES (GLenum light, GLenum pname, GLfixed *params);
+GL_API void GL_APIENTRY glGetMaterialxvOES (GLenum face, GLenum pname, GLfixed *params);
+GL_API void GL_APIENTRY glPointParameterxOES (GLenum pname, GLfixed param);
+GL_API void GL_APIENTRY glSampleCoveragexOES (GLclampx value, GLboolean invert);
+GL_API void GL_APIENTRY glGetTexGenxvOES (GLenum coord, GLenum pname, GLfixed *params);
+GL_API void GL_APIENTRY glTexGenxOES (GLenum coord, GLenum pname, GLfixed param);
+GL_API void GL_APIENTRY glTexGenxvOES (GLenum coord, GLenum pname, const GLfixed *params);
#endif
+#endif /* GL_OES_fixed_point */
-/* GL_OES_framebuffer_object */
#ifndef GL_OES_framebuffer_object
#define GL_OES_framebuffer_object 1
-#ifdef GL_GLEXT_PROTOTYPES
-GL_API GLboolean GL_APIENTRY glIsRenderbufferOES (GLuint renderbuffer);
-GL_API void GL_APIENTRY glBindRenderbufferOES (GLenum target, GLuint renderbuffer);
-GL_API void GL_APIENTRY glDeleteRenderbuffersOES (GLsizei n, const GLuint* renderbuffers);
-GL_API void GL_APIENTRY glGenRenderbuffersOES (GLsizei n, GLuint* renderbuffers);
-GL_API void GL_APIENTRY glRenderbufferStorageOES (GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
-GL_API void GL_APIENTRY glGetRenderbufferParameterivOES (GLenum target, GLenum pname, GLint* params);
-GL_API GLboolean GL_APIENTRY glIsFramebufferOES (GLuint framebuffer);
-GL_API void GL_APIENTRY glBindFramebufferOES (GLenum target, GLuint framebuffer);
-GL_API void GL_APIENTRY glDeleteFramebuffersOES (GLsizei n, const GLuint* framebuffers);
-GL_API void GL_APIENTRY glGenFramebuffersOES (GLsizei n, GLuint* framebuffers);
-GL_API GLenum GL_APIENTRY glCheckFramebufferStatusOES (GLenum target);
-GL_API void GL_APIENTRY glFramebufferRenderbufferOES (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
-GL_API void GL_APIENTRY glFramebufferTexture2DOES (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
-GL_API void GL_APIENTRY glGetFramebufferAttachmentParameterivOES (GLenum target, GLenum attachment, GLenum pname, GLint* params);
-GL_API void GL_APIENTRY glGenerateMipmapOES (GLenum target);
-#endif
+#define GL_NONE_OES 0
+#define GL_FRAMEBUFFER_OES 0x8D40
+#define GL_RENDERBUFFER_OES 0x8D41
+#define GL_RGBA4_OES 0x8056
+#define GL_RGB5_A1_OES 0x8057
+#define GL_RGB565_OES 0x8D62
+#define GL_DEPTH_COMPONENT16_OES 0x81A5
+#define GL_RENDERBUFFER_WIDTH_OES 0x8D42
+#define GL_RENDERBUFFER_HEIGHT_OES 0x8D43
+#define GL_RENDERBUFFER_INTERNAL_FORMAT_OES 0x8D44
+#define GL_RENDERBUFFER_RED_SIZE_OES 0x8D50
+#define GL_RENDERBUFFER_GREEN_SIZE_OES 0x8D51
+#define GL_RENDERBUFFER_BLUE_SIZE_OES 0x8D52
+#define GL_RENDERBUFFER_ALPHA_SIZE_OES 0x8D53
+#define GL_RENDERBUFFER_DEPTH_SIZE_OES 0x8D54
+#define GL_RENDERBUFFER_STENCIL_SIZE_OES 0x8D55
+#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_OES 0x8CD0
+#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_OES 0x8CD1
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_OES 0x8CD2
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_OES 0x8CD3
+#define GL_COLOR_ATTACHMENT0_OES 0x8CE0
+#define GL_DEPTH_ATTACHMENT_OES 0x8D00
+#define GL_STENCIL_ATTACHMENT_OES 0x8D20
+#define GL_FRAMEBUFFER_COMPLETE_OES 0x8CD5
+#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES 0x8CD6
+#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_OES 0x8CD7
+#define GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_OES 0x8CD9
+#define GL_FRAMEBUFFER_INCOMPLETE_FORMATS_OES 0x8CDA
+#define GL_FRAMEBUFFER_UNSUPPORTED_OES 0x8CDD
+#define GL_FRAMEBUFFER_BINDING_OES 0x8CA6
+#define GL_RENDERBUFFER_BINDING_OES 0x8CA7
+#define GL_MAX_RENDERBUFFER_SIZE_OES 0x84E8
+#define GL_INVALID_FRAMEBUFFER_OPERATION_OES 0x0506
typedef GLboolean (GL_APIENTRYP PFNGLISRENDERBUFFEROESPROC) (GLuint renderbuffer);
typedef void (GL_APIENTRYP PFNGLBINDRENDERBUFFEROESPROC) (GLenum target, GLuint renderbuffer);
-typedef void (GL_APIENTRYP PFNGLDELETERENDERBUFFERSOESPROC) (GLsizei n, const GLuint* renderbuffers);
-typedef void (GL_APIENTRYP PFNGLGENRENDERBUFFERSOESPROC) (GLsizei n, GLuint* renderbuffers);
+typedef void (GL_APIENTRYP PFNGLDELETERENDERBUFFERSOESPROC) (GLsizei n, const GLuint *renderbuffers);
+typedef void (GL_APIENTRYP PFNGLGENRENDERBUFFERSOESPROC) (GLsizei n, GLuint *renderbuffers);
typedef void (GL_APIENTRYP PFNGLRENDERBUFFERSTORAGEOESPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
-typedef void (GL_APIENTRYP PFNGLGETRENDERBUFFERPARAMETERIVOESPROC) (GLenum target, GLenum pname, GLint* params);
+typedef void (GL_APIENTRYP PFNGLGETRENDERBUFFERPARAMETERIVOESPROC) (GLenum target, GLenum pname, GLint *params);
typedef GLboolean (GL_APIENTRYP PFNGLISFRAMEBUFFEROESPROC) (GLuint framebuffer);
typedef void (GL_APIENTRYP PFNGLBINDFRAMEBUFFEROESPROC) (GLenum target, GLuint framebuffer);
-typedef void (GL_APIENTRYP PFNGLDELETEFRAMEBUFFERSOESPROC) (GLsizei n, const GLuint* framebuffers);
-typedef void (GL_APIENTRYP PFNGLGENFRAMEBUFFERSOESPROC) (GLsizei n, GLuint* framebuffers);
+typedef void (GL_APIENTRYP PFNGLDELETEFRAMEBUFFERSOESPROC) (GLsizei n, const GLuint *framebuffers);
+typedef void (GL_APIENTRYP PFNGLGENFRAMEBUFFERSOESPROC) (GLsizei n, GLuint *framebuffers);
typedef GLenum (GL_APIENTRYP PFNGLCHECKFRAMEBUFFERSTATUSOESPROC) (GLenum target);
typedef void (GL_APIENTRYP PFNGLFRAMEBUFFERRENDERBUFFEROESPROC) (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
typedef void (GL_APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DOESPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
-typedef void (GL_APIENTRYP PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVOESPROC) (GLenum target, GLenum attachment, GLenum pname, GLint* params);
+typedef void (GL_APIENTRYP PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVOESPROC) (GLenum target, GLenum attachment, GLenum pname, GLint *params);
typedef void (GL_APIENTRYP PFNGLGENERATEMIPMAPOESPROC) (GLenum target);
+#ifdef GL_GLEXT_PROTOTYPES
+GL_API GLboolean GL_APIENTRY glIsRenderbufferOES (GLuint renderbuffer);
+GL_API void GL_APIENTRY glBindRenderbufferOES (GLenum target, GLuint renderbuffer);
+GL_API void GL_APIENTRY glDeleteRenderbuffersOES (GLsizei n, const GLuint *renderbuffers);
+GL_API void GL_APIENTRY glGenRenderbuffersOES (GLsizei n, GLuint *renderbuffers);
+GL_API void GL_APIENTRY glRenderbufferStorageOES (GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
+GL_API void GL_APIENTRY glGetRenderbufferParameterivOES (GLenum target, GLenum pname, GLint *params);
+GL_API GLboolean GL_APIENTRY glIsFramebufferOES (GLuint framebuffer);
+GL_API void GL_APIENTRY glBindFramebufferOES (GLenum target, GLuint framebuffer);
+GL_API void GL_APIENTRY glDeleteFramebuffersOES (GLsizei n, const GLuint *framebuffers);
+GL_API void GL_APIENTRY glGenFramebuffersOES (GLsizei n, GLuint *framebuffers);
+GL_API GLenum GL_APIENTRY glCheckFramebufferStatusOES (GLenum target);
+GL_API void GL_APIENTRY glFramebufferRenderbufferOES (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
+GL_API void GL_APIENTRY glFramebufferTexture2DOES (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
+GL_API void GL_APIENTRY glGetFramebufferAttachmentParameterivOES (GLenum target, GLenum attachment, GLenum pname, GLint *params);
+GL_API void GL_APIENTRY glGenerateMipmapOES (GLenum target);
#endif
+#endif /* GL_OES_framebuffer_object */
-/* GL_OES_mapbuffer */
#ifndef GL_OES_mapbuffer
#define GL_OES_mapbuffer 1
-#ifdef GL_GLEXT_PROTOTYPES
-GL_API void* GL_APIENTRY glMapBufferOES (GLenum target, GLenum access);
-GL_API GLboolean GL_APIENTRY glUnmapBufferOES (GLenum target);
-GL_API void GL_APIENTRY glGetBufferPointervOES (GLenum target, GLenum pname, GLvoid ** params);
-#endif
-typedef void* (GL_APIENTRYP PFNGLMAPBUFFEROESPROC) (GLenum target, GLenum access);
+#define GL_WRITE_ONLY_OES 0x88B9
+#define GL_BUFFER_ACCESS_OES 0x88BB
+#define GL_BUFFER_MAPPED_OES 0x88BC
+#define GL_BUFFER_MAP_POINTER_OES 0x88BD
+typedef void *(GL_APIENTRYP PFNGLMAPBUFFEROESPROC) (GLenum target, GLenum access);
typedef GLboolean (GL_APIENTRYP PFNGLUNMAPBUFFEROESPROC) (GLenum target);
-typedef void (GL_APIENTRYP PFNGLGETBUFFERPOINTERVOESPROC) (GLenum target, GLenum pname, GLvoid ** params);
+typedef void (GL_APIENTRYP PFNGLGETBUFFERPOINTERVOESPROC) (GLenum target, GLenum pname, void **params);
+#ifdef GL_GLEXT_PROTOTYPES
+GL_API void *GL_APIENTRY glMapBufferOES (GLenum target, GLenum access);
+GL_API GLboolean GL_APIENTRY glUnmapBufferOES (GLenum target);
+GL_API void GL_APIENTRY glGetBufferPointervOES (GLenum target, GLenum pname, void **params);
#endif
+#endif /* GL_OES_mapbuffer */
-/* GL_OES_matrix_get */
#ifndef GL_OES_matrix_get
#define GL_OES_matrix_get 1
-#endif
+#define GL_MODELVIEW_MATRIX_FLOAT_AS_INT_BITS_OES 0x898D
+#define GL_PROJECTION_MATRIX_FLOAT_AS_INT_BITS_OES 0x898E
+#define GL_TEXTURE_MATRIX_FLOAT_AS_INT_BITS_OES 0x898F
+#endif /* GL_OES_matrix_get */
-/* GL_OES_matrix_palette */
#ifndef GL_OES_matrix_palette
#define GL_OES_matrix_palette 1
+#define GL_MAX_VERTEX_UNITS_OES 0x86A4
+#define GL_MAX_PALETTE_MATRICES_OES 0x8842
+#define GL_MATRIX_PALETTE_OES 0x8840
+#define GL_MATRIX_INDEX_ARRAY_OES 0x8844
+#define GL_WEIGHT_ARRAY_OES 0x86AD
+#define GL_CURRENT_PALETTE_MATRIX_OES 0x8843
+#define GL_MATRIX_INDEX_ARRAY_SIZE_OES 0x8846
+#define GL_MATRIX_INDEX_ARRAY_TYPE_OES 0x8847
+#define GL_MATRIX_INDEX_ARRAY_STRIDE_OES 0x8848
+#define GL_MATRIX_INDEX_ARRAY_POINTER_OES 0x8849
+#define GL_MATRIX_INDEX_ARRAY_BUFFER_BINDING_OES 0x8B9E
+#define GL_WEIGHT_ARRAY_SIZE_OES 0x86AB
+#define GL_WEIGHT_ARRAY_TYPE_OES 0x86A9
+#define GL_WEIGHT_ARRAY_STRIDE_OES 0x86AA
+#define GL_WEIGHT_ARRAY_POINTER_OES 0x86AC
+#define GL_WEIGHT_ARRAY_BUFFER_BINDING_OES 0x889E
+typedef void (GL_APIENTRYP PFNGLCURRENTPALETTEMATRIXOESPROC) (GLuint matrixpaletteindex);
+typedef void (GL_APIENTRYP PFNGLLOADPALETTEFROMMODELVIEWMATRIXOESPROC) (void);
+typedef void (GL_APIENTRYP PFNGLMATRIXINDEXPOINTEROESPROC) (GLint size, GLenum type, GLsizei stride, const void *pointer);
+typedef void (GL_APIENTRYP PFNGLWEIGHTPOINTEROESPROC) (GLint size, GLenum type, GLsizei stride, const void *pointer);
#ifdef GL_GLEXT_PROTOTYPES
GL_API void GL_APIENTRY glCurrentPaletteMatrixOES (GLuint matrixpaletteindex);
GL_API void GL_APIENTRY glLoadPaletteFromModelViewMatrixOES (void);
-GL_API void GL_APIENTRY glMatrixIndexPointerOES (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
-GL_API void GL_APIENTRY glWeightPointerOES (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
+GL_API void GL_APIENTRY glMatrixIndexPointerOES (GLint size, GLenum type, GLsizei stride, const void *pointer);
+GL_API void GL_APIENTRY glWeightPointerOES (GLint size, GLenum type, GLsizei stride, const void *pointer);
#endif
-typedef void (GL_APIENTRYP PFNGLCURRENTPALETTEMATRIXOESPROC) (GLuint matrixpaletteindex);
-typedef void (GL_APIENTRYP PFNGLLOADPALETTEFROMMODELVIEWMATRIXOESPROC) (void);
-typedef void (GL_APIENTRYP PFNGLMATRIXINDEXPOINTEROESPROC) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
-typedef void (GL_APIENTRYP PFNGLWEIGHTPOINTEROESPROC) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
-#endif
+#endif /* GL_OES_matrix_palette */
-/* GL_OES_packed_depth_stencil */
#ifndef GL_OES_packed_depth_stencil
#define GL_OES_packed_depth_stencil 1
-#endif
+#define GL_DEPTH_STENCIL_OES 0x84F9
+#define GL_UNSIGNED_INT_24_8_OES 0x84FA
+#define GL_DEPTH24_STENCIL8_OES 0x88F0
+#endif /* GL_OES_packed_depth_stencil */
-/* GL_OES_required_internalformat */
-#ifndef GL_OES_required_internalformat
-#define GL_OES_required_internalformat 1
-#endif
-
-/* GL_OES_query_matrix */
#ifndef GL_OES_query_matrix
#define GL_OES_query_matrix 1
+typedef GLbitfield (GL_APIENTRYP PFNGLQUERYMATRIXXOESPROC) (GLfixed *mantissa, GLint *exponent);
#ifdef GL_GLEXT_PROTOTYPES
-GL_API GLbitfield GL_APIENTRY glQueryMatrixxOES (GLfixed mantissa[16], GLint exponent[16]);
+GL_API GLbitfield GL_APIENTRY glQueryMatrixxOES (GLfixed *mantissa, GLint *exponent);
#endif
-typedef GLbitfield (GL_APIENTRYP PFNGLQUERYMATRIXXOESPROC) (GLfixed mantissa[16], GLint exponent[16]);
-#endif
+#endif /* GL_OES_query_matrix */
-/* GL_OES_rgb8_rgba8 */
+#ifndef GL_OES_required_internalformat
+#define GL_OES_required_internalformat 1
+#define GL_ALPHA8_OES 0x803C
+#define GL_LUMINANCE4_ALPHA4_OES 0x8043
+#define GL_LUMINANCE8_ALPHA8_OES 0x8045
+#define GL_LUMINANCE8_OES 0x8040
+#define GL_RGB8_OES 0x8051
+#define GL_RGBA8_OES 0x8058
+#define GL_RGB10_EXT 0x8052
+#define GL_RGB10_A2_EXT 0x8059
+#endif /* GL_OES_required_internalformat */
+
#ifndef GL_OES_rgb8_rgba8
#define GL_OES_rgb8_rgba8 1
-#endif
+#endif /* GL_OES_rgb8_rgba8 */
-/* GL_OES_single_precision */
#ifndef GL_OES_single_precision
#define GL_OES_single_precision 1
-#ifdef GL_GLEXT_PROTOTYPES
-GL_API void GL_APIENTRY glDepthRangefOES (GLclampf zNear, GLclampf zFar);
-GL_API void GL_APIENTRY glFrustumfOES (GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar);
-GL_API void GL_APIENTRY glOrthofOES (GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar);
-GL_API void GL_APIENTRY glClipPlanefOES (GLenum plane, const GLfloat *equation);
-GL_API void GL_APIENTRY glGetClipPlanefOES (GLenum pname, GLfloat eqn[4]);
-GL_API void GL_APIENTRY glClearDepthfOES (GLclampf depth);
-#endif
-typedef void (GL_APIENTRYP PFNGLDEPTHRANGEFOESPROC) (GLclampf zNear, GLclampf zFar);
-typedef void (GL_APIENTRYP PFNGLFRUSTUMFOESPROC) (GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar);
-typedef void (GL_APIENTRYP PFNGLORTHOFOESPROC) (GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar);
-typedef void (GL_APIENTRYP PFNGLCLIPPLANEFOESPROC) (GLenum plane, const GLfloat *equation);
-typedef void (GL_APIENTRYP PFNGLGETCLIPPLANEFOESPROC) (GLenum pname, GLfloat eqn[4]);
typedef void (GL_APIENTRYP PFNGLCLEARDEPTHFOESPROC) (GLclampf depth);
+typedef void (GL_APIENTRYP PFNGLCLIPPLANEFOESPROC) (GLenum plane, const GLfloat *equation);
+typedef void (GL_APIENTRYP PFNGLDEPTHRANGEFOESPROC) (GLclampf n, GLclampf f);
+typedef void (GL_APIENTRYP PFNGLFRUSTUMFOESPROC) (GLfloat l, GLfloat r, GLfloat b, GLfloat t, GLfloat n, GLfloat f);
+typedef void (GL_APIENTRYP PFNGLGETCLIPPLANEFOESPROC) (GLenum plane, GLfloat *equation);
+typedef void (GL_APIENTRYP PFNGLORTHOFOESPROC) (GLfloat l, GLfloat r, GLfloat b, GLfloat t, GLfloat n, GLfloat f);
+#ifdef GL_GLEXT_PROTOTYPES
+GL_API void GL_APIENTRY glClearDepthfOES (GLclampf depth);
+GL_API void GL_APIENTRY glClipPlanefOES (GLenum plane, const GLfloat *equation);
+GL_API void GL_APIENTRY glDepthRangefOES (GLclampf n, GLclampf f);
+GL_API void GL_APIENTRY glFrustumfOES (GLfloat l, GLfloat r, GLfloat b, GLfloat t, GLfloat n, GLfloat f);
+GL_API void GL_APIENTRY glGetClipPlanefOES (GLenum plane, GLfloat *equation);
+GL_API void GL_APIENTRY glOrthofOES (GLfloat l, GLfloat r, GLfloat b, GLfloat t, GLfloat n, GLfloat f);
#endif
+#endif /* GL_OES_single_precision */
-/* GL_OES_stencil1 */
#ifndef GL_OES_stencil1
#define GL_OES_stencil1 1
-#endif
+#define GL_STENCIL_INDEX1_OES 0x8D46
+#endif /* GL_OES_stencil1 */
-/* GL_OES_stencil4 */
#ifndef GL_OES_stencil4
#define GL_OES_stencil4 1
-#endif
+#define GL_STENCIL_INDEX4_OES 0x8D47
+#endif /* GL_OES_stencil4 */
-/* GL_OES_stencil8 */
#ifndef GL_OES_stencil8
#define GL_OES_stencil8 1
-#endif
+#define GL_STENCIL_INDEX8_OES 0x8D48
+#endif /* GL_OES_stencil8 */
-/* GL_OES_stencil_wrap */
#ifndef GL_OES_stencil_wrap
#define GL_OES_stencil_wrap 1
-#endif
+#define GL_INCR_WRAP_OES 0x8507
+#define GL_DECR_WRAP_OES 0x8508
+#endif /* GL_OES_stencil_wrap */
-/* GL_OES_texture_cube_map */
#ifndef GL_OES_texture_cube_map
#define GL_OES_texture_cube_map 1
+#define GL_NORMAL_MAP_OES 0x8511
+#define GL_REFLECTION_MAP_OES 0x8512
+#define GL_TEXTURE_CUBE_MAP_OES 0x8513
+#define GL_TEXTURE_BINDING_CUBE_MAP_OES 0x8514
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_X_OES 0x8515
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X_OES 0x8516
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y_OES 0x8517
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_OES 0x8518
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z_OES 0x8519
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_OES 0x851A
+#define GL_MAX_CUBE_MAP_TEXTURE_SIZE_OES 0x851C
+#define GL_TEXTURE_GEN_MODE_OES 0x2500
+#define GL_TEXTURE_GEN_STR_OES 0x8D60
+typedef void (GL_APIENTRYP PFNGLTEXGENFOESPROC) (GLenum coord, GLenum pname, GLfloat param);
+typedef void (GL_APIENTRYP PFNGLTEXGENFVOESPROC) (GLenum coord, GLenum pname, const GLfloat *params);
+typedef void (GL_APIENTRYP PFNGLTEXGENIOESPROC) (GLenum coord, GLenum pname, GLint param);
+typedef void (GL_APIENTRYP PFNGLTEXGENIVOESPROC) (GLenum coord, GLenum pname, const GLint *params);
+typedef void (GL_APIENTRYP PFNGLGETTEXGENFVOESPROC) (GLenum coord, GLenum pname, GLfloat *params);
+typedef void (GL_APIENTRYP PFNGLGETTEXGENIVOESPROC) (GLenum coord, GLenum pname, GLint *params);
#ifdef GL_GLEXT_PROTOTYPES
GL_API void GL_APIENTRY glTexGenfOES (GLenum coord, GLenum pname, GLfloat param);
GL_API void GL_APIENTRY glTexGenfvOES (GLenum coord, GLenum pname, const GLfloat *params);
GL_API void GL_APIENTRY glTexGeniOES (GLenum coord, GLenum pname, GLint param);
GL_API void GL_APIENTRY glTexGenivOES (GLenum coord, GLenum pname, const GLint *params);
-GL_API void GL_APIENTRY glTexGenxOES (GLenum coord, GLenum pname, GLfixed param);
-GL_API void GL_APIENTRY glTexGenxvOES (GLenum coord, GLenum pname, const GLfixed *params);
GL_API void GL_APIENTRY glGetTexGenfvOES (GLenum coord, GLenum pname, GLfloat *params);
GL_API void GL_APIENTRY glGetTexGenivOES (GLenum coord, GLenum pname, GLint *params);
-GL_API void GL_APIENTRY glGetTexGenxvOES (GLenum coord, GLenum pname, GLfixed *params);
#endif
-typedef void (GL_APIENTRYP PFNGLTEXGENFOESPROC) (GLenum coord, GLenum pname, GLfloat param);
-typedef void (GL_APIENTRYP PFNGLTEXGENFVOESPROC) (GLenum coord, GLenum pname, const GLfloat *params);
-typedef void (GL_APIENTRYP PFNGLTEXGENIOESPROC) (GLenum coord, GLenum pname, GLint param);
-typedef void (GL_APIENTRYP PFNGLTEXGENIVOESPROC) (GLenum coord, GLenum pname, const GLint *params);
-typedef void (GL_APIENTRYP PFNGLTEXGENXOESPROC) (GLenum coord, GLenum pname, GLfixed param);
-typedef void (GL_APIENTRYP PFNGLTEXGENXVOESPROC) (GLenum coord, GLenum pname, const GLfixed *params);
-typedef void (GL_APIENTRYP PFNGLGETTEXGENFVOESPROC) (GLenum coord, GLenum pname, GLfloat *params);
-typedef void (GL_APIENTRYP PFNGLGETTEXGENIVOESPROC) (GLenum coord, GLenum pname, GLint *params);
-typedef void (GL_APIENTRYP PFNGLGETTEXGENXVOESPROC) (GLenum coord, GLenum pname, GLfixed *params);
-#endif
+#endif /* GL_OES_texture_cube_map */
-/* GL_OES_texture_env_crossbar */
#ifndef GL_OES_texture_env_crossbar
#define GL_OES_texture_env_crossbar 1
-#endif
+#endif /* GL_OES_texture_env_crossbar */
-/* GL_OES_texture_mirrored_repeat */
#ifndef GL_OES_texture_mirrored_repeat
#define GL_OES_texture_mirrored_repeat 1
-#endif
+#define GL_MIRRORED_REPEAT_OES 0x8370
+#endif /* GL_OES_texture_mirrored_repeat */
-/* GL_OES_vertex_array_object */
#ifndef GL_OES_vertex_array_object
#define GL_OES_vertex_array_object 1
+#define GL_VERTEX_ARRAY_BINDING_OES 0x85B5
+typedef void (GL_APIENTRYP PFNGLBINDVERTEXARRAYOESPROC) (GLuint array);
+typedef void (GL_APIENTRYP PFNGLDELETEVERTEXARRAYSOESPROC) (GLsizei n, const GLuint *arrays);
+typedef void (GL_APIENTRYP PFNGLGENVERTEXARRAYSOESPROC) (GLsizei n, GLuint *arrays);
+typedef GLboolean (GL_APIENTRYP PFNGLISVERTEXARRAYOESPROC) (GLuint array);
#ifdef GL_GLEXT_PROTOTYPES
GL_API void GL_APIENTRY glBindVertexArrayOES (GLuint array);
GL_API void GL_APIENTRY glDeleteVertexArraysOES (GLsizei n, const GLuint *arrays);
GL_API void GL_APIENTRY glGenVertexArraysOES (GLsizei n, GLuint *arrays);
GL_API GLboolean GL_APIENTRY glIsVertexArrayOES (GLuint array);
#endif
-typedef void (GL_APIENTRYP PFNGLBINDVERTEXARRAYOESPROC) (GLuint array);
-typedef void (GL_APIENTRYP PFNGLDELETEVERTEXARRAYSOESPROC) (GLsizei n, const GLuint *arrays);
-typedef void (GL_APIENTRYP PFNGLGENVERTEXARRAYSOESPROC) (GLsizei n, GLuint *arrays);
-typedef GLboolean (GL_APIENTRYP PFNGLISVERTEXARRAYOESPROC) (GLuint array);
-#endif
+#endif /* GL_OES_vertex_array_object */
-/*------------------------------------------------------------------------*
- * AMD extension functions
- *------------------------------------------------------------------------*/
-
-/* GL_AMD_compressed_3DC_texture */
#ifndef GL_AMD_compressed_3DC_texture
#define GL_AMD_compressed_3DC_texture 1
-#endif
+#define GL_3DC_X_AMD 0x87F9
+#define GL_3DC_XY_AMD 0x87FA
+#endif /* GL_AMD_compressed_3DC_texture */
-/* GL_AMD_compressed_ATC_texture */
#ifndef GL_AMD_compressed_ATC_texture
#define GL_AMD_compressed_ATC_texture 1
-#endif
+#define GL_ATC_RGB_AMD 0x8C92
+#define GL_ATC_RGBA_EXPLICIT_ALPHA_AMD 0x8C93
+#define GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD 0x87EE
+#endif /* GL_AMD_compressed_ATC_texture */
-/*------------------------------------------------------------------------*
- * APPLE extension functions
- *------------------------------------------------------------------------*/
-
-/* GL_APPLE_copy_texture_levels */
#ifndef GL_APPLE_copy_texture_levels
#define GL_APPLE_copy_texture_levels 1
+typedef void (GL_APIENTRYP PFNGLCOPYTEXTURELEVELSAPPLEPROC) (GLuint destinationTexture, GLuint sourceTexture, GLint sourceBaseLevel, GLsizei sourceLevelCount);
#ifdef GL_GLEXT_PROTOTYPES
GL_API void GL_APIENTRY glCopyTextureLevelsAPPLE (GLuint destinationTexture, GLuint sourceTexture, GLint sourceBaseLevel, GLsizei sourceLevelCount);
#endif
-typedef void (GL_APIENTRYP PFNGLCOPYTEXTURELEVELSAPPLEPROC) (GLuint destinationTexture, GLuint sourceTexture, GLint sourceBaseLevel, GLsizei sourceLevelCount);
-#endif
+#endif /* GL_APPLE_copy_texture_levels */
-/* GL_APPLE_framebuffer_multisample */
#ifndef GL_APPLE_framebuffer_multisample
#define GL_APPLE_framebuffer_multisample 1
-#ifdef GL_GLEXT_PROTOTYPES
-GL_API void GL_APIENTRY glRenderbufferStorageMultisampleAPPLE (GLenum, GLsizei, GLenum, GLsizei, GLsizei);
-GL_API void GL_APIENTRY glResolveMultisampleFramebufferAPPLE (void);
-#endif /* GL_GLEXT_PROTOTYPES */
+#define GL_RENDERBUFFER_SAMPLES_APPLE 0x8CAB
+#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_APPLE 0x8D56
+#define GL_MAX_SAMPLES_APPLE 0x8D57
+#define GL_READ_FRAMEBUFFER_APPLE 0x8CA8
+#define GL_DRAW_FRAMEBUFFER_APPLE 0x8CA9
+#define GL_DRAW_FRAMEBUFFER_BINDING_APPLE 0x8CA6
+#define GL_READ_FRAMEBUFFER_BINDING_APPLE 0x8CAA
typedef void (GL_APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEAPPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
typedef void (GL_APIENTRYP PFNGLRESOLVEMULTISAMPLEFRAMEBUFFERAPPLEPROC) (void);
+#ifdef GL_GLEXT_PROTOTYPES
+GL_API void GL_APIENTRY glRenderbufferStorageMultisampleAPPLE (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+GL_API void GL_APIENTRY glResolveMultisampleFramebufferAPPLE (void);
#endif
+#endif /* GL_APPLE_framebuffer_multisample */
-/* GL_APPLE_sync */
#ifndef GL_APPLE_sync
#define GL_APPLE_sync 1
+typedef struct __GLsync *GLsync;
+typedef khronos_uint64_t GLuint64;
+typedef khronos_int64_t GLint64;
+#define GL_SYNC_OBJECT_APPLE 0x8A53
+#define GL_MAX_SERVER_WAIT_TIMEOUT_APPLE 0x9111
+#define GL_OBJECT_TYPE_APPLE 0x9112
+#define GL_SYNC_CONDITION_APPLE 0x9113
+#define GL_SYNC_STATUS_APPLE 0x9114
+#define GL_SYNC_FLAGS_APPLE 0x9115
+#define GL_SYNC_FENCE_APPLE 0x9116
+#define GL_SYNC_GPU_COMMANDS_COMPLETE_APPLE 0x9117
+#define GL_UNSIGNALED_APPLE 0x9118
+#define GL_SIGNALED_APPLE 0x9119
+#define GL_ALREADY_SIGNALED_APPLE 0x911A
+#define GL_TIMEOUT_EXPIRED_APPLE 0x911B
+#define GL_CONDITION_SATISFIED_APPLE 0x911C
+#define GL_WAIT_FAILED_APPLE 0x911D
+#define GL_SYNC_FLUSH_COMMANDS_BIT_APPLE 0x00000001
+#define GL_TIMEOUT_IGNORED_APPLE 0xFFFFFFFFFFFFFFFFull
+typedef GLsync (GL_APIENTRYP PFNGLFENCESYNCAPPLEPROC) (GLenum condition, GLbitfield flags);
+typedef GLboolean (GL_APIENTRYP PFNGLISSYNCAPPLEPROC) (GLsync sync);
+typedef void (GL_APIENTRYP PFNGLDELETESYNCAPPLEPROC) (GLsync sync);
+typedef GLenum (GL_APIENTRYP PFNGLCLIENTWAITSYNCAPPLEPROC) (GLsync sync, GLbitfield flags, GLuint64 timeout);
+typedef void (GL_APIENTRYP PFNGLWAITSYNCAPPLEPROC) (GLsync sync, GLbitfield flags, GLuint64 timeout);
+typedef void (GL_APIENTRYP PFNGLGETINTEGER64VAPPLEPROC) (GLenum pname, GLint64 *params);
+typedef void (GL_APIENTRYP PFNGLGETSYNCIVAPPLEPROC) (GLsync sync, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values);
#ifdef GL_GLEXT_PROTOTYPES
GL_API GLsync GL_APIENTRY glFenceSyncAPPLE (GLenum condition, GLbitfield flags);
GL_API GLboolean GL_APIENTRY glIsSyncAPPLE (GLsync sync);
@@ -978,138 +574,170 @@
GL_API void GL_APIENTRY glGetInteger64vAPPLE (GLenum pname, GLint64 *params);
GL_API void GL_APIENTRY glGetSyncivAPPLE (GLsync sync, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values);
#endif
-typedef GLsync (GL_APIENTRYP PFNGLFENCESYNCAPPLEPROC) (GLenum condition, GLbitfield flags);
-typedef GLboolean (GL_APIENTRYP PFNGLISSYNCAPPLEPROC) (GLsync sync);
-typedef void (GL_APIENTRYP PFNGLDELETESYNCAPPLEPROC) (GLsync sync);
-typedef GLenum (GL_APIENTRYP PFNGLCLIENTWAITSYNCAPPLEPROC) (GLsync sync, GLbitfield flags, GLuint64 timeout);
-typedef void (GL_APIENTRYP PFNGLWAITSYNCAPPLEPROC) (GLsync sync, GLbitfield flags, GLuint64 timeout);
-typedef void (GL_APIENTRYP PFNGLGETINTEGER64VAPPLEPROC) (GLenum pname, GLint64 *params);
-typedef void (GL_APIENTRYP PFNGLGETSYNCIVAPPLEPROC) (GLsync sync, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values);
-#endif
+#endif /* GL_APPLE_sync */
-/* GL_APPLE_texture_2D_limited_npot */
#ifndef GL_APPLE_texture_2D_limited_npot
#define GL_APPLE_texture_2D_limited_npot 1
-#endif
+#endif /* GL_APPLE_texture_2D_limited_npot */
-/* GL_APPLE_texture_format_BGRA8888 */
#ifndef GL_APPLE_texture_format_BGRA8888
#define GL_APPLE_texture_format_BGRA8888 1
-#endif
+#define GL_BGRA_EXT 0x80E1
+#define GL_BGRA8_EXT 0x93A1
+#endif /* GL_APPLE_texture_format_BGRA8888 */
-/* GL_APPLE_texture_max_level */
#ifndef GL_APPLE_texture_max_level
#define GL_APPLE_texture_max_level 1
-#endif
+#define GL_TEXTURE_MAX_LEVEL_APPLE 0x813D
+#endif /* GL_APPLE_texture_max_level */
-/*------------------------------------------------------------------------*
- * ARM extension functions
- *------------------------------------------------------------------------*/
-
-/* GL_ARM_rgba8 */
#ifndef GL_ARM_rgba8
#define GL_ARM_rgba8 1
-#endif
+#endif /* GL_ARM_rgba8 */
-/*------------------------------------------------------------------------*
- * EXT extension functions
- *------------------------------------------------------------------------*/
-
-/* GL_EXT_blend_minmax */
#ifndef GL_EXT_blend_minmax
#define GL_EXT_blend_minmax 1
-#endif
+#define GL_MIN_EXT 0x8007
+#define GL_MAX_EXT 0x8008
+#endif /* GL_EXT_blend_minmax */
-/* GL_EXT_discard_framebuffer */
#ifndef GL_EXT_discard_framebuffer
#define GL_EXT_discard_framebuffer 1
+#define GL_COLOR_EXT 0x1800
+#define GL_DEPTH_EXT 0x1801
+#define GL_STENCIL_EXT 0x1802
+typedef void (GL_APIENTRYP PFNGLDISCARDFRAMEBUFFEREXTPROC) (GLenum target, GLsizei numAttachments, const GLenum *attachments);
#ifdef GL_GLEXT_PROTOTYPES
GL_API void GL_APIENTRY glDiscardFramebufferEXT (GLenum target, GLsizei numAttachments, const GLenum *attachments);
#endif
-typedef void (GL_APIENTRYP PFNGLDISCARDFRAMEBUFFEREXTPROC) (GLenum target, GLsizei numAttachments, const GLenum *attachments);
-#endif
+#endif /* GL_EXT_discard_framebuffer */
-/* GL_EXT_map_buffer_range */
#ifndef GL_EXT_map_buffer_range
#define GL_EXT_map_buffer_range 1
+#define GL_MAP_READ_BIT_EXT 0x0001
+#define GL_MAP_WRITE_BIT_EXT 0x0002
+#define GL_MAP_INVALIDATE_RANGE_BIT_EXT 0x0004
+#define GL_MAP_INVALIDATE_BUFFER_BIT_EXT 0x0008
+#define GL_MAP_FLUSH_EXPLICIT_BIT_EXT 0x0010
+#define GL_MAP_UNSYNCHRONIZED_BIT_EXT 0x0020
+typedef void *(GL_APIENTRYP PFNGLMAPBUFFERRANGEEXTPROC) (GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access);
+typedef void (GL_APIENTRYP PFNGLFLUSHMAPPEDBUFFERRANGEEXTPROC) (GLenum target, GLintptr offset, GLsizeiptr length);
#ifdef GL_GLEXT_PROTOTYPES
-GL_API void GL_APIENTRY *glMapBufferRangeEXT (GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access);
+GL_API void *GL_APIENTRY glMapBufferRangeEXT (GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access);
GL_API void GL_APIENTRY glFlushMappedBufferRangeEXT (GLenum target, GLintptr offset, GLsizeiptr length);
#endif
-typedef void* (GL_APIENTRYP PFNGLMAPBUFFERRANGEEXTPROC) (GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access);
-typedef void (GL_APIENTRYP PFNGLFLUSHMAPPEDBUFFERRANGEEXTPROC) (GLenum target, GLintptr offset, GLsizeiptr length);
-#endif
+#endif /* GL_EXT_map_buffer_range */
-/* GL_EXT_multisampled_render_to_texture */
-#ifndef GL_EXT_multisampled_render_to_texture
-#define GL_EXT_multisampled_render_to_texture 1
-#ifdef GL_GLEXT_PROTOTYPES
-GL_API void GL_APIENTRY glRenderbufferStorageMultisampleEXT (GLenum, GLsizei, GLenum, GLsizei, GLsizei);
-GL_API void GL_APIENTRY glFramebufferTexture2DMultisampleEXT (GLenum, GLenum, GLenum, GLuint, GLint, GLsizei);
-#endif
-typedef void (GL_APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
-typedef void (GL_APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples);
-#endif
-
-/* GL_EXT_multi_draw_arrays */
#ifndef GL_EXT_multi_draw_arrays
#define GL_EXT_multi_draw_arrays 1
-#ifdef GL_GLEXT_PROTOTYPES
-GL_API void GL_APIENTRY glMultiDrawArraysEXT (GLenum, const GLint *, const GLsizei *, GLsizei);
-GL_API void GL_APIENTRY glMultiDrawElementsEXT (GLenum, const GLsizei *, GLenum, const GLvoid* const*, GLsizei);
-#endif /* GL_GLEXT_PROTOTYPES */
typedef void (GL_APIENTRYP PFNGLMULTIDRAWARRAYSEXTPROC) (GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount);
-typedef void (GL_APIENTRYP PFNGLMULTIDRAWELEMENTSEXTPROC) (GLenum mode, const GLsizei *count, GLenum type, const GLvoid* const*indices, GLsizei primcount);
+typedef void (GL_APIENTRYP PFNGLMULTIDRAWELEMENTSEXTPROC) (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei primcount);
+#ifdef GL_GLEXT_PROTOTYPES
+GL_API void GL_APIENTRY glMultiDrawArraysEXT (GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount);
+GL_API void GL_APIENTRY glMultiDrawElementsEXT (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei primcount);
#endif
+#endif /* GL_EXT_multi_draw_arrays */
-/* GL_EXT_read_format_bgra */
+#ifndef GL_EXT_multisampled_render_to_texture
+#define GL_EXT_multisampled_render_to_texture 1
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_SAMPLES_EXT 0x8D6C
+#define GL_RENDERBUFFER_SAMPLES_EXT 0x8CAB
+#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT 0x8D56
+#define GL_MAX_SAMPLES_EXT 0x8D57
+typedef void (GL_APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+typedef void (GL_APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples);
+#ifdef GL_GLEXT_PROTOTYPES
+GL_API void GL_APIENTRY glRenderbufferStorageMultisampleEXT (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+GL_API void GL_APIENTRY glFramebufferTexture2DMultisampleEXT (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples);
+#endif
+#endif /* GL_EXT_multisampled_render_to_texture */
+
#ifndef GL_EXT_read_format_bgra
#define GL_EXT_read_format_bgra 1
-#endif
+#define GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT 0x8365
+#define GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT 0x8366
+#endif /* GL_EXT_read_format_bgra */
-/* GL_EXT_robustness */
#ifndef GL_EXT_robustness
#define GL_EXT_robustness 1
+#define GL_GUILTY_CONTEXT_RESET_EXT 0x8253
+#define GL_INNOCENT_CONTEXT_RESET_EXT 0x8254
+#define GL_UNKNOWN_CONTEXT_RESET_EXT 0x8255
+#define GL_CONTEXT_ROBUST_ACCESS_EXT 0x90F3
+#define GL_RESET_NOTIFICATION_STRATEGY_EXT 0x8256
+#define GL_LOSE_CONTEXT_ON_RESET_EXT 0x8252
+#define GL_NO_RESET_NOTIFICATION_EXT 0x8261
+typedef GLenum (GL_APIENTRYP PFNGLGETGRAPHICSRESETSTATUSEXTPROC) (void);
+typedef void (GL_APIENTRYP PFNGLREADNPIXELSEXTPROC) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data);
+typedef void (GL_APIENTRYP PFNGLGETNUNIFORMFVEXTPROC) (GLuint program, GLint location, GLsizei bufSize, GLfloat *params);
+typedef void (GL_APIENTRYP PFNGLGETNUNIFORMIVEXTPROC) (GLuint program, GLint location, GLsizei bufSize, GLint *params);
#ifdef GL_GLEXT_PROTOTYPES
GL_API GLenum GL_APIENTRY glGetGraphicsResetStatusEXT (void);
GL_API void GL_APIENTRY glReadnPixelsEXT (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data);
-GL_API void GL_APIENTRY glGetnUniformfvEXT (GLuint program, GLint location, GLsizei bufSize, float *params);
+GL_API void GL_APIENTRY glGetnUniformfvEXT (GLuint program, GLint location, GLsizei bufSize, GLfloat *params);
GL_API void GL_APIENTRY glGetnUniformivEXT (GLuint program, GLint location, GLsizei bufSize, GLint *params);
#endif
-typedef GLenum (GL_APIENTRYP PFNGLGETGRAPHICSRESETSTATUSEXTPROC) (void);
-typedef void (GL_APIENTRYP PFNGLREADNPIXELSEXTPROC) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data);
-typedef void (GL_APIENTRYP PFNGLGETNUNIFORMFVEXTPROC) (GLuint program, GLint location, GLsizei bufSize, float *params);
-typedef void (GL_APIENTRYP PFNGLGETNUNIFORMIVEXTPROC) (GLuint program, GLint location, GLsizei bufSize, GLint *params);
-#endif
+#endif /* GL_EXT_robustness */
-/* GL_EXT_sRGB */
#ifndef GL_EXT_sRGB
#define GL_EXT_sRGB 1
-#endif
+#define GL_SRGB_EXT 0x8C40
+#define GL_SRGB_ALPHA_EXT 0x8C42
+#define GL_SRGB8_ALPHA8_EXT 0x8C43
+#define GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT 0x8210
+#endif /* GL_EXT_sRGB */
-/* GL_EXT_texture_compression_dxt1 */
#ifndef GL_EXT_texture_compression_dxt1
#define GL_EXT_texture_compression_dxt1 1
-#endif
+#define GL_COMPRESSED_RGB_S3TC_DXT1_EXT 0x83F0
+#define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1
+#endif /* GL_EXT_texture_compression_dxt1 */
-/* GL_EXT_texture_filter_anisotropic */
#ifndef GL_EXT_texture_filter_anisotropic
#define GL_EXT_texture_filter_anisotropic 1
-#endif
+#define GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE
+#define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF
+#endif /* GL_EXT_texture_filter_anisotropic */
-/* GL_EXT_texture_format_BGRA8888 */
#ifndef GL_EXT_texture_format_BGRA8888
#define GL_EXT_texture_format_BGRA8888 1
-#endif
+#endif /* GL_EXT_texture_format_BGRA8888 */
-/* GL_EXT_texture_lod_bias */
#ifndef GL_EXT_texture_lod_bias
#define GL_EXT_texture_lod_bias 1
-#endif
+#define GL_MAX_TEXTURE_LOD_BIAS_EXT 0x84FD
+#define GL_TEXTURE_FILTER_CONTROL_EXT 0x8500
+#define GL_TEXTURE_LOD_BIAS_EXT 0x8501
+#endif /* GL_EXT_texture_lod_bias */
-/* GL_EXT_texture_storage */
#ifndef GL_EXT_texture_storage
#define GL_EXT_texture_storage 1
+#define GL_TEXTURE_IMMUTABLE_FORMAT_EXT 0x912F
+#define GL_ALPHA8_EXT 0x803C
+#define GL_LUMINANCE8_EXT 0x8040
+#define GL_LUMINANCE8_ALPHA8_EXT 0x8045
+#define GL_RGBA32F_EXT 0x8814
+#define GL_RGB32F_EXT 0x8815
+#define GL_ALPHA32F_EXT 0x8816
+#define GL_LUMINANCE32F_EXT 0x8818
+#define GL_LUMINANCE_ALPHA32F_EXT 0x8819
+#define GL_RGBA16F_EXT 0x881A
+#define GL_RGB16F_EXT 0x881B
+#define GL_ALPHA16F_EXT 0x881C
+#define GL_LUMINANCE16F_EXT 0x881E
+#define GL_LUMINANCE_ALPHA16F_EXT 0x881F
+#define GL_R8_EXT 0x8229
+#define GL_RG8_EXT 0x822B
+#define GL_R32F_EXT 0x822E
+#define GL_RG32F_EXT 0x8230
+#define GL_R16F_EXT 0x822D
+#define GL_RG16F_EXT 0x822F
+typedef void (GL_APIENTRYP PFNGLTEXSTORAGE1DEXTPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width);
+typedef void (GL_APIENTRYP PFNGLTEXSTORAGE2DEXTPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
+typedef void (GL_APIENTRYP PFNGLTEXSTORAGE3DEXTPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
+typedef void (GL_APIENTRYP PFNGLTEXTURESTORAGE1DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width);
+typedef void (GL_APIENTRYP PFNGLTEXTURESTORAGE2DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
+typedef void (GL_APIENTRYP PFNGLTEXTURESTORAGE3DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
#ifdef GL_GLEXT_PROTOTYPES
GL_API void GL_APIENTRY glTexStorage1DEXT (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width);
GL_API void GL_APIENTRY glTexStorage2DEXT (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
@@ -1118,71 +746,69 @@
GL_API void GL_APIENTRY glTextureStorage2DEXT (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
GL_API void GL_APIENTRY glTextureStorage3DEXT (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
#endif
-typedef void (GL_APIENTRYP PFNGLTEXSTORAGE1DEXTPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width);
-typedef void (GL_APIENTRYP PFNGLTEXSTORAGE2DEXTPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
-typedef void (GL_APIENTRYP PFNGLTEXSTORAGE3DEXTPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
-typedef void (GL_APIENTRYP PFNGLTEXTURESTORAGE1DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width);
-typedef void (GL_APIENTRYP PFNGLTEXTURESTORAGE2DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
-typedef void (GL_APIENTRYP PFNGLTEXTURESTORAGE3DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
-#endif
+#endif /* GL_EXT_texture_storage */
-/*------------------------------------------------------------------------*
- * IMG extension functions
- *------------------------------------------------------------------------*/
-
-/* GL_IMG_read_format */
-#ifndef GL_IMG_read_format
-#define GL_IMG_read_format 1
-#endif
-
-/* GL_IMG_texture_compression_pvrtc */
-#ifndef GL_IMG_texture_compression_pvrtc
-#define GL_IMG_texture_compression_pvrtc 1
-#endif
-
-/* GL_IMG_texture_env_enhanced_fixed_function */
-#ifndef GL_IMG_texture_env_enhanced_fixed_function
-#define GL_IMG_texture_env_enhanced_fixed_function 1
-#endif
-
-/* GL_IMG_user_clip_plane */
-#ifndef GL_IMG_user_clip_plane
-#define GL_IMG_user_clip_plane 1
-#ifdef GL_GLEXT_PROTOTYPES
-GL_API void GL_APIENTRY glClipPlanefIMG (GLenum, const GLfloat *);
-GL_API void GL_APIENTRY glClipPlanexIMG (GLenum, const GLfixed *);
-#endif
-typedef void (GL_APIENTRYP PFNGLCLIPPLANEFIMGPROC) (GLenum p, const GLfloat *eqn);
-typedef void (GL_APIENTRYP PFNGLCLIPPLANEXIMGPROC) (GLenum p, const GLfixed *eqn);
-#endif
-
-/* GL_IMG_multisampled_render_to_texture */
#ifndef GL_IMG_multisampled_render_to_texture
#define GL_IMG_multisampled_render_to_texture 1
-#ifdef GL_GLEXT_PROTOTYPES
-GL_API void GL_APIENTRY glRenderbufferStorageMultisampleIMG (GLenum, GLsizei, GLenum, GLsizei, GLsizei);
-GL_API void GL_APIENTRY glFramebufferTexture2DMultisampleIMG (GLenum, GLenum, GLenum, GLuint, GLint, GLsizei);
-#endif
+#define GL_RENDERBUFFER_SAMPLES_IMG 0x9133
+#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_IMG 0x9134
+#define GL_MAX_SAMPLES_IMG 0x9135
+#define GL_TEXTURE_SAMPLES_IMG 0x9136
typedef void (GL_APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEIMGPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
typedef void (GL_APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DMULTISAMPLEIMGPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples);
+#ifdef GL_GLEXT_PROTOTYPES
+GL_API void GL_APIENTRY glRenderbufferStorageMultisampleIMG (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+GL_API void GL_APIENTRY glFramebufferTexture2DMultisampleIMG (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples);
#endif
+#endif /* GL_IMG_multisampled_render_to_texture */
-/*------------------------------------------------------------------------*
- * NV extension functions
- *------------------------------------------------------------------------*/
+#ifndef GL_IMG_read_format
+#define GL_IMG_read_format 1
+#define GL_BGRA_IMG 0x80E1
+#define GL_UNSIGNED_SHORT_4_4_4_4_REV_IMG 0x8365
+#endif /* GL_IMG_read_format */
-/* NV_fence */
+#ifndef GL_IMG_texture_compression_pvrtc
+#define GL_IMG_texture_compression_pvrtc 1
+#define GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG 0x8C00
+#define GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG 0x8C01
+#define GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG 0x8C02
+#define GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG 0x8C03
+#endif /* GL_IMG_texture_compression_pvrtc */
+
+#ifndef GL_IMG_texture_env_enhanced_fixed_function
+#define GL_IMG_texture_env_enhanced_fixed_function 1
+#define GL_MODULATE_COLOR_IMG 0x8C04
+#define GL_RECIP_ADD_SIGNED_ALPHA_IMG 0x8C05
+#define GL_TEXTURE_ALPHA_MODULATE_IMG 0x8C06
+#define GL_FACTOR_ALPHA_MODULATE_IMG 0x8C07
+#define GL_FRAGMENT_ALPHA_MODULATE_IMG 0x8C08
+#define GL_ADD_BLEND_IMG 0x8C09
+#define GL_DOT3_RGBA_IMG 0x86AF
+#endif /* GL_IMG_texture_env_enhanced_fixed_function */
+
+#ifndef GL_IMG_user_clip_plane
+#define GL_IMG_user_clip_plane 1
+#define GL_CLIP_PLANE0_IMG 0x3000
+#define GL_CLIP_PLANE1_IMG 0x3001
+#define GL_CLIP_PLANE2_IMG 0x3002
+#define GL_CLIP_PLANE3_IMG 0x3003
+#define GL_CLIP_PLANE4_IMG 0x3004
+#define GL_CLIP_PLANE5_IMG 0x3005
+#define GL_MAX_CLIP_PLANES_IMG 0x0D32
+typedef void (GL_APIENTRYP PFNGLCLIPPLANEFIMGPROC) (GLenum p, const GLfloat *eqn);
+typedef void (GL_APIENTRYP PFNGLCLIPPLANEXIMGPROC) (GLenum p, const GLfixed *eqn);
+#ifdef GL_GLEXT_PROTOTYPES
+GL_API void GL_APIENTRY glClipPlanefIMG (GLenum p, const GLfloat *eqn);
+GL_API void GL_APIENTRY glClipPlanexIMG (GLenum p, const GLfixed *eqn);
+#endif
+#endif /* GL_IMG_user_clip_plane */
+
#ifndef GL_NV_fence
#define GL_NV_fence 1
-#ifdef GL_GLEXT_PROTOTYPES
-GL_API void GL_APIENTRY glDeleteFencesNV (GLsizei, const GLuint *);
-GL_API void GL_APIENTRY glGenFencesNV (GLsizei, GLuint *);
-GL_API GLboolean GL_APIENTRY glIsFenceNV (GLuint);
-GL_API GLboolean GL_APIENTRY glTestFenceNV (GLuint);
-GL_API void GL_APIENTRY glGetFenceivNV (GLuint, GLenum, GLint *);
-GL_API void GL_APIENTRY glFinishFenceNV (GLuint);
-GL_API void GL_APIENTRY glSetFenceNV (GLuint, GLenum);
-#endif
+#define GL_ALL_COMPLETED_NV 0x84F2
+#define GL_FENCE_STATUS_NV 0x84F3
+#define GL_FENCE_CONDITION_NV 0x84F4
typedef void (GL_APIENTRYP PFNGLDELETEFENCESNVPROC) (GLsizei n, const GLuint *fences);
typedef void (GL_APIENTRYP PFNGLGENFENCESNVPROC) (GLsizei n, GLuint *fences);
typedef GLboolean (GL_APIENTRYP PFNGLISFENCENVPROC) (GLuint fence);
@@ -1190,30 +816,53 @@
typedef void (GL_APIENTRYP PFNGLGETFENCEIVNVPROC) (GLuint fence, GLenum pname, GLint *params);
typedef void (GL_APIENTRYP PFNGLFINISHFENCENVPROC) (GLuint fence);
typedef void (GL_APIENTRYP PFNGLSETFENCENVPROC) (GLuint fence, GLenum condition);
+#ifdef GL_GLEXT_PROTOTYPES
+GL_API void GL_APIENTRY glDeleteFencesNV (GLsizei n, const GLuint *fences);
+GL_API void GL_APIENTRY glGenFencesNV (GLsizei n, GLuint *fences);
+GL_API GLboolean GL_APIENTRY glIsFenceNV (GLuint fence);
+GL_API GLboolean GL_APIENTRY glTestFenceNV (GLuint fence);
+GL_API void GL_APIENTRY glGetFenceivNV (GLuint fence, GLenum pname, GLint *params);
+GL_API void GL_APIENTRY glFinishFenceNV (GLuint fence);
+GL_API void GL_APIENTRY glSetFenceNV (GLuint fence, GLenum condition);
#endif
+#endif /* GL_NV_fence */
-/*------------------------------------------------------------------------*
- * QCOM extension functions
- *------------------------------------------------------------------------*/
-
-/* GL_QCOM_driver_control */
#ifndef GL_QCOM_driver_control
#define GL_QCOM_driver_control 1
+typedef char GLchar;
+typedef void (GL_APIENTRYP PFNGLGETDRIVERCONTROLSQCOMPROC) (GLint *num, GLsizei size, GLuint *driverControls);
+typedef void (GL_APIENTRYP PFNGLGETDRIVERCONTROLSTRINGQCOMPROC) (GLuint driverControl, GLsizei bufSize, GLsizei *length, GLchar *driverControlString);
+typedef void (GL_APIENTRYP PFNGLENABLEDRIVERCONTROLQCOMPROC) (GLuint driverControl);
+typedef void (GL_APIENTRYP PFNGLDISABLEDRIVERCONTROLQCOMPROC) (GLuint driverControl);
#ifdef GL_GLEXT_PROTOTYPES
GL_API void GL_APIENTRY glGetDriverControlsQCOM (GLint *num, GLsizei size, GLuint *driverControls);
GL_API void GL_APIENTRY glGetDriverControlStringQCOM (GLuint driverControl, GLsizei bufSize, GLsizei *length, GLchar *driverControlString);
GL_API void GL_APIENTRY glEnableDriverControlQCOM (GLuint driverControl);
GL_API void GL_APIENTRY glDisableDriverControlQCOM (GLuint driverControl);
#endif
-typedef void (GL_APIENTRYP PFNGLGETDRIVERCONTROLSQCOMPROC) (GLint *num, GLsizei size, GLuint *driverControls);
-typedef void (GL_APIENTRYP PFNGLGETDRIVERCONTROLSTRINGQCOMPROC) (GLuint driverControl, GLsizei bufSize, GLsizei *length, GLchar *driverControlString);
-typedef void (GL_APIENTRYP PFNGLENABLEDRIVERCONTROLQCOMPROC) (GLuint driverControl);
-typedef void (GL_APIENTRYP PFNGLDISABLEDRIVERCONTROLQCOMPROC) (GLuint driverControl);
-#endif
+#endif /* GL_QCOM_driver_control */
-/* GL_QCOM_extended_get */
#ifndef GL_QCOM_extended_get
#define GL_QCOM_extended_get 1
+#define GL_TEXTURE_WIDTH_QCOM 0x8BD2
+#define GL_TEXTURE_HEIGHT_QCOM 0x8BD3
+#define GL_TEXTURE_DEPTH_QCOM 0x8BD4
+#define GL_TEXTURE_INTERNAL_FORMAT_QCOM 0x8BD5
+#define GL_TEXTURE_FORMAT_QCOM 0x8BD6
+#define GL_TEXTURE_TYPE_QCOM 0x8BD7
+#define GL_TEXTURE_IMAGE_VALID_QCOM 0x8BD8
+#define GL_TEXTURE_NUM_LEVELS_QCOM 0x8BD9
+#define GL_TEXTURE_TARGET_QCOM 0x8BDA
+#define GL_TEXTURE_OBJECT_VALID_QCOM 0x8BDB
+#define GL_STATE_RESTORE 0x8BDC
+typedef void (GL_APIENTRYP PFNGLEXTGETTEXTURESQCOMPROC) (GLuint *textures, GLint maxTextures, GLint *numTextures);
+typedef void (GL_APIENTRYP PFNGLEXTGETBUFFERSQCOMPROC) (GLuint *buffers, GLint maxBuffers, GLint *numBuffers);
+typedef void (GL_APIENTRYP PFNGLEXTGETRENDERBUFFERSQCOMPROC) (GLuint *renderbuffers, GLint maxRenderbuffers, GLint *numRenderbuffers);
+typedef void (GL_APIENTRYP PFNGLEXTGETFRAMEBUFFERSQCOMPROC) (GLuint *framebuffers, GLint maxFramebuffers, GLint *numFramebuffers);
+typedef void (GL_APIENTRYP PFNGLEXTGETTEXLEVELPARAMETERIVQCOMPROC) (GLuint texture, GLenum face, GLint level, GLenum pname, GLint *params);
+typedef void (GL_APIENTRYP PFNGLEXTTEXOBJECTSTATEOVERRIDEIQCOMPROC) (GLenum target, GLenum pname, GLint param);
+typedef void (GL_APIENTRYP PFNGLEXTGETTEXSUBIMAGEQCOMPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, void *texels);
+typedef void (GL_APIENTRYP PFNGLEXTGETBUFFERPOINTERVQCOMPROC) (GLenum target, void **params);
#ifdef GL_GLEXT_PROTOTYPES
GL_API void GL_APIENTRY glExtGetTexturesQCOM (GLuint *textures, GLint maxTextures, GLint *numTextures);
GL_API void GL_APIENTRY glExtGetBuffersQCOM (GLuint *buffers, GLint maxBuffers, GLint *numBuffers);
@@ -1221,58 +870,79 @@
GL_API void GL_APIENTRY glExtGetFramebuffersQCOM (GLuint *framebuffers, GLint maxFramebuffers, GLint *numFramebuffers);
GL_API void GL_APIENTRY glExtGetTexLevelParameterivQCOM (GLuint texture, GLenum face, GLint level, GLenum pname, GLint *params);
GL_API void GL_APIENTRY glExtTexObjectStateOverrideiQCOM (GLenum target, GLenum pname, GLint param);
-GL_API void GL_APIENTRY glExtGetTexSubImageQCOM (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLvoid *texels);
-GL_API void GL_APIENTRY glExtGetBufferPointervQCOM (GLenum target, GLvoid **params);
+GL_API void GL_APIENTRY glExtGetTexSubImageQCOM (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, void *texels);
+GL_API void GL_APIENTRY glExtGetBufferPointervQCOM (GLenum target, void **params);
#endif
-typedef void (GL_APIENTRYP PFNGLEXTGETTEXTURESQCOMPROC) (GLuint *textures, GLint maxTextures, GLint *numTextures);
-typedef void (GL_APIENTRYP PFNGLEXTGETBUFFERSQCOMPROC) (GLuint *buffers, GLint maxBuffers, GLint *numBuffers);
-typedef void (GL_APIENTRYP PFNGLEXTGETRENDERBUFFERSQCOMPROC) (GLuint *renderbuffers, GLint maxRenderbuffers, GLint *numRenderbuffers);
-typedef void (GL_APIENTRYP PFNGLEXTGETFRAMEBUFFERSQCOMPROC) (GLuint *framebuffers, GLint maxFramebuffers, GLint *numFramebuffers);
-typedef void (GL_APIENTRYP PFNGLEXTGETTEXLEVELPARAMETERIVQCOMPROC) (GLuint texture, GLenum face, GLint level, GLenum pname, GLint *params);
-typedef void (GL_APIENTRYP PFNGLEXTTEXOBJECTSTATEOVERRIDEIQCOMPROC) (GLenum target, GLenum pname, GLint param);
-typedef void (GL_APIENTRYP PFNGLEXTGETTEXSUBIMAGEQCOMPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLvoid *texels);
-typedef void (GL_APIENTRYP PFNGLEXTGETBUFFERPOINTERVQCOMPROC) (GLenum target, GLvoid **params);
-#endif
+#endif /* GL_QCOM_extended_get */
-/* GL_QCOM_extended_get2 */
#ifndef GL_QCOM_extended_get2
#define GL_QCOM_extended_get2 1
+typedef void (GL_APIENTRYP PFNGLEXTGETSHADERSQCOMPROC) (GLuint *shaders, GLint maxShaders, GLint *numShaders);
+typedef void (GL_APIENTRYP PFNGLEXTGETPROGRAMSQCOMPROC) (GLuint *programs, GLint maxPrograms, GLint *numPrograms);
+typedef GLboolean (GL_APIENTRYP PFNGLEXTISPROGRAMBINARYQCOMPROC) (GLuint program);
+typedef void (GL_APIENTRYP PFNGLEXTGETPROGRAMBINARYSOURCEQCOMPROC) (GLuint program, GLenum shadertype, GLchar *source, GLint *length);
#ifdef GL_GLEXT_PROTOTYPES
GL_API void GL_APIENTRY glExtGetShadersQCOM (GLuint *shaders, GLint maxShaders, GLint *numShaders);
GL_API void GL_APIENTRY glExtGetProgramsQCOM (GLuint *programs, GLint maxPrograms, GLint *numPrograms);
GL_API GLboolean GL_APIENTRY glExtIsProgramBinaryQCOM (GLuint program);
GL_API void GL_APIENTRY glExtGetProgramBinarySourceQCOM (GLuint program, GLenum shadertype, GLchar *source, GLint *length);
#endif
-typedef void (GL_APIENTRYP PFNGLEXTGETSHADERSQCOMPROC) (GLuint *shaders, GLint maxShaders, GLint *numShaders);
-typedef void (GL_APIENTRYP PFNGLEXTGETPROGRAMSQCOMPROC) (GLuint *programs, GLint maxPrograms, GLint *numPrograms);
-typedef GLboolean (GL_APIENTRYP PFNGLEXTISPROGRAMBINARYQCOMPROC) (GLuint program);
-typedef void (GL_APIENTRYP PFNGLEXTGETPROGRAMBINARYSOURCEQCOMPROC) (GLuint program, GLenum shadertype, GLchar *source, GLint *length);
-#endif
+#endif /* GL_QCOM_extended_get2 */
-/* GL_QCOM_perfmon_global_mode */
#ifndef GL_QCOM_perfmon_global_mode
#define GL_QCOM_perfmon_global_mode 1
-#endif
+#define GL_PERFMON_GLOBAL_MODE_QCOM 0x8FA0
+#endif /* GL_QCOM_perfmon_global_mode */
-/* GL_QCOM_writeonly_rendering */
-#ifndef GL_QCOM_writeonly_rendering
-#define GL_QCOM_writeonly_rendering 1
-#endif
-
-/* GL_QCOM_tiled_rendering */
#ifndef GL_QCOM_tiled_rendering
#define GL_QCOM_tiled_rendering 1
+#define GL_COLOR_BUFFER_BIT0_QCOM 0x00000001
+#define GL_COLOR_BUFFER_BIT1_QCOM 0x00000002
+#define GL_COLOR_BUFFER_BIT2_QCOM 0x00000004
+#define GL_COLOR_BUFFER_BIT3_QCOM 0x00000008
+#define GL_COLOR_BUFFER_BIT4_QCOM 0x00000010
+#define GL_COLOR_BUFFER_BIT5_QCOM 0x00000020
+#define GL_COLOR_BUFFER_BIT6_QCOM 0x00000040
+#define GL_COLOR_BUFFER_BIT7_QCOM 0x00000080
+#define GL_DEPTH_BUFFER_BIT0_QCOM 0x00000100
+#define GL_DEPTH_BUFFER_BIT1_QCOM 0x00000200
+#define GL_DEPTH_BUFFER_BIT2_QCOM 0x00000400
+#define GL_DEPTH_BUFFER_BIT3_QCOM 0x00000800
+#define GL_DEPTH_BUFFER_BIT4_QCOM 0x00001000
+#define GL_DEPTH_BUFFER_BIT5_QCOM 0x00002000
+#define GL_DEPTH_BUFFER_BIT6_QCOM 0x00004000
+#define GL_DEPTH_BUFFER_BIT7_QCOM 0x00008000
+#define GL_STENCIL_BUFFER_BIT0_QCOM 0x00010000
+#define GL_STENCIL_BUFFER_BIT1_QCOM 0x00020000
+#define GL_STENCIL_BUFFER_BIT2_QCOM 0x00040000
+#define GL_STENCIL_BUFFER_BIT3_QCOM 0x00080000
+#define GL_STENCIL_BUFFER_BIT4_QCOM 0x00100000
+#define GL_STENCIL_BUFFER_BIT5_QCOM 0x00200000
+#define GL_STENCIL_BUFFER_BIT6_QCOM 0x00400000
+#define GL_STENCIL_BUFFER_BIT7_QCOM 0x00800000
+#define GL_MULTISAMPLE_BUFFER_BIT0_QCOM 0x01000000
+#define GL_MULTISAMPLE_BUFFER_BIT1_QCOM 0x02000000
+#define GL_MULTISAMPLE_BUFFER_BIT2_QCOM 0x04000000
+#define GL_MULTISAMPLE_BUFFER_BIT3_QCOM 0x08000000
+#define GL_MULTISAMPLE_BUFFER_BIT4_QCOM 0x10000000
+#define GL_MULTISAMPLE_BUFFER_BIT5_QCOM 0x20000000
+#define GL_MULTISAMPLE_BUFFER_BIT6_QCOM 0x40000000
+#define GL_MULTISAMPLE_BUFFER_BIT7_QCOM 0x80000000
+typedef void (GL_APIENTRYP PFNGLSTARTTILINGQCOMPROC) (GLuint x, GLuint y, GLuint width, GLuint height, GLbitfield preserveMask);
+typedef void (GL_APIENTRYP PFNGLENDTILINGQCOMPROC) (GLbitfield preserveMask);
#ifdef GL_GLEXT_PROTOTYPES
GL_API void GL_APIENTRY glStartTilingQCOM (GLuint x, GLuint y, GLuint width, GLuint height, GLbitfield preserveMask);
GL_API void GL_APIENTRY glEndTilingQCOM (GLbitfield preserveMask);
#endif
-typedef void (GL_APIENTRYP PFNGLSTARTTILINGQCOMPROC) (GLuint x, GLuint y, GLuint width, GLuint height, GLbitfield preserveMask);
-typedef void (GL_APIENTRYP PFNGLENDTILINGQCOMPROC) (GLbitfield preserveMask);
-#endif
+#endif /* GL_QCOM_tiled_rendering */
+
+#ifndef GL_QCOM_writeonly_rendering
+#define GL_QCOM_writeonly_rendering 1
+#define GL_WRITEONLY_RENDERING_QCOM 0x8823
+#endif /* GL_QCOM_writeonly_rendering */
#ifdef __cplusplus
}
#endif
-#endif /* __glext_h_ */
-
+#endif
diff --git a/opengl/include/GLES/glplatform.h b/opengl/include/GLES/glplatform.h
index 2db6ee2..16060a9 100644
--- a/opengl/include/GLES/glplatform.h
+++ b/opengl/include/GLES/glplatform.h
@@ -1,20 +1,28 @@
#ifndef __glplatform_h_
#define __glplatform_h_
-/* $Revision: 10601 $ on $Date:: 2010-03-04 22:15:27 -0800 #$ */
-
/*
- * This document is licensed under the SGI Free Software B License Version
- * 2.0. For details, see http://oss.sgi.com/projects/FreeB/ .
- */
+** Copyright (c) 2017 The Khronos Group Inc.
+**
+** 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.
+*/
/* Platform-specific types and definitions for OpenGL ES 1.X gl.h
*
* Adopters may modify khrplatform.h and this file to suit their platform.
- * You are encouraged to submit all modifications to the Khronos group so that
- * they can be included in future versions of this file. Please submit changes
- * by sending them to the public Khronos Bugzilla (http://khronos.org/bugzilla)
- * by filing a bug against product "OpenGL-ES" component "Registry".
+ * Please contribute modifications back to Khronos as pull requests on the
+ * public github repository:
+ * https://github.com/KhronosGroup/OpenGL-Registry
*/
#include <KHR/khrplatform.h>
diff --git a/opengl/include/GLES2/NOTICE b/opengl/include/GLES2/NOTICE
index 7a94373..710388f 100644
--- a/opengl/include/GLES2/NOTICE
+++ b/opengl/include/GLES2/NOTICE
@@ -1,4 +1,18 @@
-Copyright (c) 2013-2015 The Khronos Group Inc.
+Copyright (c) 2017 The Khronos Group Inc.
+
+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.
+
+Copyright (c) 2013-2017 The Khronos Group Inc.
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and/or associated documentation files (the
@@ -18,3 +32,4 @@
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+
diff --git a/opengl/include/GLES2/gl2.h b/opengl/include/GLES2/gl2.h
index f64ec00..8819e30 100644
--- a/opengl/include/GLES2/gl2.h
+++ b/opengl/include/GLES2/gl2.h
@@ -6,7 +6,7 @@
#endif
/*
-** Copyright (c) 2013-2015 The Khronos Group Inc.
+** Copyright (c) 2013-2017 The Khronos Group Inc.
**
** Permission is hereby granted, free of charge, to any person obtaining a
** copy of this software and/or associated documentation files (the
@@ -31,9 +31,7 @@
** This header is generated from the Khronos OpenGL / OpenGL ES XML
** API Registry. The current version of the Registry, generator scripts
** used to make the header, and the header can be found at
-** http://www.opengl.org/registry/
-**
-** Khronos $Revision: 32120 $ on $Date: 2015-10-15 04:27:13 -0700 (Thu, 15 Oct 2015) $
+** https://github.com/KhronosGroup/OpenGL-Registry
*/
#include <GLES2/gl2platform.h>
@@ -42,11 +40,11 @@
#define GL_APIENTRYP GL_APIENTRY*
#endif
-#if !defined(GL_GLES_PROTOTYPES)
+#ifndef GL_GLES_PROTOTYPES
#define GL_GLES_PROTOTYPES 1
#endif
-/* Generated on date 20151015 */
+/* Generated on date 20170613 */
/* Generated C header for:
* API: gles2
diff --git a/opengl/include/GLES2/gl2ext.h b/opengl/include/GLES2/gl2ext.h
index 2d05596..b5eb723 100644
--- a/opengl/include/GLES2/gl2ext.h
+++ b/opengl/include/GLES2/gl2ext.h
@@ -6,7 +6,7 @@
#endif
/*
-** Copyright (c) 2013-2015 The Khronos Group Inc.
+** Copyright (c) 2013-2017 The Khronos Group Inc.
**
** Permission is hereby granted, free of charge, to any person obtaining a
** copy of this software and/or associated documentation files (the
@@ -31,16 +31,14 @@
** This header is generated from the Khronos OpenGL / OpenGL ES XML
** API Registry. The current version of the Registry, generator scripts
** used to make the header, and the header can be found at
-** http://www.opengl.org/registry/
-**
-** Khronos $Revision: 32120 $ on $Date: 2015-10-15 04:27:13 -0700 (Thu, 15 Oct 2015) $
+** https://github.com/KhronosGroup/OpenGL-Registry
*/
#ifndef GL_APIENTRYP
#define GL_APIENTRYP GL_APIENTRY*
#endif
-/* Generated on date 20151015 */
+/* Generated on date 20170613 */
/* Generated C header for:
* API: gles2
@@ -752,6 +750,34 @@
#define GL_INT_10_10_10_2_OES 0x8DF7
#endif /* GL_OES_vertex_type_10_10_10_2 */
+#ifndef GL_OES_viewport_array
+#define GL_OES_viewport_array 1
+#define GL_MAX_VIEWPORTS_OES 0x825B
+#define GL_VIEWPORT_SUBPIXEL_BITS_OES 0x825C
+#define GL_VIEWPORT_BOUNDS_RANGE_OES 0x825D
+#define GL_VIEWPORT_INDEX_PROVOKING_VERTEX_OES 0x825F
+typedef void (GL_APIENTRYP PFNGLVIEWPORTARRAYVOESPROC) (GLuint first, GLsizei count, const GLfloat *v);
+typedef void (GL_APIENTRYP PFNGLVIEWPORTINDEXEDFOESPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat w, GLfloat h);
+typedef void (GL_APIENTRYP PFNGLVIEWPORTINDEXEDFVOESPROC) (GLuint index, const GLfloat *v);
+typedef void (GL_APIENTRYP PFNGLSCISSORARRAYVOESPROC) (GLuint first, GLsizei count, const GLint *v);
+typedef void (GL_APIENTRYP PFNGLSCISSORINDEXEDOESPROC) (GLuint index, GLint left, GLint bottom, GLsizei width, GLsizei height);
+typedef void (GL_APIENTRYP PFNGLSCISSORINDEXEDVOESPROC) (GLuint index, const GLint *v);
+typedef void (GL_APIENTRYP PFNGLDEPTHRANGEARRAYFVOESPROC) (GLuint first, GLsizei count, const GLfloat *v);
+typedef void (GL_APIENTRYP PFNGLDEPTHRANGEINDEXEDFOESPROC) (GLuint index, GLfloat n, GLfloat f);
+typedef void (GL_APIENTRYP PFNGLGETFLOATI_VOESPROC) (GLenum target, GLuint index, GLfloat *data);
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glViewportArrayvOES (GLuint first, GLsizei count, const GLfloat *v);
+GL_APICALL void GL_APIENTRY glViewportIndexedfOES (GLuint index, GLfloat x, GLfloat y, GLfloat w, GLfloat h);
+GL_APICALL void GL_APIENTRY glViewportIndexedfvOES (GLuint index, const GLfloat *v);
+GL_APICALL void GL_APIENTRY glScissorArrayvOES (GLuint first, GLsizei count, const GLint *v);
+GL_APICALL void GL_APIENTRY glScissorIndexedOES (GLuint index, GLint left, GLint bottom, GLsizei width, GLsizei height);
+GL_APICALL void GL_APIENTRY glScissorIndexedvOES (GLuint index, const GLint *v);
+GL_APICALL void GL_APIENTRY glDepthRangeArrayfvOES (GLuint first, GLsizei count, const GLfloat *v);
+GL_APICALL void GL_APIENTRY glDepthRangeIndexedfOES (GLuint index, GLfloat n, GLfloat f);
+GL_APICALL void GL_APIENTRY glGetFloati_vOES (GLenum target, GLuint index, GLfloat *data);
+#endif
+#endif /* GL_OES_viewport_array */
+
#ifndef GL_AMD_compressed_3DC_texture
#define GL_AMD_compressed_3DC_texture 1
#define GL_3DC_X_AMD 0x87F9
@@ -1025,6 +1051,10 @@
#define GL_SHADER_BINARY_DMP 0x9250
#endif /* GL_DMP_shader_binary */
+#ifndef GL_EXT_EGL_image_array
+#define GL_EXT_EGL_image_array 1
+#endif /* GL_EXT_EGL_image_array */
+
#ifndef GL_EXT_YUV_target
#define GL_EXT_YUV_target 1
#define GL_SAMPLER_EXTERNAL_2D_Y2Y_EXT 0x8BE7
@@ -1086,6 +1116,31 @@
#endif
#endif /* GL_EXT_buffer_storage */
+#ifndef GL_EXT_clear_texture
+#define GL_EXT_clear_texture 1
+typedef void (GL_APIENTRYP PFNGLCLEARTEXIMAGEEXTPROC) (GLuint texture, GLint level, GLenum format, GLenum type, const void *data);
+typedef void (GL_APIENTRYP PFNGLCLEARTEXSUBIMAGEEXTPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *data);
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glClearTexImageEXT (GLuint texture, GLint level, GLenum format, GLenum type, const void *data);
+GL_APICALL void GL_APIENTRY glClearTexSubImageEXT (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *data);
+#endif
+#endif /* GL_EXT_clear_texture */
+
+#ifndef GL_EXT_clip_cull_distance
+#define GL_EXT_clip_cull_distance 1
+#define GL_MAX_CLIP_DISTANCES_EXT 0x0D32
+#define GL_MAX_CULL_DISTANCES_EXT 0x82F9
+#define GL_MAX_COMBINED_CLIP_AND_CULL_DISTANCES_EXT 0x82FA
+#define GL_CLIP_DISTANCE0_EXT 0x3000
+#define GL_CLIP_DISTANCE1_EXT 0x3001
+#define GL_CLIP_DISTANCE2_EXT 0x3002
+#define GL_CLIP_DISTANCE3_EXT 0x3003
+#define GL_CLIP_DISTANCE4_EXT 0x3004
+#define GL_CLIP_DISTANCE5_EXT 0x3005
+#define GL_CLIP_DISTANCE6_EXT 0x3006
+#define GL_CLIP_DISTANCE7_EXT 0x3007
+#endif /* GL_EXT_clip_cull_distance */
+
#ifndef GL_EXT_color_buffer_float
#define GL_EXT_color_buffer_float 1
#endif /* GL_EXT_color_buffer_float */
@@ -1100,6 +1155,10 @@
#define GL_UNSIGNED_NORMALIZED_EXT 0x8C17
#endif /* GL_EXT_color_buffer_half_float */
+#ifndef GL_EXT_conservative_depth
+#define GL_EXT_conservative_depth 1
+#endif /* GL_EXT_conservative_depth */
+
#ifndef GL_EXT_copy_image
#define GL_EXT_copy_image 1
typedef void (GL_APIENTRYP PFNGLCOPYIMAGESUBDATAEXTPROC) (GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth);
@@ -1271,6 +1330,27 @@
#endif
#endif /* GL_EXT_draw_instanced */
+#ifndef GL_EXT_draw_transform_feedback
+#define GL_EXT_draw_transform_feedback 1
+typedef void (GL_APIENTRYP PFNGLDRAWTRANSFORMFEEDBACKEXTPROC) (GLenum mode, GLuint id);
+typedef void (GL_APIENTRYP PFNGLDRAWTRANSFORMFEEDBACKINSTANCEDEXTPROC) (GLenum mode, GLuint id, GLsizei instancecount);
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glDrawTransformFeedbackEXT (GLenum mode, GLuint id);
+GL_APICALL void GL_APIENTRY glDrawTransformFeedbackInstancedEXT (GLenum mode, GLuint id, GLsizei instancecount);
+#endif
+#endif /* GL_EXT_draw_transform_feedback */
+
+#ifndef GL_EXT_external_buffer
+#define GL_EXT_external_buffer 1
+typedef void *GLeglClientBufferEXT;
+typedef void (GL_APIENTRYP PFNGLBUFFERSTORAGEEXTERNALEXTPROC) (GLenum target, GLintptr offset, GLsizeiptr size, GLeglClientBufferEXT clientBuffer, GLbitfield flags);
+typedef void (GL_APIENTRYP PFNGLNAMEDBUFFERSTORAGEEXTERNALEXTPROC) (GLuint buffer, GLintptr offset, GLsizeiptr size, GLeglClientBufferEXT clientBuffer, GLbitfield flags);
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glBufferStorageExternalEXT (GLenum target, GLintptr offset, GLsizeiptr size, GLeglClientBufferEXT clientBuffer, GLbitfield flags);
+GL_APICALL void GL_APIENTRY glNamedBufferStorageExternalEXT (GLuint buffer, GLintptr offset, GLsizeiptr size, GLeglClientBufferEXT clientBuffer, GLbitfield flags);
+#endif
+#endif /* GL_EXT_external_buffer */
+
#ifndef GL_EXT_float_blend
#define GL_EXT_float_blend 1
#endif /* GL_EXT_float_blend */
@@ -1349,6 +1429,85 @@
#endif
#endif /* GL_EXT_map_buffer_range */
+#ifndef GL_EXT_memory_object
+#define GL_EXT_memory_object 1
+#define GL_TEXTURE_TILING_EXT 0x9580
+#define GL_DEDICATED_MEMORY_OBJECT_EXT 0x9581
+#define GL_PROTECTED_MEMORY_OBJECT_EXT 0x959B
+#define GL_NUM_TILING_TYPES_EXT 0x9582
+#define GL_TILING_TYPES_EXT 0x9583
+#define GL_OPTIMAL_TILING_EXT 0x9584
+#define GL_LINEAR_TILING_EXT 0x9585
+#define GL_NUM_DEVICE_UUIDS_EXT 0x9596
+#define GL_DEVICE_UUID_EXT 0x9597
+#define GL_DRIVER_UUID_EXT 0x9598
+#define GL_UUID_SIZE_EXT 16
+typedef void (GL_APIENTRYP PFNGLGETUNSIGNEDBYTEVEXTPROC) (GLenum pname, GLubyte *data);
+typedef void (GL_APIENTRYP PFNGLGETUNSIGNEDBYTEI_VEXTPROC) (GLenum target, GLuint index, GLubyte *data);
+typedef void (GL_APIENTRYP PFNGLDELETEMEMORYOBJECTSEXTPROC) (GLsizei n, const GLuint *memoryObjects);
+typedef GLboolean (GL_APIENTRYP PFNGLISMEMORYOBJECTEXTPROC) (GLuint memoryObject);
+typedef void (GL_APIENTRYP PFNGLCREATEMEMORYOBJECTSEXTPROC) (GLsizei n, GLuint *memoryObjects);
+typedef void (GL_APIENTRYP PFNGLMEMORYOBJECTPARAMETERIVEXTPROC) (GLuint memoryObject, GLenum pname, const GLint *params);
+typedef void (GL_APIENTRYP PFNGLGETMEMORYOBJECTPARAMETERIVEXTPROC) (GLuint memoryObject, GLenum pname, GLint *params);
+typedef void (GL_APIENTRYP PFNGLTEXSTORAGEMEM2DEXTPROC) (GLenum target, GLsizei levels, GLenum internalFormat, GLsizei width, GLsizei height, GLuint memory, GLuint64 offset);
+typedef void (GL_APIENTRYP PFNGLTEXSTORAGEMEM2DMULTISAMPLEEXTPROC) (GLenum target, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations, GLuint memory, GLuint64 offset);
+typedef void (GL_APIENTRYP PFNGLTEXSTORAGEMEM3DEXTPROC) (GLenum target, GLsizei levels, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLuint memory, GLuint64 offset);
+typedef void (GL_APIENTRYP PFNGLTEXSTORAGEMEM3DMULTISAMPLEEXTPROC) (GLenum target, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations, GLuint memory, GLuint64 offset);
+typedef void (GL_APIENTRYP PFNGLBUFFERSTORAGEMEMEXTPROC) (GLenum target, GLsizeiptr size, GLuint memory, GLuint64 offset);
+typedef void (GL_APIENTRYP PFNGLTEXTURESTORAGEMEM2DEXTPROC) (GLuint texture, GLsizei levels, GLenum internalFormat, GLsizei width, GLsizei height, GLuint memory, GLuint64 offset);
+typedef void (GL_APIENTRYP PFNGLTEXTURESTORAGEMEM2DMULTISAMPLEEXTPROC) (GLuint texture, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations, GLuint memory, GLuint64 offset);
+typedef void (GL_APIENTRYP PFNGLTEXTURESTORAGEMEM3DEXTPROC) (GLuint texture, GLsizei levels, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLuint memory, GLuint64 offset);
+typedef void (GL_APIENTRYP PFNGLTEXTURESTORAGEMEM3DMULTISAMPLEEXTPROC) (GLuint texture, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations, GLuint memory, GLuint64 offset);
+typedef void (GL_APIENTRYP PFNGLNAMEDBUFFERSTORAGEMEMEXTPROC) (GLuint buffer, GLsizeiptr size, GLuint memory, GLuint64 offset);
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glGetUnsignedBytevEXT (GLenum pname, GLubyte *data);
+GL_APICALL void GL_APIENTRY glGetUnsignedBytei_vEXT (GLenum target, GLuint index, GLubyte *data);
+GL_APICALL void GL_APIENTRY glDeleteMemoryObjectsEXT (GLsizei n, const GLuint *memoryObjects);
+GL_APICALL GLboolean GL_APIENTRY glIsMemoryObjectEXT (GLuint memoryObject);
+GL_APICALL void GL_APIENTRY glCreateMemoryObjectsEXT (GLsizei n, GLuint *memoryObjects);
+GL_APICALL void GL_APIENTRY glMemoryObjectParameterivEXT (GLuint memoryObject, GLenum pname, const GLint *params);
+GL_APICALL void GL_APIENTRY glGetMemoryObjectParameterivEXT (GLuint memoryObject, GLenum pname, GLint *params);
+GL_APICALL void GL_APIENTRY glTexStorageMem2DEXT (GLenum target, GLsizei levels, GLenum internalFormat, GLsizei width, GLsizei height, GLuint memory, GLuint64 offset);
+GL_APICALL void GL_APIENTRY glTexStorageMem2DMultisampleEXT (GLenum target, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations, GLuint memory, GLuint64 offset);
+GL_APICALL void GL_APIENTRY glTexStorageMem3DEXT (GLenum target, GLsizei levels, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLuint memory, GLuint64 offset);
+GL_APICALL void GL_APIENTRY glTexStorageMem3DMultisampleEXT (GLenum target, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations, GLuint memory, GLuint64 offset);
+GL_APICALL void GL_APIENTRY glBufferStorageMemEXT (GLenum target, GLsizeiptr size, GLuint memory, GLuint64 offset);
+GL_APICALL void GL_APIENTRY glTextureStorageMem2DEXT (GLuint texture, GLsizei levels, GLenum internalFormat, GLsizei width, GLsizei height, GLuint memory, GLuint64 offset);
+GL_APICALL void GL_APIENTRY glTextureStorageMem2DMultisampleEXT (GLuint texture, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations, GLuint memory, GLuint64 offset);
+GL_APICALL void GL_APIENTRY glTextureStorageMem3DEXT (GLuint texture, GLsizei levels, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLuint memory, GLuint64 offset);
+GL_APICALL void GL_APIENTRY glTextureStorageMem3DMultisampleEXT (GLuint texture, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations, GLuint memory, GLuint64 offset);
+GL_APICALL void GL_APIENTRY glNamedBufferStorageMemEXT (GLuint buffer, GLsizeiptr size, GLuint memory, GLuint64 offset);
+#endif
+#endif /* GL_EXT_memory_object */
+
+#ifndef GL_EXT_memory_object_fd
+#define GL_EXT_memory_object_fd 1
+#define GL_HANDLE_TYPE_OPAQUE_FD_EXT 0x9586
+typedef void (GL_APIENTRYP PFNGLIMPORTMEMORYFDEXTPROC) (GLuint memory, GLuint64 size, GLenum handleType, GLint fd);
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glImportMemoryFdEXT (GLuint memory, GLuint64 size, GLenum handleType, GLint fd);
+#endif
+#endif /* GL_EXT_memory_object_fd */
+
+#ifndef GL_EXT_memory_object_win32
+#define GL_EXT_memory_object_win32 1
+#define GL_HANDLE_TYPE_OPAQUE_WIN32_EXT 0x9587
+#define GL_HANDLE_TYPE_OPAQUE_WIN32_KMT_EXT 0x9588
+#define GL_DEVICE_LUID_EXT 0x9599
+#define GL_DEVICE_NODE_MASK_EXT 0x959A
+#define GL_LUID_SIZE_EXT 8
+#define GL_HANDLE_TYPE_D3D12_TILEPOOL_EXT 0x9589
+#define GL_HANDLE_TYPE_D3D12_RESOURCE_EXT 0x958A
+#define GL_HANDLE_TYPE_D3D11_IMAGE_EXT 0x958B
+#define GL_HANDLE_TYPE_D3D11_IMAGE_KMT_EXT 0x958C
+typedef void (GL_APIENTRYP PFNGLIMPORTMEMORYWIN32HANDLEEXTPROC) (GLuint memory, GLuint64 size, GLenum handleType, void *handle);
+typedef void (GL_APIENTRYP PFNGLIMPORTMEMORYWIN32NAMEEXTPROC) (GLuint memory, GLuint64 size, GLenum handleType, const void *name);
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glImportMemoryWin32HandleEXT (GLuint memory, GLuint64 size, GLenum handleType, void *handle);
+GL_APICALL void GL_APIENTRY glImportMemoryWin32NameEXT (GLuint memory, GLuint64 size, GLenum handleType, const void *name);
+#endif
+#endif /* GL_EXT_memory_object_win32 */
+
#ifndef GL_EXT_multi_draw_arrays
#define GL_EXT_multi_draw_arrays 1
typedef void (GL_APIENTRYP PFNGLMULTIDRAWARRAYSEXTPROC) (GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount);
@@ -1412,6 +1571,15 @@
#define GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT 0x8D6A
#endif /* GL_EXT_occlusion_query_boolean */
+#ifndef GL_EXT_polygon_offset_clamp
+#define GL_EXT_polygon_offset_clamp 1
+#define GL_POLYGON_OFFSET_CLAMP_EXT 0x8E1B
+typedef void (GL_APIENTRYP PFNGLPOLYGONOFFSETCLAMPEXTPROC) (GLfloat factor, GLfloat units, GLfloat clamp);
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glPolygonOffsetClampEXT (GLfloat factor, GLfloat units, GLfloat clamp);
+#endif
+#endif /* GL_EXT_polygon_offset_clamp */
+
#ifndef GL_EXT_post_depth_coverage
#define GL_EXT_post_depth_coverage 1
#endif /* GL_EXT_post_depth_coverage */
@@ -1425,6 +1593,12 @@
#endif
#endif /* GL_EXT_primitive_bounding_box */
+#ifndef GL_EXT_protected_textures
+#define GL_EXT_protected_textures 1
+#define GL_CONTEXT_FLAG_PROTECTED_CONTENT_BIT_EXT 0x00000010
+#define GL_TEXTURE_PROTECTED_EXT 0x8BFA
+#endif /* GL_EXT_protected_textures */
+
#ifndef GL_EXT_pvrtc_sRGB
#define GL_EXT_pvrtc_sRGB 1
#define GL_COMPRESSED_SRGB_PVRTC_2BPPV1_EXT 0x8A54
@@ -1499,6 +1673,53 @@
#define GL_FRAMEBUFFER_SRGB_EXT 0x8DB9
#endif /* GL_EXT_sRGB_write_control */
+#ifndef GL_EXT_semaphore
+#define GL_EXT_semaphore 1
+#define GL_LAYOUT_GENERAL_EXT 0x958D
+#define GL_LAYOUT_COLOR_ATTACHMENT_EXT 0x958E
+#define GL_LAYOUT_DEPTH_STENCIL_ATTACHMENT_EXT 0x958F
+#define GL_LAYOUT_DEPTH_STENCIL_READ_ONLY_EXT 0x9590
+#define GL_LAYOUT_SHADER_READ_ONLY_EXT 0x9591
+#define GL_LAYOUT_TRANSFER_SRC_EXT 0x9592
+#define GL_LAYOUT_TRANSFER_DST_EXT 0x9593
+typedef void (GL_APIENTRYP PFNGLGENSEMAPHORESEXTPROC) (GLsizei n, GLuint *semaphores);
+typedef void (GL_APIENTRYP PFNGLDELETESEMAPHORESEXTPROC) (GLsizei n, const GLuint *semaphores);
+typedef GLboolean (GL_APIENTRYP PFNGLISSEMAPHOREEXTPROC) (GLuint semaphore);
+typedef void (GL_APIENTRYP PFNGLSEMAPHOREPARAMETERUI64VEXTPROC) (GLuint semaphore, GLenum pname, const GLuint64 *params);
+typedef void (GL_APIENTRYP PFNGLGETSEMAPHOREPARAMETERUI64VEXTPROC) (GLuint semaphore, GLenum pname, GLuint64 *params);
+typedef void (GL_APIENTRYP PFNGLWAITSEMAPHOREEXTPROC) (GLuint semaphore, GLuint numBufferBarriers, const GLuint *buffers, GLuint numTextureBarriers, const GLuint *textures, const GLenum *srcLayouts);
+typedef void (GL_APIENTRYP PFNGLSIGNALSEMAPHOREEXTPROC) (GLuint semaphore, GLuint numBufferBarriers, const GLuint *buffers, GLuint numTextureBarriers, const GLuint *textures, const GLenum *dstLayouts);
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glGenSemaphoresEXT (GLsizei n, GLuint *semaphores);
+GL_APICALL void GL_APIENTRY glDeleteSemaphoresEXT (GLsizei n, const GLuint *semaphores);
+GL_APICALL GLboolean GL_APIENTRY glIsSemaphoreEXT (GLuint semaphore);
+GL_APICALL void GL_APIENTRY glSemaphoreParameterui64vEXT (GLuint semaphore, GLenum pname, const GLuint64 *params);
+GL_APICALL void GL_APIENTRY glGetSemaphoreParameterui64vEXT (GLuint semaphore, GLenum pname, GLuint64 *params);
+GL_APICALL void GL_APIENTRY glWaitSemaphoreEXT (GLuint semaphore, GLuint numBufferBarriers, const GLuint *buffers, GLuint numTextureBarriers, const GLuint *textures, const GLenum *srcLayouts);
+GL_APICALL void GL_APIENTRY glSignalSemaphoreEXT (GLuint semaphore, GLuint numBufferBarriers, const GLuint *buffers, GLuint numTextureBarriers, const GLuint *textures, const GLenum *dstLayouts);
+#endif
+#endif /* GL_EXT_semaphore */
+
+#ifndef GL_EXT_semaphore_fd
+#define GL_EXT_semaphore_fd 1
+typedef void (GL_APIENTRYP PFNGLIMPORTSEMAPHOREFDEXTPROC) (GLuint semaphore, GLenum handleType, GLint fd);
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glImportSemaphoreFdEXT (GLuint semaphore, GLenum handleType, GLint fd);
+#endif
+#endif /* GL_EXT_semaphore_fd */
+
+#ifndef GL_EXT_semaphore_win32
+#define GL_EXT_semaphore_win32 1
+#define GL_HANDLE_TYPE_D3D12_FENCE_EXT 0x9594
+#define GL_D3D12_FENCE_VALUE_EXT 0x9595
+typedef void (GL_APIENTRYP PFNGLIMPORTSEMAPHOREWIN32HANDLEEXTPROC) (GLuint semaphore, GLenum handleType, void *handle);
+typedef void (GL_APIENTRYP PFNGLIMPORTSEMAPHOREWIN32NAMEEXTPROC) (GLuint semaphore, GLenum handleType, const void *name);
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glImportSemaphoreWin32HandleEXT (GLuint semaphore, GLenum handleType, void *handle);
+GL_APICALL void GL_APIENTRY glImportSemaphoreWin32NameEXT (GLuint semaphore, GLenum handleType, const void *name);
+#endif
+#endif /* GL_EXT_semaphore_win32 */
+
#ifndef GL_EXT_separate_shader_objects
#define GL_EXT_separate_shader_objects 1
#define GL_ACTIVE_PROGRAM_EXT 0x8259
@@ -1604,6 +1825,10 @@
#define GL_FRAGMENT_SHADER_DISCARDS_SAMPLES_EXT 0x8A52
#endif /* GL_EXT_shader_framebuffer_fetch */
+#ifndef GL_EXT_shader_group_vote
+#define GL_EXT_shader_group_vote 1
+#endif /* GL_EXT_shader_group_vote */
+
#ifndef GL_EXT_shader_implicit_conversions
#define GL_EXT_shader_implicit_conversions 1
#endif /* GL_EXT_shader_implicit_conversions */
@@ -1616,6 +1841,10 @@
#define GL_EXT_shader_io_blocks 1
#endif /* GL_EXT_shader_io_blocks */
+#ifndef GL_EXT_shader_non_constant_global_initializers
+#define GL_EXT_shader_non_constant_global_initializers 1
+#endif /* GL_EXT_shader_non_constant_global_initializers */
+
#ifndef GL_EXT_shader_pixel_local_storage
#define GL_EXT_shader_pixel_local_storage 1
#define GL_MAX_SHADER_PIXEL_LOCAL_STORAGE_FAST_SIZE_EXT 0x8F63
@@ -1623,6 +1852,21 @@
#define GL_SHADER_PIXEL_LOCAL_STORAGE_EXT 0x8F64
#endif /* GL_EXT_shader_pixel_local_storage */
+#ifndef GL_EXT_shader_pixel_local_storage2
+#define GL_EXT_shader_pixel_local_storage2 1
+#define GL_MAX_SHADER_COMBINED_LOCAL_STORAGE_FAST_SIZE_EXT 0x9650
+#define GL_MAX_SHADER_COMBINED_LOCAL_STORAGE_SIZE_EXT 0x9651
+#define GL_FRAMEBUFFER_INCOMPLETE_INSUFFICIENT_SHADER_COMBINED_LOCAL_STORAGE_EXT 0x9652
+typedef void (GL_APIENTRYP PFNGLFRAMEBUFFERPIXELLOCALSTORAGESIZEEXTPROC) (GLuint target, GLsizei size);
+typedef GLsizei (GL_APIENTRYP PFNGLGETFRAMEBUFFERPIXELLOCALSTORAGESIZEEXTPROC) (GLuint target);
+typedef void (GL_APIENTRYP PFNGLCLEARPIXELLOCALSTORAGEUIEXTPROC) (GLsizei offset, GLsizei n, const GLuint *values);
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glFramebufferPixelLocalStorageSizeEXT (GLuint target, GLsizei size);
+GL_APICALL GLsizei GL_APIENTRY glGetFramebufferPixelLocalStorageSizeEXT (GLuint target);
+GL_APICALL void GL_APIENTRY glClearPixelLocalStorageuiEXT (GLsizei offset, GLsizei n, const GLuint *values);
+#endif
+#endif /* GL_EXT_shader_pixel_local_storage2 */
+
#ifndef GL_EXT_shader_texture_lod
#define GL_EXT_shader_texture_lod 1
#endif /* GL_EXT_shader_texture_lod */
@@ -1656,6 +1900,10 @@
#endif
#endif /* GL_EXT_sparse_texture */
+#ifndef GL_EXT_sparse_texture2
+#define GL_EXT_sparse_texture2 1
+#endif /* GL_EXT_sparse_texture2 */
+
#ifndef GL_EXT_tessellation_point_size
#define GL_EXT_tessellation_point_size 1
#endif /* GL_EXT_tessellation_point_size */
@@ -1759,6 +2007,11 @@
#endif
#endif /* GL_EXT_texture_buffer */
+#ifndef GL_EXT_texture_compression_astc_decode_mode
+#define GL_EXT_texture_compression_astc_decode_mode 1
+#define GL_TEXTURE_ASTC_DECODE_PRECISION_EXT 0x8F69
+#endif /* GL_EXT_texture_compression_astc_decode_mode */
+
#ifndef GL_EXT_texture_compression_dxt1
#define GL_EXT_texture_compression_dxt1 1
#define GL_COMPRESSED_RGB_S3TC_DXT1_EXT 0x83F0
@@ -1888,11 +2141,67 @@
#define GL_UNPACK_SKIP_PIXELS_EXT 0x0CF4
#endif /* GL_EXT_unpack_subimage */
+#ifndef GL_EXT_win32_keyed_mutex
+#define GL_EXT_win32_keyed_mutex 1
+typedef GLboolean (GL_APIENTRYP PFNGLACQUIREKEYEDMUTEXWIN32EXTPROC) (GLuint memory, GLuint64 key, GLuint timeout);
+typedef GLboolean (GL_APIENTRYP PFNGLRELEASEKEYEDMUTEXWIN32EXTPROC) (GLuint memory, GLuint64 key);
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL GLboolean GL_APIENTRY glAcquireKeyedMutexWin32EXT (GLuint memory, GLuint64 key, GLuint timeout);
+GL_APICALL GLboolean GL_APIENTRY glReleaseKeyedMutexWin32EXT (GLuint memory, GLuint64 key);
+#endif
+#endif /* GL_EXT_win32_keyed_mutex */
+
+#ifndef GL_EXT_window_rectangles
+#define GL_EXT_window_rectangles 1
+#define GL_INCLUSIVE_EXT 0x8F10
+#define GL_EXCLUSIVE_EXT 0x8F11
+#define GL_WINDOW_RECTANGLE_EXT 0x8F12
+#define GL_WINDOW_RECTANGLE_MODE_EXT 0x8F13
+#define GL_MAX_WINDOW_RECTANGLES_EXT 0x8F14
+#define GL_NUM_WINDOW_RECTANGLES_EXT 0x8F15
+typedef void (GL_APIENTRYP PFNGLWINDOWRECTANGLESEXTPROC) (GLenum mode, GLsizei count, const GLint *box);
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glWindowRectanglesEXT (GLenum mode, GLsizei count, const GLint *box);
+#endif
+#endif /* GL_EXT_window_rectangles */
+
#ifndef GL_FJ_shader_binary_GCCSO
#define GL_FJ_shader_binary_GCCSO 1
#define GL_GCCSO_SHADER_BINARY_FJ 0x9260
#endif /* GL_FJ_shader_binary_GCCSO */
+#ifndef GL_IMG_bindless_texture
+#define GL_IMG_bindless_texture 1
+typedef GLuint64 (GL_APIENTRYP PFNGLGETTEXTUREHANDLEIMGPROC) (GLuint texture);
+typedef GLuint64 (GL_APIENTRYP PFNGLGETTEXTURESAMPLERHANDLEIMGPROC) (GLuint texture, GLuint sampler);
+typedef void (GL_APIENTRYP PFNGLUNIFORMHANDLEUI64IMGPROC) (GLint location, GLuint64 value);
+typedef void (GL_APIENTRYP PFNGLUNIFORMHANDLEUI64VIMGPROC) (GLint location, GLsizei count, const GLuint64 *value);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORMHANDLEUI64IMGPROC) (GLuint program, GLint location, GLuint64 value);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORMHANDLEUI64VIMGPROC) (GLuint program, GLint location, GLsizei count, const GLuint64 *values);
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL GLuint64 GL_APIENTRY glGetTextureHandleIMG (GLuint texture);
+GL_APICALL GLuint64 GL_APIENTRY glGetTextureSamplerHandleIMG (GLuint texture, GLuint sampler);
+GL_APICALL void GL_APIENTRY glUniformHandleui64IMG (GLint location, GLuint64 value);
+GL_APICALL void GL_APIENTRY glUniformHandleui64vIMG (GLint location, GLsizei count, const GLuint64 *value);
+GL_APICALL void GL_APIENTRY glProgramUniformHandleui64IMG (GLuint program, GLint location, GLuint64 value);
+GL_APICALL void GL_APIENTRY glProgramUniformHandleui64vIMG (GLuint program, GLint location, GLsizei count, const GLuint64 *values);
+#endif
+#endif /* GL_IMG_bindless_texture */
+
+#ifndef GL_IMG_framebuffer_downsample
+#define GL_IMG_framebuffer_downsample 1
+#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_AND_DOWNSAMPLE_IMG 0x913C
+#define GL_NUM_DOWNSAMPLE_SCALES_IMG 0x913D
+#define GL_DOWNSAMPLE_SCALES_IMG 0x913E
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_SCALE_IMG 0x913F
+typedef void (GL_APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DDOWNSAMPLEIMGPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint xscale, GLint yscale);
+typedef void (GL_APIENTRYP PFNGLFRAMEBUFFERTEXTURELAYERDOWNSAMPLEIMGPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer, GLint xscale, GLint yscale);
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glFramebufferTexture2DDownsampleIMG (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint xscale, GLint yscale);
+GL_APICALL void GL_APIENTRY glFramebufferTextureLayerDownsampleIMG (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer, GLint xscale, GLint yscale);
+#endif
+#endif /* GL_IMG_framebuffer_downsample */
+
#ifndef GL_IMG_multisampled_render_to_texture
#define GL_IMG_multisampled_render_to_texture 1
#define GL_RENDERBUFFER_SAMPLES_IMG 0x9133
@@ -1944,6 +2253,11 @@
#define GL_CUBIC_MIPMAP_LINEAR_IMG 0x913B
#endif /* GL_IMG_texture_filter_cubic */
+#ifndef GL_INTEL_conservative_rasterization
+#define GL_INTEL_conservative_rasterization 1
+#define GL_CONSERVATIVE_RASTERIZATION_INTEL 0x83FE
+#endif /* GL_INTEL_conservative_rasterization */
+
#ifndef GL_INTEL_framebuffer_CMAA
#define GL_INTEL_framebuffer_CMAA 1
typedef void (GL_APIENTRYP PFNGLAPPLYFRAMEBUFFERATTACHMENTCMAAINTELPROC) (void);
@@ -1998,6 +2312,14 @@
#endif
#endif /* GL_INTEL_performance_query */
+#ifndef GL_MESA_shader_integer_functions
+#define GL_MESA_shader_integer_functions 1
+#endif /* GL_MESA_shader_integer_functions */
+
+#ifndef GL_NVX_blend_equation_advanced_multi_draw_buffers
+#define GL_NVX_blend_equation_advanced_multi_draw_buffers 1
+#endif /* GL_NVX_blend_equation_advanced_multi_draw_buffers */
+
#ifndef GL_NV_bindless_texture
#define GL_NV_bindless_texture 1
typedef GLuint64 (GL_APIENTRYP PFNGLGETTEXTUREHANDLENVPROC) (GLuint texture);
@@ -2120,6 +2442,17 @@
#endif
#endif /* GL_NV_conservative_raster */
+#ifndef GL_NV_conservative_raster_pre_snap_triangles
+#define GL_NV_conservative_raster_pre_snap_triangles 1
+#define GL_CONSERVATIVE_RASTER_MODE_NV 0x954D
+#define GL_CONSERVATIVE_RASTER_MODE_POST_SNAP_NV 0x954E
+#define GL_CONSERVATIVE_RASTER_MODE_PRE_SNAP_TRIANGLES_NV 0x954F
+typedef void (GL_APIENTRYP PFNGLCONSERVATIVERASTERPARAMETERINVPROC) (GLenum pname, GLint param);
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glConservativeRasterParameteriNV (GLenum pname, GLint param);
+#endif
+#endif /* GL_NV_conservative_raster_pre_snap_triangles */
+
#ifndef GL_NV_copy_buffer
#define GL_NV_copy_buffer 1
#define GL_COPY_READ_BUFFER_NV 0x8F36
@@ -2205,6 +2538,23 @@
#endif
#endif /* GL_NV_draw_instanced */
+#ifndef GL_NV_draw_vulkan_image
+#define GL_NV_draw_vulkan_image 1
+typedef void (GL_APIENTRY *GLVULKANPROCNV)(void);
+typedef void (GL_APIENTRYP PFNGLDRAWVKIMAGENVPROC) (GLuint64 vkImage, GLuint sampler, GLfloat x0, GLfloat y0, GLfloat x1, GLfloat y1, GLfloat z, GLfloat s0, GLfloat t0, GLfloat s1, GLfloat t1);
+typedef GLVULKANPROCNV (GL_APIENTRYP PFNGLGETVKPROCADDRNVPROC) (const GLchar *name);
+typedef void (GL_APIENTRYP PFNGLWAITVKSEMAPHORENVPROC) (GLuint64 vkSemaphore);
+typedef void (GL_APIENTRYP PFNGLSIGNALVKSEMAPHORENVPROC) (GLuint64 vkSemaphore);
+typedef void (GL_APIENTRYP PFNGLSIGNALVKFENCENVPROC) (GLuint64 vkFence);
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glDrawVkImageNV (GLuint64 vkImage, GLuint sampler, GLfloat x0, GLfloat y0, GLfloat x1, GLfloat y1, GLfloat z, GLfloat s0, GLfloat t0, GLfloat s1, GLfloat t1);
+GL_APICALL GLVULKANPROCNV GL_APIENTRY glGetVkProcAddrNV (const GLchar *name);
+GL_APICALL void GL_APIENTRY glWaitVkSemaphoreNV (GLuint64 vkSemaphore);
+GL_APICALL void GL_APIENTRY glSignalVkSemaphoreNV (GLuint64 vkSemaphore);
+GL_APICALL void GL_APIENTRY glSignalVkFenceNV (GLuint64 vkFence);
+#endif
+#endif /* GL_NV_draw_vulkan_image */
+
#ifndef GL_NV_explicit_attrib_location
#define GL_NV_explicit_attrib_location 1
#endif /* GL_NV_explicit_attrib_location */
@@ -2307,6 +2657,109 @@
#define GL_NV_geometry_shader_passthrough 1
#endif /* GL_NV_geometry_shader_passthrough */
+#ifndef GL_NV_gpu_shader5
+#define GL_NV_gpu_shader5 1
+typedef khronos_int64_t GLint64EXT;
+typedef khronos_uint64_t GLuint64EXT;
+#define GL_INT64_NV 0x140E
+#define GL_UNSIGNED_INT64_NV 0x140F
+#define GL_INT8_NV 0x8FE0
+#define GL_INT8_VEC2_NV 0x8FE1
+#define GL_INT8_VEC3_NV 0x8FE2
+#define GL_INT8_VEC4_NV 0x8FE3
+#define GL_INT16_NV 0x8FE4
+#define GL_INT16_VEC2_NV 0x8FE5
+#define GL_INT16_VEC3_NV 0x8FE6
+#define GL_INT16_VEC4_NV 0x8FE7
+#define GL_INT64_VEC2_NV 0x8FE9
+#define GL_INT64_VEC3_NV 0x8FEA
+#define GL_INT64_VEC4_NV 0x8FEB
+#define GL_UNSIGNED_INT8_NV 0x8FEC
+#define GL_UNSIGNED_INT8_VEC2_NV 0x8FED
+#define GL_UNSIGNED_INT8_VEC3_NV 0x8FEE
+#define GL_UNSIGNED_INT8_VEC4_NV 0x8FEF
+#define GL_UNSIGNED_INT16_NV 0x8FF0
+#define GL_UNSIGNED_INT16_VEC2_NV 0x8FF1
+#define GL_UNSIGNED_INT16_VEC3_NV 0x8FF2
+#define GL_UNSIGNED_INT16_VEC4_NV 0x8FF3
+#define GL_UNSIGNED_INT64_VEC2_NV 0x8FF5
+#define GL_UNSIGNED_INT64_VEC3_NV 0x8FF6
+#define GL_UNSIGNED_INT64_VEC4_NV 0x8FF7
+#define GL_FLOAT16_NV 0x8FF8
+#define GL_FLOAT16_VEC2_NV 0x8FF9
+#define GL_FLOAT16_VEC3_NV 0x8FFA
+#define GL_FLOAT16_VEC4_NV 0x8FFB
+#define GL_PATCHES 0x000E
+typedef void (GL_APIENTRYP PFNGLUNIFORM1I64NVPROC) (GLint location, GLint64EXT x);
+typedef void (GL_APIENTRYP PFNGLUNIFORM2I64NVPROC) (GLint location, GLint64EXT x, GLint64EXT y);
+typedef void (GL_APIENTRYP PFNGLUNIFORM3I64NVPROC) (GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z);
+typedef void (GL_APIENTRYP PFNGLUNIFORM4I64NVPROC) (GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z, GLint64EXT w);
+typedef void (GL_APIENTRYP PFNGLUNIFORM1I64VNVPROC) (GLint location, GLsizei count, const GLint64EXT *value);
+typedef void (GL_APIENTRYP PFNGLUNIFORM2I64VNVPROC) (GLint location, GLsizei count, const GLint64EXT *value);
+typedef void (GL_APIENTRYP PFNGLUNIFORM3I64VNVPROC) (GLint location, GLsizei count, const GLint64EXT *value);
+typedef void (GL_APIENTRYP PFNGLUNIFORM4I64VNVPROC) (GLint location, GLsizei count, const GLint64EXT *value);
+typedef void (GL_APIENTRYP PFNGLUNIFORM1UI64NVPROC) (GLint location, GLuint64EXT x);
+typedef void (GL_APIENTRYP PFNGLUNIFORM2UI64NVPROC) (GLint location, GLuint64EXT x, GLuint64EXT y);
+typedef void (GL_APIENTRYP PFNGLUNIFORM3UI64NVPROC) (GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z);
+typedef void (GL_APIENTRYP PFNGLUNIFORM4UI64NVPROC) (GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z, GLuint64EXT w);
+typedef void (GL_APIENTRYP PFNGLUNIFORM1UI64VNVPROC) (GLint location, GLsizei count, const GLuint64EXT *value);
+typedef void (GL_APIENTRYP PFNGLUNIFORM2UI64VNVPROC) (GLint location, GLsizei count, const GLuint64EXT *value);
+typedef void (GL_APIENTRYP PFNGLUNIFORM3UI64VNVPROC) (GLint location, GLsizei count, const GLuint64EXT *value);
+typedef void (GL_APIENTRYP PFNGLUNIFORM4UI64VNVPROC) (GLint location, GLsizei count, const GLuint64EXT *value);
+typedef void (GL_APIENTRYP PFNGLGETUNIFORMI64VNVPROC) (GLuint program, GLint location, GLint64EXT *params);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM1I64NVPROC) (GLuint program, GLint location, GLint64EXT x);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM2I64NVPROC) (GLuint program, GLint location, GLint64EXT x, GLint64EXT y);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM3I64NVPROC) (GLuint program, GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM4I64NVPROC) (GLuint program, GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z, GLint64EXT w);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM1I64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLint64EXT *value);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM2I64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLint64EXT *value);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM3I64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLint64EXT *value);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM4I64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLint64EXT *value);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM1UI64NVPROC) (GLuint program, GLint location, GLuint64EXT x);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM2UI64NVPROC) (GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM3UI64NVPROC) (GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM4UI64NVPROC) (GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z, GLuint64EXT w);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM1UI64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM2UI64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM3UI64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM4UI64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value);
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glUniform1i64NV (GLint location, GLint64EXT x);
+GL_APICALL void GL_APIENTRY glUniform2i64NV (GLint location, GLint64EXT x, GLint64EXT y);
+GL_APICALL void GL_APIENTRY glUniform3i64NV (GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z);
+GL_APICALL void GL_APIENTRY glUniform4i64NV (GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z, GLint64EXT w);
+GL_APICALL void GL_APIENTRY glUniform1i64vNV (GLint location, GLsizei count, const GLint64EXT *value);
+GL_APICALL void GL_APIENTRY glUniform2i64vNV (GLint location, GLsizei count, const GLint64EXT *value);
+GL_APICALL void GL_APIENTRY glUniform3i64vNV (GLint location, GLsizei count, const GLint64EXT *value);
+GL_APICALL void GL_APIENTRY glUniform4i64vNV (GLint location, GLsizei count, const GLint64EXT *value);
+GL_APICALL void GL_APIENTRY glUniform1ui64NV (GLint location, GLuint64EXT x);
+GL_APICALL void GL_APIENTRY glUniform2ui64NV (GLint location, GLuint64EXT x, GLuint64EXT y);
+GL_APICALL void GL_APIENTRY glUniform3ui64NV (GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z);
+GL_APICALL void GL_APIENTRY glUniform4ui64NV (GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z, GLuint64EXT w);
+GL_APICALL void GL_APIENTRY glUniform1ui64vNV (GLint location, GLsizei count, const GLuint64EXT *value);
+GL_APICALL void GL_APIENTRY glUniform2ui64vNV (GLint location, GLsizei count, const GLuint64EXT *value);
+GL_APICALL void GL_APIENTRY glUniform3ui64vNV (GLint location, GLsizei count, const GLuint64EXT *value);
+GL_APICALL void GL_APIENTRY glUniform4ui64vNV (GLint location, GLsizei count, const GLuint64EXT *value);
+GL_APICALL void GL_APIENTRY glGetUniformi64vNV (GLuint program, GLint location, GLint64EXT *params);
+GL_APICALL void GL_APIENTRY glProgramUniform1i64NV (GLuint program, GLint location, GLint64EXT x);
+GL_APICALL void GL_APIENTRY glProgramUniform2i64NV (GLuint program, GLint location, GLint64EXT x, GLint64EXT y);
+GL_APICALL void GL_APIENTRY glProgramUniform3i64NV (GLuint program, GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z);
+GL_APICALL void GL_APIENTRY glProgramUniform4i64NV (GLuint program, GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z, GLint64EXT w);
+GL_APICALL void GL_APIENTRY glProgramUniform1i64vNV (GLuint program, GLint location, GLsizei count, const GLint64EXT *value);
+GL_APICALL void GL_APIENTRY glProgramUniform2i64vNV (GLuint program, GLint location, GLsizei count, const GLint64EXT *value);
+GL_APICALL void GL_APIENTRY glProgramUniform3i64vNV (GLuint program, GLint location, GLsizei count, const GLint64EXT *value);
+GL_APICALL void GL_APIENTRY glProgramUniform4i64vNV (GLuint program, GLint location, GLsizei count, const GLint64EXT *value);
+GL_APICALL void GL_APIENTRY glProgramUniform1ui64NV (GLuint program, GLint location, GLuint64EXT x);
+GL_APICALL void GL_APIENTRY glProgramUniform2ui64NV (GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y);
+GL_APICALL void GL_APIENTRY glProgramUniform3ui64NV (GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z);
+GL_APICALL void GL_APIENTRY glProgramUniform4ui64NV (GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z, GLuint64EXT w);
+GL_APICALL void GL_APIENTRY glProgramUniform1ui64vNV (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value);
+GL_APICALL void GL_APIENTRY glProgramUniform2ui64vNV (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value);
+GL_APICALL void GL_APIENTRY glProgramUniform3ui64vNV (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value);
+GL_APICALL void GL_APIENTRY glProgramUniform4ui64vNV (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value);
+#endif
+#endif /* GL_NV_gpu_shader5 */
+
#ifndef GL_NV_image_formats
#define GL_NV_image_formats 1
#endif /* GL_NV_image_formats */
@@ -2713,6 +3166,10 @@
#define GL_NV_sample_mask_override_coverage 1
#endif /* GL_NV_sample_mask_override_coverage */
+#ifndef GL_NV_shader_atomic_fp16_vector
+#define GL_NV_shader_atomic_fp16_vector 1
+#endif /* GL_NV_shader_atomic_fp16_vector */
+
#ifndef GL_NV_shader_noperspective_interpolation
#define GL_NV_shader_noperspective_interpolation 1
#endif /* GL_NV_shader_noperspective_interpolation */
@@ -2779,11 +3236,32 @@
#define GL_NV_viewport_array2 1
#endif /* GL_NV_viewport_array2 */
+#ifndef GL_NV_viewport_swizzle
+#define GL_NV_viewport_swizzle 1
+#define GL_VIEWPORT_SWIZZLE_POSITIVE_X_NV 0x9350
+#define GL_VIEWPORT_SWIZZLE_NEGATIVE_X_NV 0x9351
+#define GL_VIEWPORT_SWIZZLE_POSITIVE_Y_NV 0x9352
+#define GL_VIEWPORT_SWIZZLE_NEGATIVE_Y_NV 0x9353
+#define GL_VIEWPORT_SWIZZLE_POSITIVE_Z_NV 0x9354
+#define GL_VIEWPORT_SWIZZLE_NEGATIVE_Z_NV 0x9355
+#define GL_VIEWPORT_SWIZZLE_POSITIVE_W_NV 0x9356
+#define GL_VIEWPORT_SWIZZLE_NEGATIVE_W_NV 0x9357
+#define GL_VIEWPORT_SWIZZLE_X_NV 0x9358
+#define GL_VIEWPORT_SWIZZLE_Y_NV 0x9359
+#define GL_VIEWPORT_SWIZZLE_Z_NV 0x935A
+#define GL_VIEWPORT_SWIZZLE_W_NV 0x935B
+typedef void (GL_APIENTRYP PFNGLVIEWPORTSWIZZLENVPROC) (GLuint index, GLenum swizzlex, GLenum swizzley, GLenum swizzlez, GLenum swizzlew);
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glViewportSwizzleNV (GLuint index, GLenum swizzlex, GLenum swizzley, GLenum swizzlez, GLenum swizzlew);
+#endif
+#endif /* GL_NV_viewport_swizzle */
+
#ifndef GL_OVR_multiview
#define GL_OVR_multiview 1
#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_NUM_VIEWS_OVR 0x9630
#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_BASE_VIEW_INDEX_OVR 0x9632
#define GL_MAX_VIEWS_OVR 0x9631
+#define GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_OVR 0x9633
typedef void (GL_APIENTRYP PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint baseViewIndex, GLsizei numViews);
#ifdef GL_GLEXT_PROTOTYPES
GL_APICALL void GL_APIENTRY glFramebufferTextureMultiviewOVR (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint baseViewIndex, GLsizei numViews);
@@ -2882,11 +3360,32 @@
#endif
#endif /* GL_QCOM_extended_get2 */
+#ifndef GL_QCOM_framebuffer_foveated
+#define GL_QCOM_framebuffer_foveated 1
+#define GL_FOVEATION_ENABLE_BIT_QCOM 0x00000001
+#define GL_FOVEATION_SCALED_BIN_METHOD_BIT_QCOM 0x00000002
+typedef void (GL_APIENTRYP PFNGLFRAMEBUFFERFOVEATIONCONFIGQCOMPROC) (GLuint framebuffer, GLuint numLayers, GLuint focalPointsPerLayer, GLuint requestedFeatures, GLuint *providedFeatures);
+typedef void (GL_APIENTRYP PFNGLFRAMEBUFFERFOVEATIONPARAMETERSQCOMPROC) (GLuint framebuffer, GLuint layer, GLuint focalPoint, GLfloat focalX, GLfloat focalY, GLfloat gainX, GLfloat gainY, GLfloat foveaArea);
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glFramebufferFoveationConfigQCOM (GLuint framebuffer, GLuint numLayers, GLuint focalPointsPerLayer, GLuint requestedFeatures, GLuint *providedFeatures);
+GL_APICALL void GL_APIENTRY glFramebufferFoveationParametersQCOM (GLuint framebuffer, GLuint layer, GLuint focalPoint, GLfloat focalX, GLfloat focalY, GLfloat gainX, GLfloat gainY, GLfloat foveaArea);
+#endif
+#endif /* GL_QCOM_framebuffer_foveated */
+
#ifndef GL_QCOM_perfmon_global_mode
#define GL_QCOM_perfmon_global_mode 1
#define GL_PERFMON_GLOBAL_MODE_QCOM 0x8FA0
#endif /* GL_QCOM_perfmon_global_mode */
+#ifndef GL_QCOM_shader_framebuffer_fetch_noncoherent
+#define GL_QCOM_shader_framebuffer_fetch_noncoherent 1
+#define GL_FRAMEBUFFER_FETCH_NONCOHERENT_QCOM 0x96A2
+typedef void (GL_APIENTRYP PFNGLFRAMEBUFFERFETCHBARRIERQCOMPROC) (void);
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glFramebufferFetchBarrierQCOM (void);
+#endif
+#endif /* GL_QCOM_shader_framebuffer_fetch_noncoherent */
+
#ifndef GL_QCOM_tiled_rendering
#define GL_QCOM_tiled_rendering 1
#define GL_COLOR_BUFFER_BIT0_QCOM 0x00000001
diff --git a/opengl/include/GLES2/gl2platform.h b/opengl/include/GLES2/gl2platform.h
index 89d4d44..eb318dc 100644
--- a/opengl/include/GLES2/gl2platform.h
+++ b/opengl/include/GLES2/gl2platform.h
@@ -1,20 +1,28 @@
#ifndef __gl2platform_h_
#define __gl2platform_h_
-/* $Revision: 23328 $ on $Date:: 2013-10-02 02:28:28 -0700 #$ */
-
/*
- * This document is licensed under the SGI Free Software B License Version
- * 2.0. For details, see http://oss.sgi.com/projects/FreeB/ .
- */
+** Copyright (c) 2017 The Khronos Group Inc.
+**
+** 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.
+*/
/* Platform-specific types and definitions for OpenGL ES 2.X gl2.h
*
* Adopters may modify khrplatform.h and this file to suit their platform.
- * You are encouraged to submit all modifications to the Khronos group so that
- * they can be included in future versions of this file. Please submit changes
- * by sending them to the public Khronos Bugzilla (http://khronos.org/bugzilla)
- * by filing a bug against product "OpenGL-ES" component "Registry".
+ * Please contribute modifications back to Khronos as pull requests on the
+ * public github repository:
+ * https://github.com/KhronosGroup/OpenGL-Registry
*/
#include <KHR/khrplatform.h>
diff --git a/opengl/include/GLES3/NOTICE b/opengl/include/GLES3/NOTICE
index 7a94373..73e9f18 100644
--- a/opengl/include/GLES3/NOTICE
+++ b/opengl/include/GLES3/NOTICE
@@ -1,4 +1,21 @@
-Copyright (c) 2013-2015 The Khronos Group Inc.
+This document is licensed under the SGI Free Software B License Version
+2.0. For details, see http://oss.sgi.com/projects/FreeB/ .
+
+Copyright (c) 2017 The Khronos Group Inc.
+
+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.
+
+Copyright (c) 2013-2017 The Khronos Group Inc.
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and/or associated documentation files (the
@@ -18,3 +35,4 @@
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+
diff --git a/opengl/include/GLES3/gl3.h b/opengl/include/GLES3/gl3.h
index d51d2e6..f1f3a65 100644
--- a/opengl/include/GLES3/gl3.h
+++ b/opengl/include/GLES3/gl3.h
@@ -6,7 +6,7 @@
#endif
/*
-** Copyright (c) 2013-2015 The Khronos Group Inc.
+** Copyright (c) 2013-2017 The Khronos Group Inc.
**
** Permission is hereby granted, free of charge, to any person obtaining a
** copy of this software and/or associated documentation files (the
@@ -31,9 +31,7 @@
** This header is generated from the Khronos OpenGL / OpenGL ES XML
** API Registry. The current version of the Registry, generator scripts
** used to make the header, and the header can be found at
-** http://www.opengl.org/registry/
-**
-** Khronos $Revision: 32120 $ on $Date: 2015-10-15 04:27:13 -0700 (Thu, 15 Oct 2015) $
+** https://github.com/KhronosGroup/OpenGL-Registry
*/
#include <GLES3/gl3platform.h>
@@ -42,11 +40,11 @@
#define GL_APIENTRYP GL_APIENTRY*
#endif
-#if !defined(GL_GLES_PROTOTYPES)
+#ifndef GL_GLES_PROTOTYPES
#define GL_GLES_PROTOTYPES 1
#endif
-/* Generated on date 20151015 */
+/* Generated on date 20170613 */
/* Generated C header for:
* API: gles2
diff --git a/opengl/include/GLES3/gl31.h b/opengl/include/GLES3/gl31.h
index 9b89a0a..4806181 100644
--- a/opengl/include/GLES3/gl31.h
+++ b/opengl/include/GLES3/gl31.h
@@ -6,7 +6,7 @@
#endif
/*
-** Copyright (c) 2013-2015 The Khronos Group Inc.
+** Copyright (c) 2013-2016 The Khronos Group Inc.
**
** Permission is hereby granted, free of charge, to any person obtaining a
** copy of this software and/or associated documentation files (the
@@ -42,11 +42,11 @@
#define GL_APIENTRYP GL_APIENTRY*
#endif
-#if !defined(GL_GLES_PROTOTYPES)
+#ifndef GL_GLES_PROTOTYPES
#define GL_GLES_PROTOTYPES 1
#endif
-/* Generated on date 20151015 */
+/* Generated on date 20161024 */
/* Generated C header for:
* API: gles2
diff --git a/opengl/include/GLES3/gl32.h b/opengl/include/GLES3/gl32.h
index a2c3611..a1af7c6 100644
--- a/opengl/include/GLES3/gl32.h
+++ b/opengl/include/GLES3/gl32.h
@@ -6,7 +6,7 @@
#endif
/*
-** Copyright (c) 2013-2015 The Khronos Group Inc.
+** Copyright (c) 2013-2016 The Khronos Group Inc.
**
** Permission is hereby granted, free of charge, to any person obtaining a
** copy of this software and/or associated documentation files (the
@@ -42,11 +42,11 @@
#define GL_APIENTRYP GL_APIENTRY*
#endif
-#if !defined(GL_GLES_PROTOTYPES)
+#ifndef GL_GLES_PROTOTYPES
#define GL_GLES_PROTOTYPES 1
#endif
-/* Generated on date 20151015 */
+/* Generated on date 20161024 */
/* Generated C header for:
* API: gles2
diff --git a/opengl/include/GLES3/gl3platform.h b/opengl/include/GLES3/gl3platform.h
index b1e869d..ca9d7a6 100644
--- a/opengl/include/GLES3/gl3platform.h
+++ b/opengl/include/GLES3/gl3platform.h
@@ -1,20 +1,28 @@
#ifndef __gl3platform_h_
#define __gl3platform_h_
-/* $Revision: 23328 $ on $Date:: 2013-10-02 02:28:28 -0700 #$ */
-
/*
- * This document is licensed under the SGI Free Software B License Version
- * 2.0. For details, see http://oss.sgi.com/projects/FreeB/ .
- */
+** Copyright (c) 2017 The Khronos Group Inc.
+**
+** 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.
+*/
/* Platform-specific types and definitions for OpenGL ES 3.X gl3.h
*
* Adopters may modify khrplatform.h and this file to suit their platform.
- * You are encouraged to submit all modifications to the Khronos group so that
- * they can be included in future versions of this file. Please submit changes
- * by sending them to the public Khronos Bugzilla (http://khronos.org/bugzilla)
- * by filing a bug against product "OpenGL-ES" component "Registry".
+ * Please contribute modifications back to Khronos as pull requests on the
+ * public github repository:
+ * https://github.com/KhronosGroup/OpenGL-Registry
*/
#include <KHR/khrplatform.h>
diff --git a/opengl/libagl/Android.mk b/opengl/libagl/Android.mk
index c7635e2..15a12e4 100644
--- a/opengl/libagl/Android.mk
+++ b/opengl/libagl/Android.mk
@@ -38,6 +38,8 @@
# The graphics code can generate division by zero
LOCAL_CFLAGS_mips += -mno-check-zero-division
+LOCAL_CFLAGS += -Wall -Werror
+
# we need to access the private Bionic header <bionic_tls.h>
LOCAL_C_INCLUDES += bionic/libc/private
diff --git a/opengl/libagl/array.cpp b/opengl/libagl/array.cpp
index 54207fa..2d36c61 100644
--- a/opengl/libagl/array.cpp
+++ b/opengl/libagl/array.cpp
@@ -136,9 +136,6 @@
static void currentColor(ogles_context_t* c, GLfixed* v, const GLvoid*) {
memcpy(v, c->current.color.v, sizeof(vec4_t));
}
-static void currentColor_clamp(ogles_context_t* c, GLfixed* v, const GLvoid*) {
- memcpy(v, c->currentColorClamped.v, sizeof(vec4_t));
-}
static void currentNormal(ogles_context_t* c, GLfixed* v, const GLvoid*) {
memcpy(v, c->currentNormal.v, sizeof(vec3_t));
}
@@ -349,6 +346,7 @@
{
// make sure the size of vertex_t allows cache-line alignment
CTA<(sizeof(vertex_t) & 0x1F) == 0> assertAlignedSize;
+ (void)assertAlignedSize; // suppress unused warning.
const int align = 32;
const size_t s = VERTEX_BUFFER_SIZE + VERTEX_CACHE_SIZE;
diff --git a/opengl/libagl/egl.cpp b/opengl/libagl/egl.cpp
index b79051c..be43705 100644
--- a/opengl/libagl/egl.cpp
+++ b/opengl/libagl/egl.cpp
@@ -81,7 +81,9 @@
const unsigned int NUM_DISPLAYS = 1;
+#ifndef __ANDROID__
static pthread_mutex_t gInitMutex = PTHREAD_MUTEX_INITIALIZER;
+#endif
static pthread_mutex_t gErrorKeyMutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_key_t gEGLErrorKey = -1;
#ifndef __ANDROID__
@@ -1776,7 +1778,6 @@
// if we're detaching, we need the current context
current_ctx = (EGLContext)getGlThreadSpecific();
} else {
- egl_context_t* c = egl_context_t::context(ctx);
egl_surface_t* d = (egl_surface_t*)draw;
egl_surface_t* r = (egl_surface_t*)read;
if ((d && d->ctx && d->ctx != ctx) ||
diff --git a/opengl/libagl/light.cpp b/opengl/libagl/light.cpp
index e7fe9d7..216c725 100644
--- a/opengl/libagl/light.cpp
+++ b/opengl/libagl/light.cpp
@@ -467,7 +467,6 @@
}
light_t& light = c->lighting.lights[i-GL_LIGHT0];
- const GLfixed kDegToRad = GLfixed((M_PI * gglIntToFixed(1)) / 180.0f);
switch (pname) {
case GL_SPOT_EXPONENT:
if (GGLfixed(param) >= gglIntToFixed(128)) {
diff --git a/opengl/libagl/matrix.cpp b/opengl/libagl/matrix.cpp
index 034c857..edd474d 100644
--- a/opengl/libagl/matrix.cpp
+++ b/opengl/libagl/matrix.cpp
@@ -51,7 +51,6 @@
static void point2__nop(transform_t const*, vec4_t* c, vec4_t const* o);
static void point3__nop(transform_t const*, vec4_t* c, vec4_t const* o);
static void point4__nop(transform_t const*, vec4_t* c, vec4_t const* o);
-static void normal__nop(transform_t const*, vec4_t* c, vec4_t const* o);
static void point2__generic(transform_t const*, vec4_t* c, vec4_t const* o);
static void point3__generic(transform_t const*, vec4_t* c, vec4_t const* o);
static void point4__generic(transform_t const*, vec4_t* c, vec4_t const* o);
@@ -524,16 +523,6 @@
}
}
-static inline
-GLfloat det22(GLfloat a, GLfloat b, GLfloat c, GLfloat d) {
- return a*d - b*c;
-}
-
-static inline
-GLfloat ndet22(GLfloat a, GLfloat b, GLfloat c, GLfloat d) {
- return b*c - a*d;
-}
-
static __attribute__((noinline))
void invert(GLfloat* inverse, const GLfloat* src)
{
diff --git a/opengl/libagl/primitives.cpp b/opengl/libagl/primitives.cpp
index 57a798d..d3b19e8 100644
--- a/opengl/libagl/primitives.cpp
+++ b/opengl/libagl/primitives.cpp
@@ -241,6 +241,7 @@
m_dx20 = v0->window.x - v2->window.x;
m_dy02 = v2->window.y - v0->window.y;
m_area = m_dx01*m_dy02 + (-m_dy10)*m_dx20;
+ (void)m_reserved; // suppress unused warning
}
void compute_iterators_t::initLine(
diff --git a/opengl/libagl/texture.cpp b/opengl/libagl/texture.cpp
index 3fe5ed0..aae8e05 100644
--- a/opengl/libagl/texture.cpp
+++ b/opengl/libagl/texture.cpp
@@ -356,10 +356,6 @@
GLenum format, GLenum type, GLsizei width, GLsizei height,
GLenum compressedFormat = 0)
{
- // find out which texture is bound to the current unit
- const int active = c->textures.active;
- const GLuint name = c->textures.tmu[active].name;
-
// convert the pixelformat to one we can handle
const int32_t formatIdx = convertGLPixelFormat(format, type);
if (formatIdx == 0) { // we don't know what to do with this
@@ -1192,7 +1188,6 @@
const GGLFormat& pixelFormat(c->rasterizer.formats[formatIdx]);
const int32_t align = c->textures.unpackAlignment-1;
const int32_t bpr = ((width * pixelFormat.size) + align) & ~align;
- const size_t size = bpr * height;
const int32_t stride = bpr / pixelFormat.size;
GGLSurface userSurface;
@@ -1276,7 +1271,6 @@
const GGLFormat& pixelFormat(c->rasterizer.formats[formatIdx]);
const int32_t align = c->textures.unpackAlignment-1;
const int32_t bpr = ((width * pixelFormat.size) + align) & ~align;
- const size_t size = bpr * height;
const int32_t stride = bpr / pixelFormat.size;
GGLSurface userSurface;
userSurface.version = sizeof(userSurface);
diff --git a/opengl/libs/Android.bp b/opengl/libs/Android.bp
index 4e275db..d43c164 100644
--- a/opengl/libs/Android.bp
+++ b/opengl/libs/Android.bp
@@ -3,6 +3,7 @@
name: "libETC1",
srcs: ["ETC1/etc1.cpp"],
host_supported: true,
+ cflags: ["-Wall", "-Werror"],
target: {
android: {
@@ -56,6 +57,9 @@
"-DGL_GLEXT_PROTOTYPES",
"-DEGL_EGLEXT_PROTOTYPES",
"-fvisibility=hidden",
+ "-Wall",
+ "-Werror",
+ "-Wno-unused-variable",
],
shared_libs: [
// ***** DO NOT ADD NEW DEPENDENCIES HERE *****
@@ -64,6 +68,16 @@
"liblog",
"libdl",
],
+ static_libs: [
+ "libarect",
+ ],
+ header_libs: [
+ "gl_headers",
+ "libsystem_headers",
+ "libhardware_headers",
+ "libnativebase_headers",
+ ],
+ export_header_lib_headers: ["gl_headers"],
// we need to access the private Bionic header <bionic_tls.h>
include_dirs: ["bionic/libc/private"],
@@ -77,6 +91,11 @@
defaults: ["gl_libs_defaults"],
cflags: [
"-DLOG_TAG=\"libEGL\"",
+ "-Wall",
+ "-Werror",
+ "-Wno-error=deprecated-register",
+ "-Wno-error=unknown-attributes",
+ "-Wno-unused-variable",
],
shared_libs: [
// ***** DO NOT ADD NEW DEPENDENCIES HERE *****
@@ -85,6 +104,11 @@
"libnativewindow",
"libbacktrace",
],
+ target: {
+ vendor: {
+ exclude_shared_libs: ["libgraphicsenv"],
+ },
+ },
}
cc_library_static {
@@ -98,6 +122,16 @@
},
}
+cc_library_static {
+ name: "libEGL_blobCache",
+ defaults: ["egl_libs_defaults"],
+ srcs: [
+ "EGL/BlobCache.cpp",
+ "EGL/FileBlobCache.cpp",
+ ],
+ export_include_dirs: ["EGL"],
+}
+
cc_library_shared {
name: "libEGL",
defaults: ["egl_libs_defaults"],
@@ -109,10 +143,19 @@
"EGL/egl.cpp",
"EGL/eglApi.cpp",
"EGL/Loader.cpp",
- "EGL/BlobCache.cpp",
],
- shared_libs: ["libvndksupport"],
- static_libs: ["libEGL_getProcAddress"],
+ shared_libs: [
+ "libvndksupport",
+ "android.hardware.configstore@1.0",
+ "android.hardware.configstore-utils",
+ "libhidlbase",
+ "libhidltransport",
+ "libutils",
+ ],
+ static_libs: [
+ "libEGL_getProcAddress",
+ "libEGL_blobCache",
+ ],
ldflags: ["-Wl,--exclude-libs=ALL"],
export_include_dirs: ["EGL/include"],
}
diff --git a/opengl/libs/EGL/BlobCache.cpp b/opengl/libs/EGL/BlobCache.cpp
index f1b30c7..b3752f5 100644
--- a/opengl/libs/EGL/BlobCache.cpp
+++ b/opengl/libs/EGL/BlobCache.cpp
@@ -18,6 +18,7 @@
#include "BlobCache.h"
+#include <errno.h>
#include <inttypes.h>
#include <cutils/properties.h>
@@ -36,9 +37,9 @@
static const uint32_t blobCacheDeviceVersion = 1;
BlobCache::BlobCache(size_t maxKeySize, size_t maxValueSize, size_t maxTotalSize):
+ mMaxTotalSize(maxTotalSize),
mMaxKeySize(maxKeySize),
mMaxValueSize(maxValueSize),
- mMaxTotalSize(maxTotalSize),
mTotalSize(0) {
int64_t now = std::chrono::steady_clock::now().time_since_epoch().count();
#ifdef _WIN32
diff --git a/opengl/libs/EGL/BlobCache.h b/opengl/libs/EGL/BlobCache.h
index a0a270a..1f5d535 100644
--- a/opengl/libs/EGL/BlobCache.h
+++ b/opengl/libs/EGL/BlobCache.h
@@ -97,6 +97,14 @@
//
int unflatten(void const* buffer, size_t size);
+protected:
+ // mMaxTotalSize is the maximum size that all cache entries can occupy. This
+ // includes space for both keys and values. When a call to BlobCache::set
+ // would otherwise cause this limit to be exceeded, either the key/value
+ // pair passed to BlobCache::set will not be cached or other cache entries
+ // will be evicted from the cache to make room for the new entry.
+ const size_t mMaxTotalSize;
+
private:
// Copying is disallowed.
BlobCache(const BlobCache&);
@@ -220,13 +228,6 @@
// simply not add the key/value pair to the cache.
const size_t mMaxValueSize;
- // mMaxTotalSize is the maximum size that all cache entries can occupy. This
- // includes space for both keys and values. When a call to BlobCache::set
- // would otherwise cause this limit to be exceeded, either the key/value
- // pair passed to BlobCache::set will not be cached or other cache entries
- // will be evicted from the cache to make room for the new entry.
- const size_t mMaxTotalSize;
-
// mTotalSize is the total combined size of all keys and values currently in
// the cache.
size_t mTotalSize;
diff --git a/opengl/libs/EGL/FileBlobCache.cpp b/opengl/libs/EGL/FileBlobCache.cpp
new file mode 100644
index 0000000..ff608a3
--- /dev/null
+++ b/opengl/libs/EGL/FileBlobCache.cpp
@@ -0,0 +1,185 @@
+/*
+ ** 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 "FileBlobCache.h"
+
+#include <inttypes.h>
+#include <log/log.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+
+
+// Cache file header
+static const char* cacheFileMagic = "EGL$";
+static const size_t cacheFileHeaderSize = 8;
+
+namespace android {
+
+static uint32_t crc32c(const uint8_t* buf, size_t len) {
+ const uint32_t polyBits = 0x82F63B78;
+ uint32_t r = 0;
+ for (size_t i = 0; i < len; i++) {
+ r ^= buf[i];
+ for (int j = 0; j < 8; j++) {
+ if (r & 1) {
+ r = (r >> 1) ^ polyBits;
+ } else {
+ r >>= 1;
+ }
+ }
+ }
+ return r;
+}
+
+FileBlobCache::FileBlobCache(size_t maxKeySize, size_t maxValueSize, size_t maxTotalSize,
+ const std::string& filename)
+ : BlobCache(maxKeySize, maxValueSize, maxTotalSize)
+ , mFilename(filename) {
+ if (mFilename.length() > 0) {
+ size_t headerSize = cacheFileHeaderSize;
+
+ int fd = open(mFilename.c_str(), O_RDONLY, 0);
+ if (fd == -1) {
+ if (errno != ENOENT) {
+ ALOGE("error opening cache file %s: %s (%d)", mFilename.c_str(),
+ strerror(errno), errno);
+ }
+ return;
+ }
+
+ struct stat statBuf;
+ if (fstat(fd, &statBuf) == -1) {
+ ALOGE("error stat'ing cache file: %s (%d)", strerror(errno), errno);
+ close(fd);
+ return;
+ }
+
+ // Sanity check the size before trying to mmap it.
+ size_t fileSize = statBuf.st_size;
+ if (fileSize > mMaxTotalSize * 2) {
+ ALOGE("cache file is too large: %#" PRIx64,
+ static_cast<off64_t>(statBuf.st_size));
+ close(fd);
+ return;
+ }
+
+ uint8_t* buf = reinterpret_cast<uint8_t*>(mmap(NULL, fileSize,
+ PROT_READ, MAP_PRIVATE, fd, 0));
+ if (buf == MAP_FAILED) {
+ ALOGE("error mmaping cache file: %s (%d)", strerror(errno),
+ errno);
+ close(fd);
+ return;
+ }
+
+ // Check the file magic and CRC
+ size_t cacheSize = fileSize - headerSize;
+ if (memcmp(buf, cacheFileMagic, 4) != 0) {
+ ALOGE("cache file has bad mojo");
+ close(fd);
+ return;
+ }
+ uint32_t* crc = reinterpret_cast<uint32_t*>(buf + 4);
+ if (crc32c(buf + headerSize, cacheSize) != *crc) {
+ ALOGE("cache file failed CRC check");
+ close(fd);
+ return;
+ }
+
+ int err = unflatten(buf + headerSize, cacheSize);
+ if (err < 0) {
+ ALOGE("error reading cache contents: %s (%d)", strerror(-err),
+ -err);
+ munmap(buf, fileSize);
+ close(fd);
+ return;
+ }
+
+ munmap(buf, fileSize);
+ close(fd);
+ }
+}
+
+void FileBlobCache::writeToFile() {
+ if (mFilename.length() > 0) {
+ size_t cacheSize = getFlattenedSize();
+ size_t headerSize = cacheFileHeaderSize;
+ const char* fname = mFilename.c_str();
+
+ // Try to create the file with no permissions so we can write it
+ // without anyone trying to read it.
+ int fd = open(fname, O_CREAT | O_EXCL | O_RDWR, 0);
+ if (fd == -1) {
+ if (errno == EEXIST) {
+ // The file exists, delete it and try again.
+ if (unlink(fname) == -1) {
+ // No point in retrying if the unlink failed.
+ ALOGE("error unlinking cache file %s: %s (%d)", fname,
+ strerror(errno), errno);
+ return;
+ }
+ // Retry now that we've unlinked the file.
+ fd = open(fname, O_CREAT | O_EXCL | O_RDWR, 0);
+ }
+ if (fd == -1) {
+ ALOGE("error creating cache file %s: %s (%d)", fname,
+ strerror(errno), errno);
+ return;
+ }
+ }
+
+ size_t fileSize = headerSize + cacheSize;
+
+ uint8_t* buf = new uint8_t [fileSize];
+ if (!buf) {
+ ALOGE("error allocating buffer for cache contents: %s (%d)",
+ strerror(errno), errno);
+ close(fd);
+ unlink(fname);
+ return;
+ }
+
+ int err = flatten(buf + headerSize, cacheSize);
+ if (err < 0) {
+ ALOGE("error writing cache contents: %s (%d)", strerror(-err),
+ -err);
+ delete [] buf;
+ close(fd);
+ unlink(fname);
+ return;
+ }
+
+ // Write the file magic and CRC
+ memcpy(buf, cacheFileMagic, 4);
+ uint32_t* crc = reinterpret_cast<uint32_t*>(buf + 4);
+ *crc = crc32c(buf + headerSize, cacheSize);
+
+ if (write(fd, buf, fileSize) == -1) {
+ ALOGE("error writing cache file: %s (%d)", strerror(errno),
+ errno);
+ delete [] buf;
+ close(fd);
+ unlink(fname);
+ return;
+ }
+
+ delete [] buf;
+ fchmod(fd, S_IRUSR);
+ close(fd);
+ }
+}
+
+}
\ No newline at end of file
diff --git a/opengl/libs/EGL/FileBlobCache.h b/opengl/libs/EGL/FileBlobCache.h
new file mode 100644
index 0000000..393703f
--- /dev/null
+++ b/opengl/libs/EGL/FileBlobCache.h
@@ -0,0 +1,43 @@
+/*
+ ** 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.
+ */
+
+#ifndef ANDROID_FILE_BLOB_CACHE_H
+#define ANDROID_FILE_BLOB_CACHE_H
+
+#include "BlobCache.h"
+#include <string>
+
+namespace android {
+
+class FileBlobCache : public BlobCache {
+public:
+ // FileBlobCache attempts to load the saved cache contents from disk into
+ // BlobCache.
+ FileBlobCache(size_t maxKeySize, size_t maxValueSize, size_t maxTotalSize,
+ const std::string& filename);
+
+ // writeToFile attempts to save the current contents of BlobCache to
+ // disk.
+ void writeToFile();
+
+private:
+ // mFilename is the name of the file for storing cache contents.
+ std::string mFilename;
+};
+
+} // namespace android
+
+#endif // ANDROID_BLOB_CACHE_H
diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp
index 6e5c510..399affc 100644
--- a/opengl/libs/EGL/Loader.cpp
+++ b/opengl/libs/EGL/Loader.cpp
@@ -28,7 +28,9 @@
#include <cutils/properties.h>
#include <log/log.h>
+#ifndef __ANDROID_VNDK__
#include <graphicsenv/GraphicsEnv.h>
+#endif
#include <vndksupport/linker.h>
#include "egl_trace.h"
@@ -325,17 +327,17 @@
switch (emulationStatus) {
case 0:
#if defined(__LP64__)
- result = "/system/lib64/egl/libGLES_android.so";
+ result = "/vendor/lib64/egl/libGLES_android.so";
#else
- result = "/system/lib/egl/libGLES_android.so";
+ result = "/vendor/lib/egl/libGLES_android.so";
#endif
return result;
case 1:
// Use host-side OpenGL through the "emulation" library
#if defined(__LP64__)
- result = std::string("/system/lib64/egl/lib") + kind + "_emulation.so";
+ result = std::string("/vendor/lib64/egl/lib") + kind + "_emulation.so";
#else
- result = std::string("/system/lib/egl/lib") + kind + "_emulation.so";
+ result = std::string("/vendor/lib/egl/lib") + kind + "_emulation.so";
#endif
return result;
default:
@@ -387,7 +389,7 @@
static bool find(std::string& result,
const std::string& pattern, const char* const search, bool exact) {
if (exact) {
- std::string absolutePath = std::string(search) + "/" + pattern;
+ std::string absolutePath = std::string(search) + "/" + pattern + ".so";
if (!access(absolutePath.c_str(), R_OK)) {
result = absolutePath;
return true;
@@ -477,10 +479,12 @@
ATRACE_CALL();
void* dso = nullptr;
+#ifndef __ANDROID_VNDK__
android_namespace_t* ns = android_getDriverNamespace();
if (ns) {
dso = load_updated_driver(kind, ns);
}
+#endif
if (!dso) {
dso = load_system_driver(kind);
if (!dso)
diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp
index 6bff38a..94dfe6a 100644
--- a/opengl/libs/EGL/eglApi.cpp
+++ b/opengl/libs/EGL/eglApi.cpp
@@ -87,9 +87,6 @@
"EGL_ANDROID_get_native_client_buffer "
"EGL_ANDROID_front_buffer_auto_refresh "
"EGL_ANDROID_get_frame_timestamps "
- "EGL_EXT_gl_colorspace_scrgb_linear "
- "EGL_EXT_gl_colorspace_display_p3_linear "
- "EGL_EXT_gl_colorspace_display_p3 "
;
char const * const gExtensionString =
@@ -457,8 +454,8 @@
// EGL_GL_COLORSPACE_SRGB_KHR, or turn sRGB formats into corresponding linear
// formats when colorspace is EGL_GL_COLORSPACE_LINEAR_KHR. In any cases where
// the modification isn't possible, the original dataSpace is returned.
-static android_dataspace modifyBufferDataspace( android_dataspace dataSpace,
- EGLint colorspace) {
+static android_dataspace modifyBufferDataspace(android_dataspace dataSpace,
+ EGLint colorspace) {
if (colorspace == EGL_GL_COLORSPACE_LINEAR_KHR) {
return HAL_DATASPACE_SRGB_LINEAR;
} else if (colorspace == EGL_GL_COLORSPACE_SRGB_KHR) {
@@ -467,31 +464,95 @@
return HAL_DATASPACE_DISPLAY_P3;
} else if (colorspace == EGL_GL_COLORSPACE_DISPLAY_P3_LINEAR_EXT) {
return HAL_DATASPACE_DISPLAY_P3_LINEAR;
+ } else if (colorspace == EGL_GL_COLORSPACE_SCRGB_EXT) {
+ return HAL_DATASPACE_V0_SCRGB;
} else if (colorspace == EGL_GL_COLORSPACE_SCRGB_LINEAR_EXT) {
return HAL_DATASPACE_V0_SCRGB_LINEAR;
}
return dataSpace;
}
-static EGLBoolean getColorSpaceAttribute(egl_display_ptr dp, const EGLint* attrib_list,
- EGLint& colorSpace, android_dataspace& dataSpace) {
+// Return true if we stripped any EGL_GL_COLORSPACE_KHR attributes.
+static EGLBoolean stripColorSpaceAttribute(egl_display_ptr dp, const EGLint* attrib_list,
+ EGLint format,
+ std::vector<EGLint>& stripped_attrib_list) {
+ std::vector<EGLint> allowedColorSpaces;
+ switch (format) {
+ case HAL_PIXEL_FORMAT_RGBA_8888:
+ case HAL_PIXEL_FORMAT_RGB_565:
+ // driver okay with linear & sRGB for 8888, but can't handle
+ // Display-P3 or other spaces.
+ allowedColorSpaces.push_back(EGL_GL_COLORSPACE_SRGB_KHR);
+ allowedColorSpaces.push_back(EGL_GL_COLORSPACE_LINEAR_KHR);
+ break;
+
+ case HAL_PIXEL_FORMAT_RGBA_FP16:
+ case HAL_PIXEL_FORMAT_RGBA_1010102:
+ default:
+ // driver does not want to see colorspace attributes for 1010102 or fp16.
+ // Future: if driver supports XXXX extension, we can pass down that colorspace
+ break;
+ }
+
+ bool stripped = false;
+ if (attrib_list && dp->haveExtension("EGL_KHR_gl_colorspace")) {
+ for (const EGLint* attr = attrib_list; attr[0] != EGL_NONE; attr += 2) {
+ if (attr[0] == EGL_GL_COLORSPACE_KHR) {
+ EGLint colorSpace = attr[1];
+ bool found = false;
+ // Verify that color space is allowed
+ for (auto it : allowedColorSpaces) {
+ if (colorSpace == it) {
+ found = true;
+ }
+ }
+ if (!found) {
+ stripped = true;
+ } else {
+ stripped_attrib_list.push_back(attr[0]);
+ stripped_attrib_list.push_back(attr[1]);
+ }
+ } else {
+ stripped_attrib_list.push_back(attr[0]);
+ stripped_attrib_list.push_back(attr[1]);
+ }
+ }
+ }
+ if (stripped) {
+ stripped_attrib_list.push_back(EGL_NONE);
+ stripped_attrib_list.push_back(EGL_NONE);
+ }
+ return stripped;
+}
+
+static EGLBoolean getColorSpaceAttribute(egl_display_ptr dp, NativeWindowType window,
+ const EGLint* attrib_list, EGLint& colorSpace,
+ android_dataspace& dataSpace) {
colorSpace = EGL_GL_COLORSPACE_LINEAR_KHR;
dataSpace = HAL_DATASPACE_UNKNOWN;
+
if (attrib_list && dp->haveExtension("EGL_KHR_gl_colorspace")) {
for (const EGLint* attr = attrib_list; *attr != EGL_NONE; attr += 2) {
if (*attr == EGL_GL_COLORSPACE_KHR) {
colorSpace = attr[1];
bool found = false;
+ bool verify = true;
// Verify that color space is allowed
if (colorSpace == EGL_GL_COLORSPACE_SRGB_KHR ||
colorSpace == EGL_GL_COLORSPACE_LINEAR_KHR) {
+ // SRGB and LINEAR are always supported when EGL_KHR_gl_colorspace
+ // is available, so no need to verify.
found = true;
+ verify = false;
} else if (colorSpace == EGL_EXT_gl_colorspace_bt2020_linear &&
dp->haveExtension("EGL_EXT_gl_colorspace_bt2020_linear")) {
found = true;
} else if (colorSpace == EGL_EXT_gl_colorspace_bt2020_pq &&
dp->haveExtension("EGL_EXT_gl_colorspace_bt2020_pq")) {
found = true;
+ } else if (colorSpace == EGL_GL_COLORSPACE_SCRGB_EXT &&
+ dp->haveExtension("EGL_EXT_gl_colorspace_scrgb")) {
+ found = true;
} else if (colorSpace == EGL_GL_COLORSPACE_SCRGB_LINEAR_EXT &&
dp->haveExtension("EGL_EXT_gl_colorspace_scrgb_linear")) {
found = true;
@@ -505,6 +566,31 @@
if (!found) {
return false;
}
+ if (verify && window) {
+ bool wide_color_support = true;
+ // Ordinarily we'd put a call to native_window_get_wide_color_support
+ // at the beginning of the function so that we'll have the
+ // result when needed elsewhere in the function.
+ // However, because eglCreateWindowSurface is called by SurfaceFlinger and
+ // SurfaceFlinger is required to answer the call below we would
+ // end up in a deadlock situation. By moving the call to only happen
+ // if the application has specifically asked for wide-color we avoid
+ // the deadlock with SurfaceFlinger since it will not ask for a
+ // wide-color surface.
+ int err = native_window_get_wide_color_support(window, &wide_color_support);
+
+ if (err) {
+ ALOGE("getColorSpaceAttribute: invalid window (win=%p) "
+ "failed (%#x) (already connected to another API?)",
+ window, err);
+ return false;
+ }
+ if (!wide_color_support) {
+ // Application has asked for a wide-color colorspace but
+ // wide-color support isn't available on the display the window is on.
+ return false;
+ }
+ }
// Only change the dataSpace from default if the application
// has explicitly set the color space with a EGL_GL_COLORSPACE_KHR attribute.
dataSpace = modifyBufferDataspace(dataSpace, colorSpace);
@@ -514,6 +600,70 @@
return true;
}
+static EGLBoolean getColorSpaceAttribute(egl_display_ptr dp, const EGLint* attrib_list,
+ EGLint& colorSpace, android_dataspace& dataSpace) {
+ return getColorSpaceAttribute(dp, NULL, attrib_list, colorSpace, dataSpace);
+}
+
+void getNativePixelFormat(EGLDisplay dpy, egl_connection_t* cnx, EGLConfig config, EGLint& format) {
+ // Set the native window's buffers format to match what this config requests.
+ // Whether to use sRGB gamma is not part of the EGLconfig, but is part
+ // of our native format. So if sRGB gamma is requested, we have to
+ // modify the EGLconfig's format before setting the native window's
+ // format.
+
+ EGLint componentType = EGL_COLOR_COMPONENT_TYPE_FIXED_EXT;
+ cnx->egl.eglGetConfigAttrib(dpy, config, EGL_COLOR_COMPONENT_TYPE_EXT, &componentType);
+
+ EGLint a = 0;
+ EGLint r, g, b;
+ r = g = b = 0;
+ cnx->egl.eglGetConfigAttrib(dpy, config, EGL_RED_SIZE, &r);
+ cnx->egl.eglGetConfigAttrib(dpy, config, EGL_GREEN_SIZE, &g);
+ cnx->egl.eglGetConfigAttrib(dpy, config, EGL_BLUE_SIZE, &b);
+ cnx->egl.eglGetConfigAttrib(dpy, config, EGL_ALPHA_SIZE, &a);
+ EGLint colorDepth = r + g + b;
+
+ // Today, the driver only understands sRGB and linear on 888X
+ // formats. Strip other colorspaces from the attribute list and
+ // only use them to set the dataspace via
+ // native_window_set_buffers_dataspace
+ // if pixel format is RGBX 8888
+ // TBD: Can test for future extensions that indicate that driver
+ // handles requested color space and we can let it through.
+ // allow SRGB and LINEAR. All others need to be stripped.
+ // else if 565, 4444
+ // TBD: Can we assume these are supported if 8888 is?
+ // else if FP16 or 1010102
+ // strip colorspace from attribs.
+ // endif
+ if (a == 0) {
+ if (colorDepth <= 16) {
+ format = HAL_PIXEL_FORMAT_RGB_565;
+ } else {
+ if (componentType == EGL_COLOR_COMPONENT_TYPE_FIXED_EXT) {
+ if (colorDepth > 24) {
+ format = HAL_PIXEL_FORMAT_RGBA_1010102;
+ } else {
+ format = HAL_PIXEL_FORMAT_RGBX_8888;
+ }
+ } else {
+ format = HAL_PIXEL_FORMAT_RGBA_FP16;
+ }
+ }
+ } else {
+ if (componentType == EGL_COLOR_COMPONENT_TYPE_FIXED_EXT) {
+ if (colorDepth > 24) {
+ format = HAL_PIXEL_FORMAT_RGBA_1010102;
+ } else {
+ format = HAL_PIXEL_FORMAT_RGBA_8888;
+ }
+ } else {
+ format = HAL_PIXEL_FORMAT_RGBA_FP16;
+ }
+ }
+}
+
EGLSurface eglCreateWindowSurface( EGLDisplay dpy, EGLConfig config,
NativeWindowType window,
const EGLint *attrib_list)
@@ -543,60 +693,24 @@
return setError(EGL_BAD_ALLOC, EGL_NO_SURFACE);
}
- // Set the native window's buffers format to match what this config requests.
- // Whether to use sRGB gamma is not part of the EGLconfig, but is part
- // of our native format. So if sRGB gamma is requested, we have to
- // modify the EGLconfig's format before setting the native window's
- // format.
-
- EGLint componentType = EGL_COLOR_COMPONENT_TYPE_FIXED_EXT;
- cnx->egl.eglGetConfigAttrib(iDpy, config, EGL_COLOR_COMPONENT_TYPE_EXT,
- &componentType);
-
EGLint format;
+ getNativePixelFormat(iDpy, cnx, config, format);
+
+ // now select correct colorspace and dataspace based on user's attribute list
EGLint colorSpace;
android_dataspace dataSpace;
- EGLint a = 0;
- EGLint r, g, b;
- r = g = b = 0;
- cnx->egl.eglGetConfigAttrib(iDpy, config, EGL_RED_SIZE, &r);
- cnx->egl.eglGetConfigAttrib(iDpy, config, EGL_GREEN_SIZE, &g);
- cnx->egl.eglGetConfigAttrib(iDpy, config, EGL_BLUE_SIZE, &b);
- cnx->egl.eglGetConfigAttrib(iDpy, config, EGL_ALPHA_SIZE, &a);
- EGLint colorDepth = r + g + b;
-
- if (a == 0) {
- if (colorDepth <= 16) {
- format = HAL_PIXEL_FORMAT_RGB_565;
- } else {
- if (componentType == EGL_COLOR_COMPONENT_TYPE_FIXED_EXT) {
- if (colorDepth > 24) {
- format = HAL_PIXEL_FORMAT_RGBA_1010102;
- } else {
- format = HAL_PIXEL_FORMAT_RGBX_8888;
- }
- } else {
- format = HAL_PIXEL_FORMAT_RGBA_FP16;
- }
- }
- } else {
- if (componentType == EGL_COLOR_COMPONENT_TYPE_FIXED_EXT) {
- if (colorDepth > 24) {
- format = HAL_PIXEL_FORMAT_RGBA_1010102;
- } else {
- format = HAL_PIXEL_FORMAT_RGBA_8888;
- }
- } else {
- format = HAL_PIXEL_FORMAT_RGBA_FP16;
- }
- }
-
- // now select a corresponding sRGB format if needed
- if (!getColorSpaceAttribute(dp, attrib_list, colorSpace, dataSpace)) {
+ if (!getColorSpaceAttribute(dp, window, attrib_list, colorSpace, dataSpace)) {
ALOGE("error invalid colorspace: %d", colorSpace);
return setError(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
}
+ std::vector<EGLint> strippedAttribList;
+ if (stripColorSpaceAttribute(dp, attrib_list, format, strippedAttribList)) {
+ // Had to modify the attribute list due to use of color space.
+ // Use modified list from here on.
+ attrib_list = strippedAttribList.data();
+ }
+
if (format != 0) {
int err = native_window_set_buffers_format(window, format);
if (err != 0) {
@@ -671,15 +785,29 @@
egl_connection_t* cnx = NULL;
egl_display_ptr dp = validate_display_connection(dpy, cnx);
- EGLint colorSpace;
- android_dataspace dataSpace;
if (dp) {
- // now select a corresponding sRGB format if needed
+ EGLDisplay iDpy = dp->disp.dpy;
+ EGLint format;
+ getNativePixelFormat(iDpy, cnx, config, format);
+
+ // now select correct colorspace and dataspace based on user's attribute list
+ EGLint colorSpace;
+ android_dataspace dataSpace;
if (!getColorSpaceAttribute(dp, attrib_list, colorSpace, dataSpace)) {
ALOGE("error invalid colorspace: %d", colorSpace);
return setError(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
}
+ // Pbuffers are not displayed so we don't need to store the
+ // colorspace. We do need to filter out color spaces the
+ // driver doesn't know how to process.
+ std::vector<EGLint> strippedAttribList;
+ if (stripColorSpaceAttribute(dp, attrib_list, format, strippedAttribList)) {
+ // Had to modify the attribute list due to use of color space.
+ // Use modified list from here on.
+ attrib_list = strippedAttribList.data();
+ }
+
EGLSurface surface = cnx->egl.eglCreatePbufferSurface(
dp->disp.dpy, config, attrib_list);
if (surface != EGL_NO_SURFACE) {
@@ -897,19 +1025,15 @@
egl_tls_t::setContext(EGL_NO_CONTEXT);
}
} else {
- // Force return to current context for drivers that cannot handle errors
- EGLBoolean restore_result = EGL_FALSE;
- // get a reference to the old current objects
- ContextRef _c2(dp.get(), cur_c);
- SurfaceRef _d2(dp.get(), cur_c->draw);
- SurfaceRef _r2(dp.get(), cur_c->read);
+ if (cur_c != NULL) {
+ // Force return to current context for drivers that cannot handle errors
+ EGLBoolean restore_result = EGL_FALSE;
+ // get a reference to the old current objects
+ ContextRef _c2(dp.get(), cur_c);
+ SurfaceRef _d2(dp.get(), cur_c->draw);
+ SurfaceRef _r2(dp.get(), cur_c->read);
- if (cur_c == NULL) {
- restore_result = dp->makeCurrent(c, cur_c,
- EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT,
- EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
- } else {
c = cur_c;
impl_ctx = c->context;
impl_draw = EGL_NO_SURFACE;
@@ -925,13 +1049,13 @@
restore_result = dp->makeCurrent(c, cur_c,
cur_c->draw, cur_c->read, cur_c->context,
impl_draw, impl_read, impl_ctx);
- }
- if (restore_result == EGL_TRUE) {
- _c2.acquire();
- _r2.acquire();
- _d2.acquire();
- } else {
- ALOGE("Could not restore original EGL context");
+ if (restore_result == EGL_TRUE) {
+ _c2.acquire();
+ _r2.acquire();
+ _d2.acquire();
+ } else {
+ ALOGE("Could not restore original EGL context");
+ }
}
// this will ALOGE the error
egl_connection_t* const cnx = &gEGLImpl;
@@ -1323,7 +1447,7 @@
return setError(EGL_BAD_PARAMETER, (const char *)0);
}
-EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name)
+extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name)
{
clearError();
@@ -1967,8 +2091,15 @@
EGLClientBuffer eglGetNativeClientBufferANDROID(const AHardwareBuffer *buffer) {
clearError();
+ // AHardwareBuffer_to_ANativeWindowBuffer is a platform-only symbol and thus
+ // this function cannot be implemented when this libEGL is built for
+ // vendors.
+#ifndef __ANDROID_VNDK__
if (!buffer) return setError(EGL_BAD_PARAMETER, (EGLClientBuffer)0);
return const_cast<ANativeWindowBuffer *>(AHardwareBuffer_to_ANativeWindowBuffer(buffer));
+#else
+ return setError(EGL_BAD_PARAMETER, (EGLClientBuffer)0);
+#endif
}
// ----------------------------------------------------------------------------
diff --git a/opengl/libs/EGL/egl_cache.cpp b/opengl/libs/EGL/egl_cache.cpp
index dc1a4af..ec548f3 100644
--- a/opengl/libs/EGL/egl_cache.cpp
+++ b/opengl/libs/EGL/egl_cache.cpp
@@ -20,12 +20,9 @@
#include "egl_display.h"
-
#include <private/EGL/cache.h>
-#include <inttypes.h>
-#include <sys/mman.h>
-#include <sys/stat.h>
+#include <unistd.h>
#include <thread>
@@ -36,10 +33,6 @@
static const size_t maxValueSize = 64 * 1024;
static const size_t maxTotalSize = 2 * 1024 * 1024;
-// Cache file header
-static const char* cacheFileMagic = "EGL$";
-static const size_t cacheFileHeaderSize = 8;
-
// The time in seconds to wait before saving newly inserted cache entries.
static const unsigned int deferredSaveDelay = 4;
@@ -123,7 +116,9 @@
void egl_cache_t::terminate() {
std::lock_guard<std::mutex> lock(mMutex);
- saveBlobCacheLocked();
+ if (mBlobCache) {
+ mBlobCache->writeToFile();
+ }
mBlobCache = NULL;
}
@@ -145,8 +140,8 @@
std::thread deferredSaveThread([this]() {
sleep(deferredSaveDelay);
std::lock_guard<std::mutex> lock(mMutex);
- if (mInitialized) {
- saveBlobCacheLocked();
+ if (mInitialized && mBlobCache) {
+ mBlobCache->writeToFile();
}
mSavePending = false;
});
@@ -178,163 +173,11 @@
BlobCache* egl_cache_t::getBlobCacheLocked() {
if (mBlobCache == nullptr) {
- mBlobCache.reset(new BlobCache(maxKeySize, maxValueSize, maxTotalSize));
- loadBlobCacheLocked();
+ mBlobCache.reset(new FileBlobCache(maxKeySize, maxValueSize, maxTotalSize, mFilename));
}
return mBlobCache.get();
}
-static uint32_t crc32c(const uint8_t* buf, size_t len) {
- const uint32_t polyBits = 0x82F63B78;
- uint32_t r = 0;
- for (size_t i = 0; i < len; i++) {
- r ^= buf[i];
- for (int j = 0; j < 8; j++) {
- if (r & 1) {
- r = (r >> 1) ^ polyBits;
- } else {
- r >>= 1;
- }
- }
- }
- return r;
-}
-
-void egl_cache_t::saveBlobCacheLocked() {
- if (mFilename.length() > 0 && mBlobCache != NULL) {
- size_t cacheSize = mBlobCache->getFlattenedSize();
- size_t headerSize = cacheFileHeaderSize;
- const char* fname = mFilename.c_str();
-
- // Try to create the file with no permissions so we can write it
- // without anyone trying to read it.
- int fd = open(fname, O_CREAT | O_EXCL | O_RDWR, 0);
- if (fd == -1) {
- if (errno == EEXIST) {
- // The file exists, delete it and try again.
- if (unlink(fname) == -1) {
- // No point in retrying if the unlink failed.
- ALOGE("error unlinking cache file %s: %s (%d)", fname,
- strerror(errno), errno);
- return;
- }
- // Retry now that we've unlinked the file.
- fd = open(fname, O_CREAT | O_EXCL | O_RDWR, 0);
- }
- if (fd == -1) {
- ALOGE("error creating cache file %s: %s (%d)", fname,
- strerror(errno), errno);
- return;
- }
- }
-
- size_t fileSize = headerSize + cacheSize;
-
- uint8_t* buf = new uint8_t [fileSize];
- if (!buf) {
- ALOGE("error allocating buffer for cache contents: %s (%d)",
- strerror(errno), errno);
- close(fd);
- unlink(fname);
- return;
- }
-
- int err = mBlobCache->flatten(buf + headerSize, cacheSize);
- if (err < 0) {
- ALOGE("error writing cache contents: %s (%d)", strerror(-err),
- -err);
- delete [] buf;
- close(fd);
- unlink(fname);
- return;
- }
-
- // Write the file magic and CRC
- memcpy(buf, cacheFileMagic, 4);
- uint32_t* crc = reinterpret_cast<uint32_t*>(buf + 4);
- *crc = crc32c(buf + headerSize, cacheSize);
-
- if (write(fd, buf, fileSize) == -1) {
- ALOGE("error writing cache file: %s (%d)", strerror(errno),
- errno);
- delete [] buf;
- close(fd);
- unlink(fname);
- return;
- }
-
- delete [] buf;
- fchmod(fd, S_IRUSR);
- close(fd);
- }
-}
-
-void egl_cache_t::loadBlobCacheLocked() {
- if (mFilename.length() > 0) {
- size_t headerSize = cacheFileHeaderSize;
-
- int fd = open(mFilename.c_str(), O_RDONLY, 0);
- if (fd == -1) {
- if (errno != ENOENT) {
- ALOGE("error opening cache file %s: %s (%d)", mFilename.c_str(),
- strerror(errno), errno);
- }
- return;
- }
-
- struct stat statBuf;
- if (fstat(fd, &statBuf) == -1) {
- ALOGE("error stat'ing cache file: %s (%d)", strerror(errno), errno);
- close(fd);
- return;
- }
-
- // Sanity check the size before trying to mmap it.
- size_t fileSize = statBuf.st_size;
- if (fileSize > maxTotalSize * 2) {
- ALOGE("cache file is too large: %#" PRIx64,
- static_cast<off64_t>(statBuf.st_size));
- close(fd);
- return;
- }
-
- uint8_t* buf = reinterpret_cast<uint8_t*>(mmap(NULL, fileSize,
- PROT_READ, MAP_PRIVATE, fd, 0));
- if (buf == MAP_FAILED) {
- ALOGE("error mmaping cache file: %s (%d)", strerror(errno),
- errno);
- close(fd);
- return;
- }
-
- // Check the file magic and CRC
- size_t cacheSize = fileSize - headerSize;
- if (memcmp(buf, cacheFileMagic, 4) != 0) {
- ALOGE("cache file has bad mojo");
- close(fd);
- return;
- }
- uint32_t* crc = reinterpret_cast<uint32_t*>(buf + 4);
- if (crc32c(buf + headerSize, cacheSize) != *crc) {
- ALOGE("cache file failed CRC check");
- close(fd);
- return;
- }
-
- int err = mBlobCache->unflatten(buf + headerSize, cacheSize);
- if (err < 0) {
- ALOGE("error reading cache contents: %s (%d)", strerror(-err),
- -err);
- munmap(buf, fileSize);
- close(fd);
- return;
- }
-
- munmap(buf, fileSize);
- close(fd);
- }
-}
-
// ----------------------------------------------------------------------------
}; // namespace android
// ----------------------------------------------------------------------------
diff --git a/opengl/libs/EGL/egl_cache.h b/opengl/libs/EGL/egl_cache.h
index 56360f0..7382b91 100644
--- a/opengl/libs/EGL/egl_cache.h
+++ b/opengl/libs/EGL/egl_cache.h
@@ -20,7 +20,7 @@
#include <EGL/egl.h>
#include <EGL/eglext.h>
-#include "BlobCache.h"
+#include "FileBlobCache.h"
#include <memory>
#include <mutex>
@@ -82,14 +82,6 @@
// possible.
BlobCache* getBlobCacheLocked();
- // saveBlobCache attempts to save the current contents of mBlobCache to
- // disk.
- void saveBlobCacheLocked();
-
- // loadBlobCache attempts to load the saved cache contents from disk into
- // mBlobCache.
- void loadBlobCacheLocked();
-
// mInitialized indicates whether the egl_cache_t is in the initialized
// state. It is initialized to false at construction time, and gets set to
// true when initialize is called. It is set back to false when terminate
@@ -101,7 +93,7 @@
// mBlobCache is the cache in which the key/value blob pairs are stored. It
// is initially NULL, and will be initialized by getBlobCacheLocked the
// first time it's needed.
- std::unique_ptr<BlobCache> mBlobCache;
+ std::unique_ptr<FileBlobCache> mBlobCache;
// mFilename is the name of the file for storing cache contents in between
// program invocations. It is initialized to an empty string at
diff --git a/opengl/libs/EGL/egl_display.cpp b/opengl/libs/EGL/egl_display.cpp
index b696920..4e5833a 100644
--- a/opengl/libs/EGL/egl_display.cpp
+++ b/opengl/libs/EGL/egl_display.cpp
@@ -30,6 +30,12 @@
#include "Loader.h"
#include <cutils/properties.h>
+#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
+#include <configstore/Utils.h>
+
+using namespace android::hardware::configstore;
+using namespace android::hardware::configstore::V1_0;
+
// ----------------------------------------------------------------------------
namespace android {
// ----------------------------------------------------------------------------
@@ -192,6 +198,18 @@
mClientApiString = sClientApiString;
mExtensionString = gBuiltinExtensionString;
+
+ bool wideColorBoardConfig =
+ getBool<ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::hasWideColorDisplay>(
+ false);
+
+ // Add wide-color extensions if device can support wide-color
+ if (wideColorBoardConfig) {
+ mExtensionString.append(
+ "EGL_EXT_gl_colorspace_scrgb EGL_EXT_gl_colorspace_scrgb_linear "
+ "EGL_EXT_gl_colorspace_display_p3_linear EGL_EXT_gl_colorspace_display_p3 ");
+ }
+
char const* start = gExtensionString;
do {
// length of the extension name
diff --git a/opengl/libs/EGL/egl_object.cpp b/opengl/libs/EGL/egl_object.cpp
index 837cfa9..72b4823 100644
--- a/opengl/libs/EGL/egl_object.cpp
+++ b/opengl/libs/EGL/egl_object.cpp
@@ -116,17 +116,23 @@
if (gl_extensions.empty()) {
// call the implementation's glGetString(GL_EXTENSIONS)
const char* exts = (const char *)gEGLImpl.hooks[version]->gl.glGetString(GL_EXTENSIONS);
- gl_extensions = exts;
- if (gl_extensions.find("GL_EXT_debug_marker") == std::string::npos) {
- gl_extensions.insert(0, "GL_EXT_debug_marker ");
- }
- // tokenize the supported extensions for the glGetStringi() wrapper
- std::stringstream ss;
- std::string str;
- ss << gl_extensions;
- while (ss >> str) {
- tokenized_gl_extensions.push_back(str);
+ // If this context is sharing with another context, and the other context was reset
+ // e.g. due to robustness failure, this context might also be reset and glGetString can
+ // return NULL.
+ if (exts) {
+ gl_extensions = exts;
+ if (gl_extensions.find("GL_EXT_debug_marker") == std::string::npos) {
+ gl_extensions.insert(0, "GL_EXT_debug_marker ");
+ }
+
+ // tokenize the supported extensions for the glGetStringi() wrapper
+ std::stringstream ss;
+ std::string str;
+ ss << gl_extensions;
+ while (ss >> str) {
+ tokenized_gl_extensions.push_back(str);
+ }
}
}
}
diff --git a/opengl/libs/libEGL.map.txt b/opengl/libs/libEGL.map.txt
index 89269a0..fa26e33 100644
--- a/opengl/libs/libEGL.map.txt
+++ b/opengl/libs/libEGL.map.txt
@@ -21,6 +21,7 @@
eglDestroyStreamKHR; # introduced=23
eglDestroySurface;
eglDestroySyncKHR; # introduced-arm=18 introduced-arm64=21 introduced-mips=18 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21
+ eglDupNativeFenceFDANDROID; # vndk
eglGetConfigAttrib;
eglGetConfigs;
eglGetCurrentContext;
@@ -44,6 +45,7 @@
eglQueryStreamTimeKHR; # introduced=23
eglQueryStreamu64KHR; # introduced=23
eglQueryString;
+ eglQueryStringImplementationANDROID; # vndk
eglQuerySurface;
eglReleaseTexImage;
eglReleaseThread;
diff --git a/opengl/specs/EGL_ANDROID_get_native_client_buffer.txt b/opengl/specs/EGL_ANDROID_get_native_client_buffer.txt
index 772b21a..285bba4 100644
--- a/opengl/specs/EGL_ANDROID_get_native_client_buffer.txt
+++ b/opengl/specs/EGL_ANDROID_get_native_client_buffer.txt
@@ -16,15 +16,15 @@
Status
- Draft
+ Complete
Version
- Version 1.0, January 27, 2017
+ Version 3, October 11, 2017
Number
- EGL Extension #XXX
+ EGL Extension #123
Dependencies
@@ -43,11 +43,11 @@
New Types
-struct AHardwareBuffer
+ struct AHardwareBuffer
New Procedures and Functions
-EGLClientBuffer eglGetNativeClientBufferANDROID(const AHardwareBuffer *buffer)
+ EGLClientBuffer eglGetNativeClientBufferANDROID(const struct AHardwareBuffer *buffer)
New Tokens
@@ -62,7 +62,7 @@
"The command
EGLClientBuffer eglGetNativeClientBufferANDROID(
- AHardwareBuffer *buffer)
+ const struct AHardwareBuffer *buffer)
may be used to create an EGLClientBuffer from an AHardwareBuffer object.
EGL implementations must guarantee that the lifetime of the returned
@@ -92,6 +92,9 @@
Revision History
+#3 (Jesse Hall, October 11, 2017)
+ - Assigned extension number, fixed minor issues for publication
+
#2 (Craig Donner, February 17, 2017)
- Fix typographical errors.
diff --git a/opengl/tests/Android.bp b/opengl/tests/Android.bp
index bf7aeb1..639f351 100644
--- a/opengl/tests/Android.bp
+++ b/opengl/tests/Android.bp
@@ -1,4 +1,19 @@
+
subdirs = [
+ "angeles",
+ "configdump",
+ "EGLTest",
+ "fillrate",
+ "filter",
+ "finish",
+ "gl2_basic",
+ "gl2_copyTexImage",
+ "gl2_yuvtex",
+ "gl_basic",
+ "gl_perf",
+ "gl_yuvtex", // just renders magenta frame, broken?
+ "gralloc",
"hwc",
"lib",
]
+
diff --git a/opengl/tests/Android.mk b/opengl/tests/Android.mk
index 92d223c..134854a 100644
--- a/opengl/tests/Android.mk
+++ b/opengl/tests/Android.mk
@@ -1,19 +1,4 @@
dirs := \
- angeles \
- configdump \
- EGLTest \
- fillrate \
- filter \
- finish \
- gl2_basic \
- gl2_copyTexImage \
- gl2_yuvtex \
- gl_basic \
- gl_perf \
- gl_yuvtex \
- gralloc \
- include \
- lib \
linetex \
swapinterval \
textures \
diff --git a/opengl/tests/EGLTest/Android.bp b/opengl/tests/EGLTest/Android.bp
new file mode 100644
index 0000000..d85af81
--- /dev/null
+++ b/opengl/tests/EGLTest/Android.bp
@@ -0,0 +1,31 @@
+
+cc_test {
+
+ name: "EGL_test",
+
+ srcs: [
+ "egl_cache_test.cpp",
+ "EGL_test.cpp",
+ ],
+
+ shared_libs: [
+ "android.hardware.configstore@1.0",
+ "android.hardware.configstore-utils",
+ "libEGL",
+ "libbase",
+ "libcutils",
+ "libbinder",
+ "libgui",
+ "libhidlbase",
+ "libhidltransport",
+ "liblog",
+ "libutils",
+ ],
+
+ include_dirs: [
+ "bionic/libc/private",
+ "frameworks/native/opengl/libs",
+ "frameworks/native/opengl/libs/EGL",
+ ],
+
+}
diff --git a/opengl/tests/EGLTest/Android.mk b/opengl/tests/EGLTest/Android.mk
deleted file mode 100644
index 5620496..0000000
--- a/opengl/tests/EGLTest/Android.mk
+++ /dev/null
@@ -1,44 +0,0 @@
-# Build the unit tests.
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-
-LOCAL_MODULE := EGL_test
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := \
- egl_cache_test.cpp \
- EGL_test.cpp \
-
-LOCAL_SHARED_LIBRARIES := \
- android.hardware.configstore@1.0 \
- android.hardware.configstore-utils \
- libEGL \
- libcutils \
- libbinder \
- libhidlbase \
- libhidltransport \
- libutils \
- libgui \
- libbase \
- liblog \
-
-LOCAL_C_INCLUDES := \
- bionic/libc/private \
- frameworks/native/opengl/libs \
- frameworks/native/opengl/libs/EGL \
-
-# gold in binutils 2.22 will warn about the usage of mktemp
-LOCAL_LDFLAGS += -Wl,--no-fatal-warnings
-
-include $(BUILD_NATIVE_TEST)
-
-# Include subdirectory makefiles
-# ============================================================
-
-# If we're building with ONE_SHOT_MAKEFILE (mm, mmm), then what the framework
-# team really wants is to build the stuff defined by this makefile.
-ifeq (,$(ONE_SHOT_MAKEFILE))
-include $(call first-makefiles-under,$(LOCAL_PATH))
-endif
diff --git a/opengl/tests/EGLTest/EGL_test.cpp b/opengl/tests/EGLTest/EGL_test.cpp
index 62e6bd3..b67a053 100644
--- a/opengl/tests/EGLTest/EGL_test.cpp
+++ b/opengl/tests/EGLTest/EGL_test.cpp
@@ -200,6 +200,7 @@
if (!hasWideColorDisplay) {
// skip this test if device does not have wide-color display
+ std::cerr << "[ ] Device does not support wide-color, test skipped" << std::endl;
return;
}
@@ -285,6 +286,7 @@
if (!hasWideColorDisplay) {
// skip this test if device does not have wide-color display
+ std::cerr << "[ ] Device does not support wide-color, test skipped" << std::endl;
return;
}
@@ -370,6 +372,7 @@
if (!hasWideColorDisplay) {
// skip this test if device does not have wide-color display
+ std::cerr << "[ ] Device does not support wide-color, test skipped" << std::endl;
return;
}
@@ -431,9 +434,10 @@
EXPECT_TRUE(eglDestroySurface(mEglDisplay, eglSurface));
}
-TEST_F(EGLTest, EGL_KHR_no_config_context) {
+TEST_F(EGLTest, EGLNoConfigContext) {
if (!hasWideColorDisplay) {
// skip this test if device does not have wide-color display
+ std::cerr << "[ ] Device does not support wide-color, test skipped" << std::endl;
return;
}
@@ -471,6 +475,7 @@
if (!hasWideColorDisplay) {
// skip this test if device does not have wide-color display
+ std::cerr << "[ ] Device does not support wide-color, test skipped" << std::endl;
return;
}
diff --git a/opengl/tests/angeles/Android.bp b/opengl/tests/angeles/Android.bp
new file mode 100644
index 0000000..bbbc447
--- /dev/null
+++ b/opengl/tests/angeles/Android.bp
@@ -0,0 +1,22 @@
+// Copyright 2006 The Android Open Source Project
+
+cc_test {
+ name: "angeles",
+
+ srcs: [
+ "app-linux.cpp",
+ "demo.c",
+ ],
+
+ gtest: false,
+
+ shared_libs: [
+ "libEGL",
+ "libGLESv1_CM",
+ "libui",
+ "libgui",
+ "libutils",
+ ],
+
+ static_libs: ["libglTest"],
+}
diff --git a/opengl/tests/angeles/Android.mk b/opengl/tests/angeles/Android.mk
deleted file mode 100644
index c78224e..0000000
--- a/opengl/tests/angeles/Android.mk
+++ /dev/null
@@ -1,11 +0,0 @@
-# Copyright 2006 The Android Open Source Project
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES:= app-linux.cpp demo.c.arm
-LOCAL_SHARED_LIBRARIES := libEGL libGLESv1_CM libui libgui libutils
-LOCAL_STATIC_LIBRARIES += libglTest
-LOCAL_C_INCLUDES += $(call include-path-for, opengl-tests-includes)
-LOCAL_MODULE:= angeles
-LOCAL_MODULE_TAGS := optional
-include $(BUILD_EXECUTABLE)
diff --git a/opengl/tests/angeles/demo.c b/opengl/tests/angeles/demo.c
index 39d871e..30c3202 100644
--- a/opengl/tests/angeles/demo.c
+++ b/opengl/tests/angeles/demo.c
@@ -462,7 +462,7 @@
// Called from the app framework.
void appInit()
{
- int a;
+ unsigned int a;
glEnable(GL_NORMALIZE);
glEnable(GL_DEPTH_TEST);
@@ -492,7 +492,7 @@
// Called from the app framework.
void appDeinit()
{
- int a;
+ unsigned int a;
for (a = 0; a < SUPERSHAPE_COUNT; ++a)
freeGLObject(sSuperShapeObjects[a]);
freeGLObject(sGroundPlane);
diff --git a/opengl/tests/configdump/Android.bp b/opengl/tests/configdump/Android.bp
new file mode 100644
index 0000000..c46477c
--- /dev/null
+++ b/opengl/tests/configdump/Android.bp
@@ -0,0 +1,13 @@
+cc_test {
+ name: "test-opengl-configdump",
+
+ gtest: false,
+
+ srcs: ["configdump.cpp"],
+
+ shared_libs: [
+ "libcutils",
+ "libEGL",
+ "libGLESv1_CM",
+ ],
+}
diff --git a/opengl/tests/configdump/Android.mk b/opengl/tests/configdump/Android.mk
deleted file mode 100644
index 3f7c915..0000000
--- a/opengl/tests/configdump/Android.mk
+++ /dev/null
@@ -1,16 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
- configdump.cpp
-
-LOCAL_SHARED_LIBRARIES := \
- libcutils \
- libEGL \
- libGLESv1_CM
-
-LOCAL_MODULE:= test-opengl-configdump
-
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_EXECUTABLE)
diff --git a/opengl/tests/configdump/configdump.cpp b/opengl/tests/configdump/configdump.cpp
index c423105..a4bb879 100644
--- a/opengl/tests/configdump/configdump.cpp
+++ b/opengl/tests/configdump/configdump.cpp
@@ -78,7 +78,7 @@
for (EGLint i=0 ; i<n ; i++) {
printf("EGLConfig[%d]\n", i);
- for (int attr = 0 ; attr<sizeof(attributes)/sizeof(Attribute) ; attr++) {
+ for (unsigned attr = 0 ; attr<sizeof(attributes)/sizeof(Attribute) ; attr++) {
EGLint value;
eglGetConfigAttrib(dpy, configs[i], attributes[attr].attribute, &value);
printf("\t%-32s: %10d (0x%08x)\n", attributes[attr].name, value, value);
diff --git a/opengl/tests/fillrate/Android.bp b/opengl/tests/fillrate/Android.bp
new file mode 100644
index 0000000..543f1e3
--- /dev/null
+++ b/opengl/tests/fillrate/Android.bp
@@ -0,0 +1,18 @@
+cc_test {
+ name: "test-opengl-fillrate",
+
+ srcs: ["fillrate.cpp"],
+
+ gtest: false,
+
+ shared_libs: [
+ "libcutils",
+ "libutils",
+ "libEGL",
+ "libGLESv1_CM",
+ "libui",
+ "libgui",
+ ],
+
+ static_libs: ["libglTest"],
+}
diff --git a/opengl/tests/fillrate/Android.mk b/opengl/tests/fillrate/Android.mk
deleted file mode 100644
index 21ff52a..0000000
--- a/opengl/tests/fillrate/Android.mk
+++ /dev/null
@@ -1,23 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
- fillrate.cpp
-
-LOCAL_SHARED_LIBRARIES := \
- libcutils \
- libutils \
- libEGL \
- libGLESv1_CM \
- libui \
- libgui
-
-LOCAL_STATIC_LIBRARIES += libglTest
-
-LOCAL_C_INCLUDES += $(call include-path-for, opengl-tests-includes)
-
-LOCAL_MODULE:= test-opengl-fillrate
-
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_EXECUTABLE)
diff --git a/opengl/tests/fillrate/fillrate.cpp b/opengl/tests/fillrate/fillrate.cpp
index 2db63d7..a42f3f2 100644
--- a/opengl/tests/fillrate/fillrate.cpp
+++ b/opengl/tests/fillrate/fillrate.cpp
@@ -30,7 +30,7 @@
using namespace android;
-int main(int argc, char** argv)
+int main(int /*argc*/, char** /*argv*/)
{
EGLint configAttribs[] = {
EGL_DEPTH_SIZE, 0,
@@ -153,7 +153,7 @@
for (int c=1, j=0 ; c<32 ; c++, j++) {
nsecs_t t = times[j];
- printf("%lld\t%d\t%f\n", t, c, (double(t)/c)/1000000.0);
+ printf("%ld\t%d\t%f\n", t, c, (double(t)/c)/1000000.0);
}
diff --git a/opengl/tests/filter/Android.bp b/opengl/tests/filter/Android.bp
new file mode 100644
index 0000000..5f925c8
--- /dev/null
+++ b/opengl/tests/filter/Android.bp
@@ -0,0 +1,20 @@
+cc_test {
+ name: "test-opengl-filter",
+
+ srcs: ["filter.cpp"],
+
+ gtest: false,
+
+ shared_libs: [
+ "libcutils",
+ "libEGL",
+ "libGLESv1_CM",
+ "libui",
+ "libgui",
+ "libutils",
+ ],
+
+ static_libs: ["libglTest"],
+
+ cflags: ["-DGL_GLEXT_PROTOTYPES"],
+}
diff --git a/opengl/tests/filter/Android.mk b/opengl/tests/filter/Android.mk
deleted file mode 100644
index 4cf9c96..0000000
--- a/opengl/tests/filter/Android.mk
+++ /dev/null
@@ -1,25 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
- filter.cpp
-
-LOCAL_SHARED_LIBRARIES := \
- libcutils \
- libEGL \
- libGLESv1_CM \
- libui \
- libgui \
- libutils
-
-LOCAL_STATIC_LIBRARIES += libglTest
-
-LOCAL_C_INCLUDES += $(call include-path-for, opengl-tests-includes)
-
-LOCAL_MODULE:= test-opengl-filter
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES
-
-include $(BUILD_EXECUTABLE)
diff --git a/opengl/tests/finish/Android.bp b/opengl/tests/finish/Android.bp
new file mode 100644
index 0000000..fb5671d
--- /dev/null
+++ b/opengl/tests/finish/Android.bp
@@ -0,0 +1,20 @@
+cc_test {
+ name: "test-opengl-finish",
+
+ srcs: ["finish.cpp"],
+
+ gtest: false,
+
+ shared_libs: [
+ "libcutils",
+ "libutils",
+ "libEGL",
+ "libGLESv1_CM",
+ "libui",
+ "libgui",
+ ],
+
+ static_libs: ["libglTest"],
+
+ cflags: ["-DGL_GLEXT_PROTOTYPES"],
+}
diff --git a/opengl/tests/finish/Android.mk b/opengl/tests/finish/Android.mk
deleted file mode 100644
index 0b9b7ea..0000000
--- a/opengl/tests/finish/Android.mk
+++ /dev/null
@@ -1,25 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
- finish.cpp
-
-LOCAL_SHARED_LIBRARIES := \
- libcutils \
- libutils \
- libEGL \
- libGLESv1_CM \
- libui \
- libgui
-
-LOCAL_STATIC_LIBRARIES += libglTest
-
-LOCAL_C_INCLUDES += $(call include-path-for, opengl-tests-includes)
-
-LOCAL_MODULE:= test-opengl-finish
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES
-
-include $(BUILD_EXECUTABLE)
diff --git a/opengl/tests/finish/finish.cpp b/opengl/tests/finish/finish.cpp
index ea3a60f..ab955fe 100644
--- a/opengl/tests/finish/finish.cpp
+++ b/opengl/tests/finish/finish.cpp
@@ -31,7 +31,7 @@
using namespace android;
-int main(int argc, char** argv)
+int main(int /*argc*/, char** /*argv*/)
{
EGLint configAttribs[] = {
EGL_DEPTH_SIZE, 0,
diff --git a/opengl/tests/gl2_basic/Android.bp b/opengl/tests/gl2_basic/Android.bp
new file mode 100644
index 0000000..7403271
--- /dev/null
+++ b/opengl/tests/gl2_basic/Android.bp
@@ -0,0 +1,20 @@
+cc_test {
+ name: "test-opengl-gl2_basic",
+
+ srcs: ["gl2_basic.cpp"],
+
+ gtest: false,
+
+ shared_libs: [
+ "libcutils",
+ "libEGL",
+ "libGLESv2",
+ "libui",
+ "libgui",
+ "libutils",
+ ],
+
+ static_libs: ["libglTest"],
+
+ cflags: ["-DGL_GLEXT_PROTOTYPES"],
+}
diff --git a/opengl/tests/gl2_basic/Android.mk b/opengl/tests/gl2_basic/Android.mk
deleted file mode 100644
index 520395c..0000000
--- a/opengl/tests/gl2_basic/Android.mk
+++ /dev/null
@@ -1,25 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
- gl2_basic.cpp
-
-LOCAL_SHARED_LIBRARIES := \
- libcutils \
- libEGL \
- libGLESv2 \
- libui \
- libgui \
- libutils
-
-LOCAL_STATIC_LIBRARIES += libglTest
-
-LOCAL_C_INCLUDES += $(call include-path-for, opengl-tests-includes)
-
-LOCAL_MODULE:= test-opengl-gl2_basic
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES
-
-include $(BUILD_EXECUTABLE)
diff --git a/opengl/tests/gl2_basic/gl2_basic.cpp b/opengl/tests/gl2_basic/gl2_basic.cpp
index ee88667..67c0969 100644
--- a/opengl/tests/gl2_basic/gl2_basic.cpp
+++ b/opengl/tests/gl2_basic/gl2_basic.cpp
@@ -30,7 +30,7 @@
#include <EGLUtils.h>
using namespace android;
-EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name);
+extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name);
static void printGLString(const char *name, GLenum s) {
// fprintf(stderr, "printGLString %s, %d\n", name, s);
diff --git a/opengl/tests/gl2_copyTexImage/Android.bp b/opengl/tests/gl2_copyTexImage/Android.bp
new file mode 100644
index 0000000..51e269c
--- /dev/null
+++ b/opengl/tests/gl2_copyTexImage/Android.bp
@@ -0,0 +1,20 @@
+cc_test {
+ name: "test-opengl-gl2_copyTexImage",
+
+ srcs: ["gl2_copyTexImage.cpp"],
+
+ gtest: false,
+
+ shared_libs: [
+ "libcutils",
+ "libEGL",
+ "libGLESv2",
+ "libui",
+ "libgui",
+ "libutils",
+ ],
+
+ static_libs: ["libglTest"],
+
+ cflags: ["-DGL_GLEXT_PROTOTYPES"],
+}
diff --git a/opengl/tests/gl2_copyTexImage/Android.mk b/opengl/tests/gl2_copyTexImage/Android.mk
deleted file mode 100644
index ff43558..0000000
--- a/opengl/tests/gl2_copyTexImage/Android.mk
+++ /dev/null
@@ -1,25 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
- gl2_copyTexImage.cpp
-
-LOCAL_SHARED_LIBRARIES := \
- libcutils \
- libEGL \
- libGLESv2 \
- libui \
- libgui \
- libutils
-
-LOCAL_STATIC_LIBRARIES += libglTest
-
-LOCAL_C_INCLUDES += $(call include-path-for, opengl-tests-includes)
-
-LOCAL_MODULE:= test-opengl-gl2_copyTexImage
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES
-
-include $(BUILD_EXECUTABLE)
diff --git a/opengl/tests/gl2_copyTexImage/gl2_copyTexImage.cpp b/opengl/tests/gl2_copyTexImage/gl2_copyTexImage.cpp
index 405a3f0..e0aafa2 100644
--- a/opengl/tests/gl2_copyTexImage/gl2_copyTexImage.cpp
+++ b/opengl/tests/gl2_copyTexImage/gl2_copyTexImage.cpp
@@ -362,7 +362,7 @@
return true;
}
-int main(int argc, char** argv) {
+int main(int /*argc*/, char** /*argv*/) {
EGLBoolean returnValue;
EGLConfig myConfig = {0};
diff --git a/opengl/tests/gl2_jni/jni/gl_code.cpp b/opengl/tests/gl2_jni/jni/gl_code.cpp
index ed896a4..5af4f6b 100644
--- a/opengl/tests/gl2_jni/jni/gl_code.cpp
+++ b/opengl/tests/gl2_jni/jni/gl_code.cpp
@@ -1,6 +1,6 @@
// OpenGL ES 2.0 code
-#include <nativehelper/jni.h>
+#include <jni.h>
#define LOG_TAG "GL2JNI gl_code.cpp"
#include <utils/Log.h>
@@ -153,12 +153,12 @@
JNIEXPORT void JNICALL Java_com_android_gl2jni_GL2JNILib_step(JNIEnv * env, jobject obj);
};
-JNIEXPORT void JNICALL Java_com_android_gl2jni_GL2JNILib_init(JNIEnv * env, jobject obj, jint width, jint height)
+JNIEXPORT void JNICALL Java_com_android_gl2jni_GL2JNILib_init(JNIEnv * /*env*/, jobject /*obj*/, jint width, jint height)
{
setupGraphics(width, height);
}
-JNIEXPORT void JNICALL Java_com_android_gl2jni_GL2JNILib_step(JNIEnv * env, jobject obj)
+JNIEXPORT void JNICALL Java_com_android_gl2jni_GL2JNILib_step(JNIEnv * /*env*/, jobject /*obj*/)
{
renderFrame();
}
diff --git a/opengl/tests/gl2_yuvtex/Android.bp b/opengl/tests/gl2_yuvtex/Android.bp
new file mode 100644
index 0000000..613d678
--- /dev/null
+++ b/opengl/tests/gl2_yuvtex/Android.bp
@@ -0,0 +1,24 @@
+cc_test {
+ name: "test-opengl-gl2_yuvtex",
+
+ srcs: ["gl2_yuvtex.cpp"],
+
+ shared_libs: [
+ "libcutils",
+ "libEGL",
+ "libGLESv2",
+ "libutils",
+ "libui",
+ "libgui",
+ "libutils",
+ ],
+
+ gtest: false,
+
+ static_libs: ["libglTest"],
+
+ cflags: [
+ "-DGL_GLEXT_PROTOTYPES",
+ "-DEGL_EGLEXT_PROTOTYPES",
+ ],
+}
diff --git a/opengl/tests/gl2_yuvtex/Android.mk b/opengl/tests/gl2_yuvtex/Android.mk
deleted file mode 100644
index 42cf771..0000000
--- a/opengl/tests/gl2_yuvtex/Android.mk
+++ /dev/null
@@ -1,26 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
- gl2_yuvtex.cpp
-
-LOCAL_SHARED_LIBRARIES := \
- libcutils \
- libEGL \
- libGLESv2 \
- libutils \
- libui \
- libgui \
- libutils
-
-LOCAL_STATIC_LIBRARIES += libglTest
-
-LOCAL_C_INCLUDES += $(call include-path-for, opengl-tests-includes)
-
-LOCAL_MODULE:= test-opengl-gl2_yuvtex
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
-
-include $(BUILD_EXECUTABLE)
diff --git a/opengl/tests/gl_basic/Android.bp b/opengl/tests/gl_basic/Android.bp
new file mode 100644
index 0000000..881d8ce
--- /dev/null
+++ b/opengl/tests/gl_basic/Android.bp
@@ -0,0 +1,18 @@
+cc_test {
+ name: "test-opengl-gl_basic",
+
+ srcs: ["gl_basic.cpp"],
+
+ gtest: false,
+
+ shared_libs: [
+ "libcutils",
+ "libEGL",
+ "libGLESv1_CM",
+ "libui",
+ "libgui",
+ "libutils",
+ ],
+
+ static_libs: ["libglTest"],
+}
diff --git a/opengl/tests/gl_basic/Android.mk b/opengl/tests/gl_basic/Android.mk
deleted file mode 100644
index 7f2259e..0000000
--- a/opengl/tests/gl_basic/Android.mk
+++ /dev/null
@@ -1,23 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
- gl_basic.cpp
-
-LOCAL_SHARED_LIBRARIES := \
- libcutils \
- libEGL \
- libGLESv1_CM \
- libui \
- libgui \
- libutils
-
-LOCAL_STATIC_LIBRARIES += libglTest
-
-LOCAL_C_INCLUDES += $(call include-path-for, opengl-tests-includes)
-
-LOCAL_MODULE:= test-opengl-gl_basic
-
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_EXECUTABLE)
diff --git a/opengl/tests/gl_basic/gl_basic.cpp b/opengl/tests/gl_basic/gl_basic.cpp
index e50d88f..0b663f7 100644
--- a/opengl/tests/gl_basic/gl_basic.cpp
+++ b/opengl/tests/gl_basic/gl_basic.cpp
@@ -189,7 +189,7 @@
return true;
}
-int main(int argc, char **argv)
+int main(int /*argc*/, char **/*argv*/)
{
int q;
int start, end;
diff --git a/opengl/tests/gl_jni/jni/gl_code.cpp b/opengl/tests/gl_jni/jni/gl_code.cpp
index cf86020..3aa8adb 100644
--- a/opengl/tests/gl_jni/jni/gl_code.cpp
+++ b/opengl/tests/gl_jni/jni/gl_code.cpp
@@ -1,6 +1,6 @@
// OpenGL ES 1.0 code
-#include <nativehelper/jni.h>
+#include <jni.h>
#define LOG_TAG "GLJNI gl_code.cpp"
#include <utils/Log.h>
@@ -140,13 +140,13 @@
JNIEXPORT void JNICALL Java_com_android_gljni_GLJNILib_changeBackground(JNIEnv * env, jobject obj);
};
-JNIEXPORT void JNICALL Java_com_android_gljni_GLJNILib_init(JNIEnv * env, jobject obj, jint width, jint height)
+JNIEXPORT void JNICALL Java_com_android_gljni_GLJNILib_init(JNIEnv * /*env*/, jobject /*obj*/, jint width, jint height)
{
init_scene(width, height);
create_texture();
}
-JNIEXPORT void JNICALL Java_com_android_gljni_GLJNILib_step(JNIEnv * env, jobject obj)
+JNIEXPORT void JNICALL Java_com_android_gljni_GLJNILib_step(JNIEnv * /*env*/, jobject /*obj*/)
{
const GLfloat vertices[] = {
-1, -1, 0,
@@ -177,7 +177,7 @@
glDrawElements(GL_TRIANGLES, nelem, GL_UNSIGNED_SHORT, quadIndices);
}
-JNIEXPORT void JNICALL Java_com_android_gljni_GLJNILib_changeBackground(JNIEnv * env, jobject obj)
+JNIEXPORT void JNICALL Java_com_android_gljni_GLJNILib_changeBackground(JNIEnv * /*env*/, jobject /*obj*/)
{
background = 1.0f - background;
}
diff --git a/opengl/tests/gl_perf/Android.bp b/opengl/tests/gl_perf/Android.bp
new file mode 100644
index 0000000..0ffb121
--- /dev/null
+++ b/opengl/tests/gl_perf/Android.bp
@@ -0,0 +1,24 @@
+cc_test {
+ name: "test-opengl-gl2_perf",
+
+ srcs: [
+ "gl2_perf.cpp",
+ "filltest.cpp",
+ ],
+
+ gtest: false,
+
+ shared_libs: [
+ "libcutils",
+ "liblog",
+ "libEGL",
+ "libGLESv2",
+ "libui",
+ "libgui",
+ "libutils",
+ ],
+
+ static_libs: ["libglTest"],
+
+ cflags: ["-DGL_GLEXT_PROTOTYPES"],
+}
diff --git a/opengl/tests/gl_perf/Android.mk b/opengl/tests/gl_perf/Android.mk
deleted file mode 100644
index 9a93fab..0000000
--- a/opengl/tests/gl_perf/Android.mk
+++ /dev/null
@@ -1,27 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
- gl2_perf.cpp \
- filltest.cpp
-
-LOCAL_SHARED_LIBRARIES := \
- libcutils \
- liblog \
- libEGL \
- libGLESv2 \
- libui \
- libgui \
- libutils
-
-LOCAL_STATIC_LIBRARIES += libglTest
-
-LOCAL_C_INCLUDES += $(call include-path-for, opengl-tests-includes)
-
-LOCAL_MODULE:= test-opengl-gl2_perf
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES
-
-include $(BUILD_EXECUTABLE)
diff --git a/opengl/tests/gl_perf/filltest.cpp b/opengl/tests/gl_perf/filltest.cpp
index 3f8faca..4135c62 100644
--- a/opengl/tests/gl_perf/filltest.cpp
+++ b/opengl/tests/gl_perf/filltest.cpp
@@ -27,10 +27,6 @@
#include <EGL/egl.h>
#include <utils/Log.h>
-
-using namespace android;
-
-
#include "fill_common.cpp"
diff --git a/opengl/tests/gl_perf/gl2_perf.cpp b/opengl/tests/gl_perf/gl2_perf.cpp
index 35df84f..2998864 100644
--- a/opengl/tests/gl_perf/gl2_perf.cpp
+++ b/opengl/tests/gl_perf/gl2_perf.cpp
@@ -56,7 +56,7 @@
static EGLDisplay dpy;
static EGLSurface surface;
-int main(int argc, char** argv) {
+int main(int /*argc*/, char** /*argv*/) {
EGLBoolean returnValue;
EGLConfig myConfig = {0};
diff --git a/opengl/tests/gl_perfapp/jni/gl_code.cpp b/opengl/tests/gl_perfapp/jni/gl_code.cpp
index 378c8e8..0cb594a 100644
--- a/opengl/tests/gl_perfapp/jni/gl_code.cpp
+++ b/opengl/tests/gl_perfapp/jni/gl_code.cpp
@@ -1,6 +1,6 @@
// OpenGL ES 2.0 code
-#include <nativehelper/jni.h>
+#include <jni.h>
#define LOG_TAG "GLPerf gl_code.cpp"
#include <utils/Log.h>
@@ -61,7 +61,7 @@
JNIEXPORT void JNICALL Java_com_android_glperf_GLPerfLib_step(JNIEnv * env, jobject obj);
};
-JNIEXPORT void JNICALL Java_com_android_glperf_GLPerfLib_init(JNIEnv * env, jobject obj, jint width, jint height)
+JNIEXPORT void JNICALL Java_com_android_glperf_GLPerfLib_init(JNIEnv * /*env*/, jobject /*obj*/, jint width, jint height)
{
gWidth = width;
gHeight = height;
@@ -87,7 +87,7 @@
}
}
-JNIEXPORT void JNICALL Java_com_android_glperf_GLPerfLib_step(JNIEnv * env, jobject obj)
+JNIEXPORT void JNICALL Java_com_android_glperf_GLPerfLib_step(JNIEnv * /*env*/, jobject /*obj*/)
{
if (! done) {
if (stateClock > 0 && ((stateClock & 1) == 0)) {
diff --git a/opengl/tests/gl_yuvtex/Android.bp b/opengl/tests/gl_yuvtex/Android.bp
new file mode 100644
index 0000000..b6be327
--- /dev/null
+++ b/opengl/tests/gl_yuvtex/Android.bp
@@ -0,0 +1,23 @@
+cc_test {
+ name: "test-opengl-gl_yuvtex",
+
+ srcs: ["gl_yuvtex.cpp"],
+
+ shared_libs: [
+ "libcutils",
+ "libEGL",
+ "libGLESv1_CM",
+ "libutils",
+ "libui",
+ "libgui",
+ ],
+
+ gtest: false,
+
+ static_libs: ["libglTest"],
+
+ cflags: [
+ "-DGL_GLEXT_PROTOTYPES",
+ "-DEGL_EGLEXT_PROTOTYPES",
+ ],
+}
diff --git a/opengl/tests/gl_yuvtex/Android.mk b/opengl/tests/gl_yuvtex/Android.mk
deleted file mode 100644
index 7f2020a..0000000
--- a/opengl/tests/gl_yuvtex/Android.mk
+++ /dev/null
@@ -1,25 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
- gl_yuvtex.cpp
-
-LOCAL_SHARED_LIBRARIES := \
- libcutils \
- libEGL \
- libGLESv1_CM \
- libutils \
- libui \
- libgui
-
-LOCAL_STATIC_LIBRARIES += libglTest
-
-LOCAL_C_INCLUDES += $(call include-path-for, opengl-tests-includes)
-
-LOCAL_MODULE:= test-opengl-gl_yuvtex
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
-
-include $(BUILD_EXECUTABLE)
diff --git a/opengl/tests/gl_yuvtex/gl_yuvtex.cpp b/opengl/tests/gl_yuvtex/gl_yuvtex.cpp
index fad26a6..7ef3f4e 100644
--- a/opengl/tests/gl_yuvtex/gl_yuvtex.cpp
+++ b/opengl/tests/gl_yuvtex/gl_yuvtex.cpp
@@ -90,7 +90,7 @@
static sp<GraphicBuffer> yuvTexBuffer;
static GLuint yuvTex;
-bool setupYuvTexSurface(EGLDisplay dpy, EGLContext context) {
+static bool setupYuvTexSurface(EGLDisplay dpy) {
int blockWidth = yuvTexWidth > 16 ? yuvTexWidth / 16 : 1;
int blockHeight = yuvTexHeight > 16 ? yuvTexHeight / 16 : 1;
yuvTexBuffer = new GraphicBuffer(yuvTexWidth, yuvTexHeight, yuvTexFormat,
@@ -298,7 +298,7 @@
printGLString("Renderer", GL_RENDERER);
printGLString("Extensions", GL_EXTENSIONS);
- if(!setupYuvTexSurface(dpy, context)) {
+ if(!setupYuvTexSurface(dpy)) {
fprintf(stderr, "Could not set up texture surface.\n");
return 1;
}
diff --git a/opengl/tests/gldual/jni/gl_code.cpp b/opengl/tests/gldual/jni/gl_code.cpp
index 22867ed..90d150b 100644
--- a/opengl/tests/gldual/jni/gl_code.cpp
+++ b/opengl/tests/gldual/jni/gl_code.cpp
@@ -1,6 +1,6 @@
// OpenGL ES 2.0 code
-#include <nativehelper/jni.h>
+#include <jni.h>
#define LOG_TAG "GL2JNI gl_code.cpp"
#include <utils/Log.h>
@@ -153,12 +153,12 @@
JNIEXPORT void JNICALL Java_com_android_gldual_GLDualLib_step(JNIEnv * env, jobject obj);
};
-JNIEXPORT void JNICALL Java_com_android_gldual_GLDualLib_init(JNIEnv * env, jobject obj, jint width, jint height)
+JNIEXPORT void JNICALL Java_com_android_gldual_GLDualLib_init(JNIEnv * /*env*/, jobject /*obj*/, jint width, jint height)
{
setupGraphics(width, height);
}
-JNIEXPORT void JNICALL Java_com_android_gldual_GLDualLib_step(JNIEnv * env, jobject obj)
+JNIEXPORT void JNICALL Java_com_android_gldual_GLDualLib_step(JNIEnv * /*env*/, jobject /*obj*/)
{
renderFrame();
}
diff --git a/opengl/tests/gralloc/Android.bp b/opengl/tests/gralloc/Android.bp
new file mode 100644
index 0000000..414c804
--- /dev/null
+++ b/opengl/tests/gralloc/Android.bp
@@ -0,0 +1,13 @@
+cc_test {
+ name: "test-opengl-gralloc",
+
+ srcs: ["gralloc.cpp"],
+
+ gtest: false,
+
+ shared_libs: [
+ "libcutils",
+ "libutils",
+ "libui",
+ ],
+}
diff --git a/opengl/tests/gralloc/Android.mk b/opengl/tests/gralloc/Android.mk
deleted file mode 100644
index d43c39a..0000000
--- a/opengl/tests/gralloc/Android.mk
+++ /dev/null
@@ -1,16 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
- gralloc.cpp
-
-LOCAL_SHARED_LIBRARIES := \
- libcutils \
- libutils \
- libui
-
-LOCAL_MODULE:= test-opengl-gralloc
-
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_EXECUTABLE)
diff --git a/opengl/tests/gralloc/gralloc.cpp b/opengl/tests/gralloc/gralloc.cpp
index 8987040..29e0882 100644
--- a/opengl/tests/gralloc/gralloc.cpp
+++ b/opengl/tests/gralloc/gralloc.cpp
@@ -37,7 +37,7 @@
return d;
}
-int main(int argc, char** argv)
+int main(int /*argc*/, char** /*argv*/)
{
size_t size = 128*256*4;
void* temp = malloc(size);
diff --git a/opengl/tests/hwc/Android.bp b/opengl/tests/hwc/Android.bp
index 425f374..55f058f 100644
--- a/opengl/tests/hwc/Android.bp
+++ b/opengl/tests/hwc/Android.bp
@@ -55,6 +55,8 @@
"libnativewindow"
],
+ gtest: false,
+
static_libs: [
"libglTest",
"libhwcTest",
diff --git a/opengl/tests/hwc/hwcRects.cpp b/opengl/tests/hwc/hwcRects.cpp
index 69e56ff..5956366 100644
--- a/opengl/tests/hwc/hwcRects.cpp
+++ b/opengl/tests/hwc/hwcRects.cpp
@@ -170,7 +170,7 @@
static EGLint width, height;
// Function prototypes
-static Rectangle parseRect(string rectStr);
+static Rectangle parseRect(const string& rectStr);
void init(void);
void printSyntax(const char *cmd);
@@ -358,7 +358,7 @@
// Parse string description of rectangle and add it to list of rectangles
// to be rendered.
-static Rectangle parseRect(string rectStr)
+static Rectangle parseRect(const string& rectStr)
{
int rv;
string str;
diff --git a/opengl/tests/lib/WindowSurface.cpp b/opengl/tests/lib/WindowSurface.cpp
index 1428945..2b76279 100644
--- a/opengl/tests/lib/WindowSurface.cpp
+++ b/opengl/tests/lib/WindowSurface.cpp
@@ -62,19 +62,10 @@
return;
}
- SurfaceComposerClient::openGlobalTransaction();
- err = sc->setLayer(0x7FFFFFFF); // always on top
- if (err != NO_ERROR) {
- fprintf(stderr, "SurfaceComposer::setLayer error: %#x\n", err);
- return;
- }
-
- err = sc->show();
- if (err != NO_ERROR) {
- fprintf(stderr, "SurfaceComposer::show error: %#x\n", err);
- return;
- }
- SurfaceComposerClient::closeGlobalTransaction();
+ SurfaceComposerClient::Transaction{}
+ .setLayer(sc, 0x7FFFFFFF)
+ .show(sc)
+ .apply();
mSurfaceControl = sc;
}
diff --git a/opengl/tests/lib/include/EGLUtils.h b/opengl/tests/lib/include/EGLUtils.h
index 014c261..9dc6bcf 100644
--- a/opengl/tests/lib/include/EGLUtils.h
+++ b/opengl/tests/lib/include/EGLUtils.h
@@ -20,11 +20,16 @@
#include <stdint.h>
#include <stdlib.h>
+#include <vector>
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <GLES2/gl2.h>
#include <system/window.h>
#include <utils/Errors.h>
-#include <EGL/egl.h>
+#include <utils/String8.h>
+extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name);
// ----------------------------------------------------------------------------
namespace android {
@@ -47,6 +52,17 @@
EGLint const* attrs,
EGLNativeWindowType window,
EGLConfig* outConfig);
+
+ static inline String8 printGLString(const char* name, GLenum s);
+ static inline String8 printEGLString(EGLDisplay dpy, const char* name, GLenum s);
+ static inline String8 checkEglError(const char* op, EGLBoolean returnVal);
+ static inline String8 checkGlError(const char* op);
+ static inline String8 printEGLConfiguration(EGLDisplay dpy, EGLConfig config);
+ static inline bool printEGLConfigurations(EGLDisplay dpy, String8& msg);
+ static inline bool printEGLConfigurations(FILE* output, EGLDisplay dpy);
+ static inline String8 decodeColorSpace(EGLint colorSpace);
+ static inline bool hasEglExtension(EGLDisplay dpy, const char* name);
+ static inline bool hasExtension(const char* exts, const char* name);
};
// ----------------------------------------------------------------------------
@@ -91,9 +107,8 @@
if (eglGetConfigs(dpy, NULL, 0, &numConfigs) == EGL_FALSE)
return BAD_VALUE;
- EGLConfig* const configs = (EGLConfig*)malloc(sizeof(EGLConfig)*numConfigs);
- if (eglChooseConfig(dpy, attrs, configs, numConfigs, &n) == EGL_FALSE) {
- free(configs);
+ std::vector<EGLConfig> configs(numConfigs);
+ if (eglChooseConfig(dpy, attrs, configs.data(), numConfigs, &n) == EGL_FALSE) {
return BAD_VALUE;
}
@@ -108,8 +123,6 @@
}
}
- free(configs);
-
if (i<n) {
*outConfig = config;
return NO_ERROR;
@@ -137,6 +150,159 @@
return selectConfigForPixelFormat(dpy, attrs, format, outConfig);
}
+String8 EGLUtils::printGLString(const char* name, GLenum s) {
+ String8 msg;
+ const char* v = reinterpret_cast<const char*>(glGetString(s));
+ msg.appendFormat("GL %s = %s\n", name, v);
+ return msg;
+}
+
+String8 EGLUtils::printEGLString(EGLDisplay dpy, const char* name, GLenum s) {
+ String8 msg;
+ const char* v = static_cast<const char*>(eglQueryString(dpy, s));
+ msg.appendFormat("GL %s = %s\n", name, v);
+ const char* va = (const char*)eglQueryStringImplementationANDROID(dpy, s);
+ msg.appendFormat("ImplementationANDROID: %s = %s\n", name, va);
+ return msg;
+}
+
+String8 EGLUtils::checkEglError(const char* op, EGLBoolean returnVal = EGL_TRUE) {
+ String8 msg;
+ if (returnVal != EGL_TRUE) {
+ msg.appendFormat("%s() returned %d\n", op, returnVal);
+ }
+
+ for (EGLint error = eglGetError(); error != EGL_SUCCESS; error = eglGetError()) {
+ msg.appendFormat("after %s() eglError %s (0x%x)\n", op, EGLUtils::strerror(error), error);
+ }
+ return msg;
+}
+
+String8 EGLUtils::checkGlError(const char* op) {
+ String8 msg;
+ for (GLint error = glGetError(); error != GL_NO_ERROR; error = glGetError()) {
+ msg.appendFormat("after %s() glError (0x%x)\n", op, error);
+ }
+ return msg;
+}
+
+String8 EGLUtils::printEGLConfiguration(EGLDisplay dpy, EGLConfig config) {
+#define X(VAL) \
+ { VAL, #VAL }
+ struct {
+ EGLint attribute;
+ const char* name;
+ } names[] = {
+ X(EGL_BUFFER_SIZE),
+ X(EGL_ALPHA_SIZE),
+ X(EGL_BLUE_SIZE),
+ X(EGL_GREEN_SIZE),
+ X(EGL_RED_SIZE),
+ X(EGL_DEPTH_SIZE),
+ X(EGL_STENCIL_SIZE),
+ X(EGL_CONFIG_CAVEAT),
+ X(EGL_CONFIG_ID),
+ X(EGL_LEVEL),
+ X(EGL_MAX_PBUFFER_HEIGHT),
+ X(EGL_MAX_PBUFFER_PIXELS),
+ X(EGL_MAX_PBUFFER_WIDTH),
+ X(EGL_NATIVE_RENDERABLE),
+ X(EGL_NATIVE_VISUAL_ID),
+ X(EGL_NATIVE_VISUAL_TYPE),
+ X(EGL_SAMPLES),
+ X(EGL_SAMPLE_BUFFERS),
+ X(EGL_SURFACE_TYPE),
+ X(EGL_TRANSPARENT_TYPE),
+ X(EGL_TRANSPARENT_RED_VALUE),
+ X(EGL_TRANSPARENT_GREEN_VALUE),
+ X(EGL_TRANSPARENT_BLUE_VALUE),
+ X(EGL_BIND_TO_TEXTURE_RGB),
+ X(EGL_BIND_TO_TEXTURE_RGBA),
+ X(EGL_MIN_SWAP_INTERVAL),
+ X(EGL_MAX_SWAP_INTERVAL),
+ X(EGL_LUMINANCE_SIZE),
+ X(EGL_ALPHA_MASK_SIZE),
+ X(EGL_COLOR_BUFFER_TYPE),
+ X(EGL_RENDERABLE_TYPE),
+ X(EGL_CONFORMANT),
+ };
+#undef X
+
+ String8 msg;
+ for (size_t j = 0; j < sizeof(names) / sizeof(names[0]); j++) {
+ EGLint value = -1;
+ EGLint returnVal = eglGetConfigAttrib(dpy, config, names[j].attribute, &value);
+ EGLint error = eglGetError();
+ if (returnVal && error == EGL_SUCCESS) {
+ msg.appendFormat(" %s: %d (0x%x)", names[j].name, value, value);
+ }
+ }
+ msg.append("\n");
+ return msg;
+}
+
+bool EGLUtils::printEGLConfigurations(EGLDisplay dpy, String8& msg) {
+ EGLint numConfig = 0;
+ EGLint returnVal = eglGetConfigs(dpy, NULL, 0, &numConfig);
+ msg.append(checkEglError("eglGetConfigs", returnVal));
+ if (!returnVal) {
+ return false;
+ }
+
+ msg.appendFormat("Number of EGL configuration: %d\n", numConfig);
+
+ std::vector<EGLConfig> configs(numConfig);
+
+ returnVal = eglGetConfigs(dpy, configs.data(), numConfig, &numConfig);
+ msg.append(checkEglError("eglGetConfigs", returnVal));
+ if (!returnVal) {
+ return false;
+ }
+
+ for (int i = 0; i < numConfig; i++) {
+ msg.appendFormat("Configuration %d\n", i);
+ msg.append(printEGLConfiguration(dpy, configs[i]));
+ }
+
+ return true;
+}
+
+bool EGLUtils::printEGLConfigurations(FILE* output, EGLDisplay dpy) {
+ String8 msg;
+ bool status = printEGLConfigurations(dpy, msg);
+ fprintf(output, "%s", msg.c_str());
+ return status;
+}
+
+String8 EGLUtils::decodeColorSpace(EGLint colorSpace) {
+ switch (colorSpace) {
+ case EGL_GL_COLORSPACE_SRGB_KHR:
+ return String8("EGL_GL_COLORSPACE_SRGB_KHR");
+ case EGL_GL_COLORSPACE_DISPLAY_P3_EXT:
+ return String8("EGL_GL_COLORSPACE_DISPLAY_P3_EXT");
+ case EGL_GL_COLORSPACE_LINEAR_KHR:
+ return String8("EGL_GL_COLORSPACE_LINEAR_KHR");
+ default:
+ return String8::format("UNKNOWN ColorSpace %d", colorSpace);
+ }
+}
+
+bool EGLUtils::hasExtension(const char* exts, const char* name) {
+ size_t nameLen = strlen(name);
+ if (exts) {
+ for (const char* match = strstr(exts, name); match; match = strstr(match + nameLen, name)) {
+ if (match[nameLen] == '\0' || match[nameLen] == ' ') {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+bool EGLUtils::hasEglExtension(EGLDisplay dpy, const char* name) {
+ return hasExtension(eglQueryString(dpy, EGL_EXTENSIONS), name);
+}
+
// ----------------------------------------------------------------------------
}; // namespace android
// ----------------------------------------------------------------------------
diff --git a/opengl/tests/linetex/linetex.cpp b/opengl/tests/linetex/linetex.cpp
index 5ad695b..cdc051b 100644
--- a/opengl/tests/linetex/linetex.cpp
+++ b/opengl/tests/linetex/linetex.cpp
@@ -29,7 +29,7 @@
using namespace android;
-int main(int argc, char** argv)
+int main(int /*argc*/, char** /*argv*/)
{
EGLint configAttribs[] = {
EGL_DEPTH_SIZE, 0,
diff --git a/opengl/tests/swapinterval/swapinterval.cpp b/opengl/tests/swapinterval/swapinterval.cpp
index 3a8a8a1..c4261e6 100644
--- a/opengl/tests/swapinterval/swapinterval.cpp
+++ b/opengl/tests/swapinterval/swapinterval.cpp
@@ -28,7 +28,7 @@
using namespace android;
-int main(int argc, char** argv)
+int main(int /*argc*/, char** /*argv*/)
{
EGLint configAttribs[] = {
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
diff --git a/opengl/tests/textures/textures.cpp b/opengl/tests/textures/textures.cpp
index 1e55db0..7be942a 100644
--- a/opengl/tests/textures/textures.cpp
+++ b/opengl/tests/textures/textures.cpp
@@ -27,7 +27,7 @@
using namespace android;
-int main(int argc, char** argv)
+int main(int /*argc*/, char** /*argv*/)
{
EGLint configAttribs[] = {
EGL_DEPTH_SIZE, 0,
diff --git a/opengl/tools/glgen/stubs/egl/EGL14cHeader.cpp b/opengl/tools/glgen/stubs/egl/EGL14cHeader.cpp
index f6813fd..66836b5 100644
--- a/opengl/tools/glgen/stubs/egl/EGL14cHeader.cpp
+++ b/opengl/tools/glgen/stubs/egl/EGL14cHeader.cpp
@@ -21,7 +21,7 @@
#pragma GCC diagnostic ignored "-Wunused-function"
#include "jni.h"
-#include "JNIHelp.h"
+#include <nativehelper/JNIHelp.h>
#include <android_runtime/AndroidRuntime.h>
#include <android_runtime/android_view_Surface.h>
#include <android_runtime/android_graphics_SurfaceTexture.h>
diff --git a/opengl/tools/glgen/stubs/egl/EGLExtcHeader.cpp b/opengl/tools/glgen/stubs/egl/EGLExtcHeader.cpp
index 4df61d3..fb75d81 100644
--- a/opengl/tools/glgen/stubs/egl/EGLExtcHeader.cpp
+++ b/opengl/tools/glgen/stubs/egl/EGLExtcHeader.cpp
@@ -21,7 +21,7 @@
#pragma GCC diagnostic ignored "-Wunused-function"
#include "jni.h"
-#include "JNIHelp.h"
+#include <nativehelper/JNIHelp.h>
#include <android_runtime/AndroidRuntime.h>
#include <android_runtime/android_view_Surface.h>
#include <android_runtime/android_graphics_SurfaceTexture.h>
diff --git a/opengl/tools/glgen/stubs/gles11/common.cpp b/opengl/tools/glgen/stubs/gles11/common.cpp
index 7062c57..2163d76 100644
--- a/opengl/tools/glgen/stubs/gles11/common.cpp
+++ b/opengl/tools/glgen/stubs/gles11/common.cpp
@@ -1,5 +1,5 @@
#include <jni.h>
-#include <JNIHelp.h>
+#include <nativehelper/JNIHelp.h>
#include <android_runtime/AndroidRuntime.h>
#include <utils/misc.h>
#include <assert.h>
diff --git a/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp b/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp
index 026cb37..03e16e9 100644
--- a/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp
+++ b/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp
@@ -21,7 +21,7 @@
#pragma GCC diagnostic ignored "-Wunused-function"
#include "jni.h"
-#include "JNIHelp.h"
+#include <nativehelper/JNIHelp.h>
#include <android_runtime/AndroidRuntime.h>
#include <utils/misc.h>
diff --git a/services/Android.bp b/services/Android.bp
deleted file mode 100644
index 7a8ee5d..0000000
--- a/services/Android.bp
+++ /dev/null
@@ -1 +0,0 @@
-subdirs = [ "*" ]
diff --git a/services/audiomanager/Android.bp b/services/audiomanager/Android.bp
index 22b084a..12ad47e 100644
--- a/services/audiomanager/Android.bp
+++ b/services/audiomanager/Android.bp
@@ -3,7 +3,6 @@
srcs: [
"IAudioManager.cpp",
- "IPlayer.cpp",
],
shared_libs: [
diff --git a/services/audiomanager/IPlayer.cpp b/services/audiomanager/IPlayer.cpp
deleted file mode 100644
index e8a9c34..0000000
--- a/services/audiomanager/IPlayer.cpp
+++ /dev/null
@@ -1,189 +0,0 @@
-/*
-**
-** 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.
-*/
-
-#define LOG_TAG "IPlayer"
-//#define LOG_NDEBUG 0
-#include <utils/Log.h>
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <binder/Parcel.h>
-
-#include <audiomanager/IPlayer.h>
-
-namespace android {
-
-enum {
- START = IBinder::FIRST_CALL_TRANSACTION,
- PAUSE = IBinder::FIRST_CALL_TRANSACTION + 1,
- STOP = IBinder::FIRST_CALL_TRANSACTION + 2,
- SET_VOLUME = IBinder::FIRST_CALL_TRANSACTION + 3,
- SET_PAN = IBinder::FIRST_CALL_TRANSACTION + 4,
- SET_START_DELAY_MS = IBinder::FIRST_CALL_TRANSACTION + 5,
- APPLY_VOLUME_SHAPER = IBinder::FIRST_CALL_TRANSACTION + 6,
-};
-
-class BpPlayer : public BpInterface<IPlayer>
-{
-public:
- explicit BpPlayer(const sp<IBinder>& impl)
- : BpInterface<IPlayer>(impl)
- {
- }
-
- virtual void start()
- {
- Parcel data, reply;
- data.writeInterfaceToken(IPlayer::getInterfaceDescriptor());
- remote()->transact(START, data, &reply);
- }
-
- virtual void pause()
- {
- Parcel data, reply;
- data.writeInterfaceToken(IPlayer::getInterfaceDescriptor());
- remote()->transact(PAUSE, data, &reply);
- }
-
- virtual void stop()
- {
- Parcel data, reply;
- data.writeInterfaceToken(IPlayer::getInterfaceDescriptor());
- remote()->transact(STOP, data, &reply);
- }
-
- virtual void setVolume(float vol)
- {
- Parcel data, reply;
- data.writeInterfaceToken(IPlayer::getInterfaceDescriptor());
- data.writeFloat(vol);
- remote()->transact(SET_VOLUME, data, &reply);
- }
-
- virtual void setPan(float pan)
- {
- Parcel data, reply;
- data.writeInterfaceToken(IPlayer::getInterfaceDescriptor());
- data.writeFloat(pan);
- remote()->transact(SET_PAN, data, &reply);
- }
-
- virtual void setStartDelayMs(int32_t delayMs) {
- Parcel data, reply;
- data.writeInterfaceToken(IPlayer::getInterfaceDescriptor());
- data.writeInt32(delayMs);
- remote()->transact(SET_START_DELAY_MS, data, &reply);
- }
-
- virtual void applyVolumeShaper(
- const sp<VolumeShaper::Configuration>& configuration,
- const sp<VolumeShaper::Operation>& operation) {
- Parcel data, reply;
- data.writeInterfaceToken(IPlayer::getInterfaceDescriptor());
-
- status_t status = configuration.get() == nullptr
- ? data.writeInt32(0)
- : data.writeInt32(1)
- ?: configuration->writeToParcel(&data);
- if (status != NO_ERROR) {
- ALOGW("applyVolumeShaper failed configuration parceling: %d", status);
- return; // ignore error
- }
-
- status = operation.get() == nullptr
- ? status = data.writeInt32(0)
- : data.writeInt32(1)
- ?: operation->writeToParcel(&data);
- if (status != NO_ERROR) {
- ALOGW("applyVolumeShaper failed operation parceling: %d", status);
- return; // ignore error
- }
-
- status = remote()->transact(APPLY_VOLUME_SHAPER, data, &reply);
-
- ALOGW_IF(status != NO_ERROR, "applyVolumeShaper failed transact: %d", status);
- return; // one way transaction, ignore error
- }
-};
-
-IMPLEMENT_META_INTERFACE(Player, "android.media.IPlayer");
-
-// ----------------------------------------------------------------------
-
-status_t BnPlayer::onTransact(
- uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
-{
- switch (code) {
- case START: {
- CHECK_INTERFACE(IPlayer, data, reply);
- start();
- return NO_ERROR;
- } break;
- case PAUSE: {
- CHECK_INTERFACE(IPlayer, data, reply);
- pause();
- return NO_ERROR;
- }
- case STOP: {
- CHECK_INTERFACE(IPlayer, data, reply);
- stop();
- return NO_ERROR;
- } break;
- case SET_VOLUME: {
- CHECK_INTERFACE(IPlayer, data, reply);
- setVolume(data.readFloat());
- return NO_ERROR;
- } break;
- case SET_PAN: {
- CHECK_INTERFACE(IPlayer, data, reply);
- setPan(data.readFloat());
- return NO_ERROR;
- } break;
- case SET_START_DELAY_MS: {
- CHECK_INTERFACE(IPlayer, data, reply);
- setStartDelayMs(data.readInt32());
- return NO_ERROR;
- } break;
- case APPLY_VOLUME_SHAPER: {
- CHECK_INTERFACE(IPlayer, data, reply);
- sp<VolumeShaper::Configuration> configuration;
- sp<VolumeShaper::Operation> operation;
-
- int32_t present;
- status_t status = data.readInt32(&present);
- if (status == NO_ERROR && present != 0) {
- configuration = new VolumeShaper::Configuration();
- status = configuration->readFromParcel(data);
- }
- status = status ?: data.readInt32(&present);
- if (status == NO_ERROR && present != 0) {
- operation = new VolumeShaper::Operation();
- status = operation->readFromParcel(data);
- }
- if (status == NO_ERROR) {
- // one way transaction, no error returned
- applyVolumeShaper(configuration, operation);
- }
- return NO_ERROR;
- } break;
- default:
- return BBinder::onTransact(code, data, reply, flags);
- }
-}
-
-} // namespace android
diff --git a/services/batteryservice/Android.bp b/services/batteryservice/Android.bp
index e441bda..186f399 100644
--- a/services/batteryservice/Android.bp
+++ b/services/batteryservice/Android.bp
@@ -1,22 +1,7 @@
-cc_library {
- name: "libbatteryservice",
-
- srcs: [
- "BatteryProperties.cpp",
- "BatteryProperty.cpp",
- "IBatteryPropertiesListener.cpp",
- "IBatteryPropertiesRegistrar.cpp",
- ],
-
- shared_libs: [
- "libutils",
- "libbinder",
- ],
-
- cflags: [
- "-Wall",
- "-Werror",
- "-Wunused",
- "-Wunreachable-code",
- ],
-}
\ No newline at end of file
+cc_library_headers {
+ name: "libbatteryservice_headers",
+ vendor_available: true,
+ export_include_dirs: ["include"],
+ header_libs: ["libbinder_headers"],
+ export_header_lib_headers: ["libbinder_headers"],
+}
diff --git a/services/batteryservice/BatteryProperties.cpp b/services/batteryservice/BatteryProperties.cpp
deleted file mode 100644
index 8fa111d..0000000
--- a/services/batteryservice/BatteryProperties.cpp
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2013 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 <stdint.h>
-#include <sys/types.h>
-#include <batteryservice/BatteryService.h>
-#include <binder/Parcel.h>
-#include <utils/Errors.h>
-#include <utils/String8.h>
-#include <utils/String16.h>
-
-namespace android {
-
-/*
- * Parcel read/write code must be kept in sync with
- * frameworks/base/core/java/android/os/BatteryProperties.java
- */
-
-status_t BatteryProperties::readFromParcel(Parcel* p) {
- chargerAcOnline = p->readInt32() == 1 ? true : false;
- chargerUsbOnline = p->readInt32() == 1 ? true : false;
- chargerWirelessOnline = p->readInt32() == 1 ? true : false;
- maxChargingCurrent = p->readInt32();
- maxChargingVoltage = p->readInt32();
- batteryStatus = p->readInt32();
- batteryHealth = p->readInt32();
- batteryPresent = p->readInt32() == 1 ? true : false;
- batteryLevel = p->readInt32();
- batteryVoltage = p->readInt32();
- batteryTemperature = p->readInt32();
- batteryFullCharge = p->readInt32();
- batteryChargeCounter = p->readInt32();
- batteryTechnology = String8((p->readString16()).string());
- return OK;
-}
-
-status_t BatteryProperties::writeToParcel(Parcel* p) const {
- p->writeInt32(chargerAcOnline ? 1 : 0);
- p->writeInt32(chargerUsbOnline ? 1 : 0);
- p->writeInt32(chargerWirelessOnline ? 1 : 0);
- p->writeInt32(maxChargingCurrent);
- p->writeInt32(maxChargingVoltage);
- p->writeInt32(batteryStatus);
- p->writeInt32(batteryHealth);
- p->writeInt32(batteryPresent ? 1 : 0);
- p->writeInt32(batteryLevel);
- p->writeInt32(batteryVoltage);
- p->writeInt32(batteryTemperature);
- p->writeInt32(batteryFullCharge);
- p->writeInt32(batteryChargeCounter);
- p->writeString16(String16(batteryTechnology));
- return OK;
-}
-
-}; // namespace android
diff --git a/services/batteryservice/BatteryProperty.cpp b/services/batteryservice/BatteryProperty.cpp
deleted file mode 100644
index 483d925..0000000
--- a/services/batteryservice/BatteryProperty.cpp
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2013 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 <stdint.h>
-#include <sys/types.h>
-#include <batteryservice/BatteryService.h>
-#include <binder/Parcel.h>
-#include <utils/Errors.h>
-
-namespace android {
-
-/*
- * Parcel read/write code must be kept in sync with
- * frameworks/base/core/java/android/os/BatteryProperty.java
- */
-
-status_t BatteryProperty::readFromParcel(Parcel* p) {
- valueInt64 = p->readInt64();
- return OK;
-}
-
-status_t BatteryProperty::writeToParcel(Parcel* p) const {
- p->writeInt64(valueInt64);
- return OK;
-}
-
-}; // namespace android
diff --git a/services/batteryservice/IBatteryPropertiesListener.cpp b/services/batteryservice/IBatteryPropertiesListener.cpp
deleted file mode 100644
index 6e5bcfe..0000000
--- a/services/batteryservice/IBatteryPropertiesListener.cpp
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (C) 2013 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 <stdint.h>
-#include <sys/types.h>
-#include <batteryservice/IBatteryPropertiesListener.h>
-#include <binder/Parcel.h>
-
-namespace android {
-
-class BpBatteryPropertiesListener : public BpInterface<IBatteryPropertiesListener>
-{
-public:
- explicit BpBatteryPropertiesListener(const sp<IBinder>& impl)
- : BpInterface<IBatteryPropertiesListener>(impl)
- {
- }
-
- void batteryPropertiesChanged(struct BatteryProperties props)
- {
- Parcel data, reply;
- data.writeInterfaceToken(IBatteryPropertiesListener::getInterfaceDescriptor());
- data.writeInt32(1);
- props.writeToParcel(&data);
- remote()->transact(TRANSACT_BATTERYPROPERTIESCHANGED, data, &reply, IBinder::FLAG_ONEWAY);
- }
-};
-
-IMPLEMENT_META_INTERFACE(BatteryPropertiesListener, "android.os.IBatteryPropertiesListener");
-
-// ----------------------------------------------------------------------------
-
-status_t BnBatteryPropertiesListener::onTransact(uint32_t code, const Parcel& data,
- Parcel* reply, uint32_t flags)
-{
- switch(code) {
- case TRANSACT_BATTERYPROPERTIESCHANGED: {
- CHECK_INTERFACE(IBatteryPropertiesListener, data, reply);
- struct BatteryProperties props = {};
- if (data.readInt32() != 0) {
- props.readFromParcel((Parcel*)&data);
- }
- batteryPropertiesChanged(props);
- return NO_ERROR;
- }
- default:
- return BBinder::onTransact(code, data, reply, flags);
- }
-};
-
-}; // namespace android
diff --git a/services/batteryservice/IBatteryPropertiesRegistrar.cpp b/services/batteryservice/IBatteryPropertiesRegistrar.cpp
deleted file mode 100644
index 01a65ae..0000000
--- a/services/batteryservice/IBatteryPropertiesRegistrar.cpp
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "IBatteryPropertiesRegistrar"
-//#define LOG_NDEBUG 0
-#include <utils/Log.h>
-
-#include <batteryservice/IBatteryPropertiesListener.h>
-#include <batteryservice/IBatteryPropertiesRegistrar.h>
-#include <stdint.h>
-#include <sys/types.h>
-#include <binder/Parcel.h>
-
-namespace android {
-
-class BpBatteryPropertiesRegistrar : public BpInterface<IBatteryPropertiesRegistrar> {
-public:
- explicit BpBatteryPropertiesRegistrar(const sp<IBinder>& impl)
- : BpInterface<IBatteryPropertiesRegistrar>(impl) {}
-
- void registerListener(const sp<IBatteryPropertiesListener>& listener) {
- Parcel data;
- data.writeInterfaceToken(IBatteryPropertiesRegistrar::getInterfaceDescriptor());
- data.writeStrongBinder(IInterface::asBinder(listener));
- remote()->transact(REGISTER_LISTENER, data, NULL);
- }
-
- void unregisterListener(const sp<IBatteryPropertiesListener>& listener) {
- Parcel data;
- data.writeInterfaceToken(IBatteryPropertiesRegistrar::getInterfaceDescriptor());
- data.writeStrongBinder(IInterface::asBinder(listener));
- remote()->transact(UNREGISTER_LISTENER, data, NULL);
- }
-
- status_t getProperty(int id, struct BatteryProperty *val) {
- Parcel data, reply;
- data.writeInterfaceToken(IBatteryPropertiesRegistrar::getInterfaceDescriptor());
- data.writeInt32(id);
- remote()->transact(GET_PROPERTY, data, &reply);
- int32_t ret = reply.readExceptionCode();
- if (ret != 0) {
- return ret;
- }
- ret = reply.readInt32();
- int parcelpresent = reply.readInt32();
- if (parcelpresent)
- val->readFromParcel(&reply);
- return ret;
- }
-
- void scheduleUpdate() {
- Parcel data;
- data.writeInterfaceToken(IBatteryPropertiesRegistrar::getInterfaceDescriptor());
- remote()->transact(SCHEDULE_UPDATE, data, NULL);
- }
-};
-
-IMPLEMENT_META_INTERFACE(BatteryPropertiesRegistrar, "android.os.IBatteryPropertiesRegistrar");
-
-status_t BnBatteryPropertiesRegistrar::onTransact(uint32_t code,
- const Parcel& data,
- Parcel* reply,
- uint32_t flags)
-{
- switch(code) {
- case REGISTER_LISTENER: {
- CHECK_INTERFACE(IBatteryPropertiesRegistrar, data, reply);
- sp<IBatteryPropertiesListener> listener =
- interface_cast<IBatteryPropertiesListener>(data.readStrongBinder());
- registerListener(listener);
- return OK;
- }
-
- case UNREGISTER_LISTENER: {
- CHECK_INTERFACE(IBatteryPropertiesRegistrar, data, reply);
- sp<IBatteryPropertiesListener> listener =
- interface_cast<IBatteryPropertiesListener>(data.readStrongBinder());
- unregisterListener(listener);
- return OK;
- }
-
- case GET_PROPERTY: {
- CHECK_INTERFACE(IBatteryPropertiesRegistrar, data, reply);
- int id = data.readInt32();
- struct BatteryProperty val;
- status_t result = getProperty(id, &val);
- reply->writeNoException();
- reply->writeInt32(result);
- reply->writeInt32(1);
- val.writeToParcel(reply);
- return OK;
- }
-
- case SCHEDULE_UPDATE: {
- CHECK_INTERFACE(IBatteryPropertiesRegistrar, data, reply);
- scheduleUpdate();
- return OK;
- }
- }
- return BBinder::onTransact(code, data, reply, flags);
-};
-
-// ----------------------------------------------------------------------------
-
-}; // namespace android
diff --git a/include/batteryservice/BatteryService.h b/services/batteryservice/include/batteryservice/BatteryService.h
similarity index 100%
rename from include/batteryservice/BatteryService.h
rename to services/batteryservice/include/batteryservice/BatteryService.h
diff --git a/include/batteryservice/BatteryServiceConstants.h b/services/batteryservice/include/batteryservice/BatteryServiceConstants.h
similarity index 100%
rename from include/batteryservice/BatteryServiceConstants.h
rename to services/batteryservice/include/batteryservice/BatteryServiceConstants.h
diff --git a/include/batteryservice/IBatteryPropertiesListener.h b/services/batteryservice/include/batteryservice/IBatteryPropertiesListener.h
similarity index 100%
rename from include/batteryservice/IBatteryPropertiesListener.h
rename to services/batteryservice/include/batteryservice/IBatteryPropertiesListener.h
diff --git a/include/batteryservice/IBatteryPropertiesRegistrar.h b/services/batteryservice/include/batteryservice/IBatteryPropertiesRegistrar.h
similarity index 100%
rename from include/batteryservice/IBatteryPropertiesRegistrar.h
rename to services/batteryservice/include/batteryservice/IBatteryPropertiesRegistrar.h
diff --git a/services/inputflinger/Android.bp b/services/inputflinger/Android.bp
index 4fd98e2..238cba3 100644
--- a/services/inputflinger/Android.bp
+++ b/services/inputflinger/Android.bp
@@ -37,6 +37,9 @@
],
cflags: [
+ "-Wall",
+ "-Wextra",
+ "-Werror",
"-Wno-unused-parameter",
// TODO: Move inputflinger to its own process and mark it hidden
//-fvisibility=hidden
diff --git a/services/inputflinger/EventHub.cpp b/services/inputflinger/EventHub.cpp
index 50589b4..99fe0f5 100644
--- a/services/inputflinger/EventHub.cpp
+++ b/services/inputflinger/EventHub.cpp
@@ -69,12 +69,6 @@
static const char *WAKE_LOCK_ID = "KeyEvents";
static const char *DEVICE_PATH = "/dev/input";
-/* return the larger integer */
-static inline int max(int v1, int v2)
-{
- return (v1 > v2) ? v1 : v2;
-}
-
static inline const char* toString(bool value) {
return value ? "true" : "false";
}
diff --git a/services/inputflinger/InputDispatcher.cpp b/services/inputflinger/InputDispatcher.cpp
index 2efb340..906794a 100644
--- a/services/inputflinger/InputDispatcher.cpp
+++ b/services/inputflinger/InputDispatcher.cpp
@@ -685,7 +685,7 @@
bool InputDispatcher::dispatchConfigurationChangedLocked(
nsecs_t currentTime, ConfigurationChangedEntry* entry) {
#if DEBUG_OUTBOUND_EVENT_DETAILS
- ALOGD("dispatchConfigurationChanged - eventTime=%lld", entry->eventTime);
+ ALOGD("dispatchConfigurationChanged - eventTime=%" PRId64, entry->eventTime);
#endif
// Reset key repeating in case a keyboard device was added or removed or something.
@@ -701,7 +701,8 @@
bool InputDispatcher::dispatchDeviceResetLocked(
nsecs_t currentTime, DeviceResetEntry* entry) {
#if DEBUG_OUTBOUND_EVENT_DETAILS
- ALOGD("dispatchDeviceReset - eventTime=%lld, deviceId=%d", entry->eventTime, entry->deviceId);
+ ALOGD("dispatchDeviceReset - eventTime=%" PRId64 ", deviceId=%d", entry->eventTime,
+ entry->deviceId);
#endif
CancelationOptions options(CancelationOptions::CANCEL_ALL_EVENTS,
@@ -811,9 +812,9 @@
void InputDispatcher::logOutboundKeyDetailsLocked(const char* prefix, const KeyEntry* entry) {
#if DEBUG_OUTBOUND_EVENT_DETAILS
- ALOGD("%seventTime=%lld, deviceId=%d, source=0x%x, policyFlags=0x%x, "
+ ALOGD("%seventTime=%" PRId64 ", deviceId=%d, source=0x%x, policyFlags=0x%x, "
"action=0x%x, flags=0x%x, keyCode=0x%x, scanCode=0x%x, metaState=0x%x, "
- "repeatCount=%d, downTime=%lld",
+ "repeatCount=%d, downTime=%" PRId64,
prefix,
entry->eventTime, entry->deviceId, entry->source, entry->policyFlags,
entry->action, entry->flags, entry->keyCode, entry->scanCode, entry->metaState,
@@ -869,10 +870,7 @@
return true;
}
- // TODO: support sending secondary display events to input monitors
- if (isMainDisplay(entry->displayId)) {
- addMonitoringTargetsLocked(inputTargets);
- }
+ addMonitoringTargetsLocked(inputTargets);
// Dispatch the motion.
if (conflictingPointerActions) {
@@ -887,10 +885,10 @@
void InputDispatcher::logOutboundMotionDetailsLocked(const char* prefix, const MotionEntry* entry) {
#if DEBUG_OUTBOUND_EVENT_DETAILS
- ALOGD("%seventTime=%lld, deviceId=%d, source=0x%x, policyFlags=0x%x, "
+ ALOGD("%seventTime=%" PRId64 ", deviceId=%d, source=0x%x, policyFlags=0x%x, "
"action=0x%x, actionButton=0x%x, flags=0x%x, "
"metaState=0x%x, buttonState=0x%x,"
- "edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, downTime=%lld",
+ "edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, downTime=%" PRId64,
prefix,
entry->eventTime, entry->deviceId, entry->source, entry->policyFlags,
entry->action, entry->actionButton, entry->flags,
@@ -1135,8 +1133,6 @@
INJECTION_PERMISSION_DENIED
};
- nsecs_t startTime = now();
-
// For security reasons, we defer updating the touch state until we are sure that
// event injection will be allowed.
int32_t displayId = entry->displayId;
@@ -1997,10 +1993,10 @@
const PointerCoords* usingCoords = motionEntry->pointerCoords;
// Set the X and Y offset depending on the input source.
- float xOffset, yOffset, scaleFactor;
+ float xOffset, yOffset;
if ((motionEntry->source & AINPUT_SOURCE_CLASS_POINTER)
&& !(dispatchEntry->targetFlags & InputTarget::FLAG_ZERO_COORDS)) {
- scaleFactor = dispatchEntry->scaleFactor;
+ float scaleFactor = dispatchEntry->scaleFactor;
xOffset = dispatchEntry->xOffset * scaleFactor;
yOffset = dispatchEntry->yOffset * scaleFactor;
if (scaleFactor != 1.0f) {
@@ -2013,7 +2009,6 @@
} else {
xOffset = 0.0f;
yOffset = 0.0f;
- scaleFactor = 1.0f;
// We don't want the dispatch target to know.
if (dispatchEntry->targetFlags & InputTarget::FLAG_ZERO_COORDS) {
@@ -2026,7 +2021,7 @@
// Publish the motion event.
status = connection->inputPublisher.publishMotionEvent(dispatchEntry->seq,
- motionEntry->deviceId, motionEntry->source,
+ motionEntry->deviceId, motionEntry->source, motionEntry->displayId,
dispatchEntry->resolvedAction, motionEntry->actionButton,
dispatchEntry->resolvedFlags, motionEntry->edgeFlags,
motionEntry->metaState, motionEntry->buttonState,
@@ -2236,7 +2231,7 @@
if (!cancelationEvents.isEmpty()) {
#if DEBUG_OUTBOUND_EVENT_DETAILS
- ALOGD("channel '%s' ~ Synthesized %d cancelation events to bring channel back in sync "
+ ALOGD("channel '%s' ~ Synthesized %zu cancelation events to bring channel back in sync "
"with reality: %s, mode=%d.",
connection->getInputChannelName(), cancelationEvents.size(),
options.reason, options.mode);
@@ -2372,7 +2367,7 @@
void InputDispatcher::notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) {
#if DEBUG_INBOUND_EVENT_DETAILS
- ALOGD("notifyConfigurationChanged - eventTime=%lld", args->eventTime);
+ ALOGD("notifyConfigurationChanged - eventTime=%" PRId64, args->eventTime);
#endif
bool needWake;
@@ -2390,8 +2385,9 @@
void InputDispatcher::notifyKey(const NotifyKeyArgs* args) {
#if DEBUG_INBOUND_EVENT_DETAILS
- ALOGD("notifyKey - eventTime=%lld, deviceId=%d, source=0x%x, policyFlags=0x%x, action=0x%x, "
- "flags=0x%x, keyCode=0x%x, scanCode=0x%x, metaState=0x%x, downTime=%lld",
+ ALOGD("notifyKey - eventTime=%" PRId64
+ ", deviceId=%d, source=0x%x, policyFlags=0x%x, action=0x%x, "
+ "flags=0x%x, keyCode=0x%x, scanCode=0x%x, metaState=0x%x, downTime=%" PRId64,
args->eventTime, args->deviceId, args->source, args->policyFlags,
args->action, args->flags, args->keyCode, args->scanCode,
args->metaState, args->downTime);
@@ -2485,9 +2481,9 @@
void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) {
#if DEBUG_INBOUND_EVENT_DETAILS
- ALOGD("notifyMotion - eventTime=%lld, deviceId=%d, source=0x%x, policyFlags=0x%x, "
+ ALOGD("notifyMotion - eventTime=%" PRId64 ", deviceId=%d, source=0x%x, policyFlags=0x%x, "
"action=0x%x, actionButton=0x%x, flags=0x%x, metaState=0x%x, buttonState=0x%x,"
- "edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, downTime=%lld",
+ "edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, downTime=%" PRId64,
args->eventTime, args->deviceId, args->source, args->policyFlags,
args->action, args->actionButton, args->flags, args->metaState, args->buttonState,
args->edgeFlags, args->xPrecision, args->yPrecision, args->downTime);
@@ -2565,9 +2561,9 @@
void InputDispatcher::notifySwitch(const NotifySwitchArgs* args) {
#if DEBUG_INBOUND_EVENT_DETAILS
- ALOGD("notifySwitch - eventTime=%lld, policyFlags=0x%x, switchValues=0x%08x, switchMask=0x%08x",
- args->eventTime, args->policyFlags,
- args->switchValues, args->switchMask);
+ ALOGD("notifySwitch - eventTime=%" PRId64 ", policyFlags=0x%x, switchValues=0x%08x, "
+ "switchMask=0x%08x",
+ args->eventTime, args->policyFlags, args->switchValues, args->switchMask);
#endif
uint32_t policyFlags = args->policyFlags;
@@ -2578,7 +2574,7 @@
void InputDispatcher::notifyDeviceReset(const NotifyDeviceResetArgs* args) {
#if DEBUG_INBOUND_EVENT_DETAILS
- ALOGD("notifyDeviceReset - eventTime=%lld, deviceId=%d",
+ ALOGD("notifyDeviceReset - eventTime=%" PRId64 ", deviceId=%d",
args->eventTime, args->deviceId);
#endif
@@ -2600,8 +2596,9 @@
uint32_t policyFlags) {
#if DEBUG_INBOUND_EVENT_DETAILS
ALOGD("injectInputEvent - eventType=%d, injectorPid=%d, injectorUid=%d, "
- "syncMode=%d, timeoutMillis=%d, policyFlags=0x%08x",
- event->getType(), injectorPid, injectorUid, syncMode, timeoutMillis, policyFlags);
+ "syncMode=%d, timeoutMillis=%d, policyFlags=0x%08x, displayId=%d",
+ event->getType(), injectorPid, injectorUid, syncMode, timeoutMillis, policyFlags,
+ displayId);
#endif
nsecs_t endTime = now() + milliseconds_to_nanoseconds(timeoutMillis);
@@ -3745,7 +3742,7 @@
msg.appendFormat(", %d->%d", fallbackKeys.keyAt(i),
fallbackKeys.valueAt(i));
}
- ALOGD("Unhandled key event: %d currently tracked fallback keys%s.",
+ ALOGD("Unhandled key event: %zu currently tracked fallback keys%s.",
fallbackKeys.size(), msg.string());
}
#endif
diff --git a/services/inputflinger/InputReader.cpp b/services/inputflinger/InputReader.cpp
index 97565aa..4304982 100644
--- a/services/inputflinger/InputReader.cpp
+++ b/services/inputflinger/InputReader.cpp
@@ -147,7 +147,33 @@
static const size_t keyCodeRotationMapSize =
sizeof(keyCodeRotationMap) / sizeof(keyCodeRotationMap[0]);
+static int32_t rotateStemKey(int32_t value, int32_t orientation,
+ const int32_t map[][2], size_t mapSize) {
+ if (orientation == DISPLAY_ORIENTATION_180) {
+ for (size_t i = 0; i < mapSize; i++) {
+ if (value == map[i][0]) {
+ return map[i][1];
+ }
+ }
+ }
+ return value;
+}
+
+// The mapping can be defined using input device configuration properties keyboard.rotated.stem_X
+static int32_t stemKeyRotationMap[][2] = {
+ // key codes enumerated with the original (unrotated) key first
+ // no rotation, 180 degree rotation
+ { AKEYCODE_STEM_PRIMARY, AKEYCODE_STEM_PRIMARY },
+ { AKEYCODE_STEM_1, AKEYCODE_STEM_1 },
+ { AKEYCODE_STEM_2, AKEYCODE_STEM_2 },
+ { AKEYCODE_STEM_3, AKEYCODE_STEM_3 },
+};
+static const size_t stemKeyRotationMapSize =
+ sizeof(stemKeyRotationMap) / sizeof(stemKeyRotationMap[0]);
+
static int32_t rotateKeyCode(int32_t keyCode, int32_t orientation) {
+ keyCode = rotateStemKey(keyCode, orientation,
+ stemKeyRotationMap, stemKeyRotationMapSize);
return rotateValueUsingRotationMap(keyCode, orientation,
keyCodeRotationMap, keyCodeRotationMapSize);
}
@@ -231,7 +257,7 @@
const String8* uniqueDisplayId, DisplayViewport* outViewport) const {
const DisplayViewport* viewport = NULL;
if (viewportType == ViewportType::VIEWPORT_VIRTUAL && uniqueDisplayId != NULL) {
- for (DisplayViewport currentViewport : mVirtualDisplays) {
+ for (const DisplayViewport& currentViewport : mVirtualDisplays) {
if (currentViewport.uniqueId == *uniqueDisplayId) {
viewport = ¤tViewport;
break;
@@ -403,7 +429,7 @@
batchSize += 1;
}
#if DEBUG_RAW_EVENTS
- ALOGD("BatchSize: %d Count: %d", batchSize, count);
+ ALOGD("BatchSize: %zu Count: %zu", batchSize, count);
#endif
processEventsForDeviceLocked(deviceId, rawEvent, batchSize);
} else {
@@ -1150,7 +1176,7 @@
size_t numMappers = mMappers.size();
for (const RawEvent* rawEvent = rawEvents; count--; rawEvent++) {
#if DEBUG_RAW_EVENTS
- ALOGD("Input event: device=%d type=0x%04x code=0x%04x value=0x%08x when=%lld",
+ ALOGD("Input event: device=%d type=0x%04x code=0x%04x value=0x%08x when=%" PRId64,
rawEvent->deviceId, rawEvent->type, rawEvent->code, rawEvent->value,
rawEvent->when);
#endif
@@ -1825,7 +1851,7 @@
#if DEBUG_POINTERS
if (newSlot) {
ALOGW("MultiTouch device emitted invalid slot index %d but it "
- "should be between 0 and %d; ignoring this slot.",
+ "should be between 0 and %zd; ignoring this slot.",
mCurrentSlot, mSlotCount - 1);
}
#endif
@@ -2121,9 +2147,9 @@
if (i != 0) {
patternStr.append(", ");
}
- patternStr.appendFormat("%lld", pattern[i]);
+ patternStr.appendFormat("%" PRId64, pattern[i]);
}
- ALOGD("vibrate: deviceId=%d, pattern=[%s], repeat=%ld, token=%d",
+ ALOGD("vibrate: deviceId=%d, pattern=[%s], repeat=%zd, token=%d",
getDeviceId(), patternStr.string(), repeat, token);
#endif
@@ -2172,8 +2198,7 @@
nsecs_t duration = mPattern[mIndex];
if (vibratorOn) {
#if DEBUG_VIBRATOR
- ALOGD("nextStep: sending vibrate deviceId=%d, duration=%lld",
- getDeviceId(), duration);
+ ALOGD("nextStep: sending vibrate deviceId=%d, duration=%" PRId64, getDeviceId(), duration);
#endif
getEventHub()->vibrate(getDeviceId(), duration);
} else {
@@ -2233,7 +2258,7 @@
dump.appendFormat(INDENT3 "Orientation: %d\n", mOrientation);
dump.appendFormat(INDENT3 "KeyDowns: %zu keys currently down\n", mKeyDowns.size());
dump.appendFormat(INDENT3 "MetaState: 0x%0x\n", mMetaState);
- dump.appendFormat(INDENT3 "DownTime: %lld\n", (long long)mDownTime);
+ dump.appendFormat(INDENT3 "DownTime: %" PRId64 "\n", mDownTime);
}
@@ -2260,18 +2285,36 @@
}
}
+static void mapStemKey(int32_t keyCode, const PropertyMap& config, char const *property) {
+ int32_t mapped = 0;
+ if (config.tryGetProperty(String8(property), mapped) && mapped > 0) {
+ for (size_t i = 0; i < stemKeyRotationMapSize; i++) {
+ if (stemKeyRotationMap[i][0] == keyCode) {
+ stemKeyRotationMap[i][1] = mapped;
+ return;
+ }
+ }
+ }
+}
+
void KeyboardInputMapper::configureParameters() {
mParameters.orientationAware = false;
- getDevice()->getConfiguration().tryGetProperty(String8("keyboard.orientationAware"),
+ const PropertyMap& config = getDevice()->getConfiguration();
+ config.tryGetProperty(String8("keyboard.orientationAware"),
mParameters.orientationAware);
mParameters.hasAssociatedDisplay = false;
if (mParameters.orientationAware) {
mParameters.hasAssociatedDisplay = true;
+
+ mapStemKey(AKEYCODE_STEM_PRIMARY, config, "keyboard.rotated.stem_primary");
+ mapStemKey(AKEYCODE_STEM_1, config, "keyboard.rotated.stem_1");
+ mapStemKey(AKEYCODE_STEM_2, config, "keyboard.rotated.stem_2");
+ mapStemKey(AKEYCODE_STEM_3, config, "keyboard.rotated.stem_3");
}
mParameters.handlesKeyRepeat = false;
- getDevice()->getConfiguration().tryGetProperty(String8("keyboard.handlesKeyRepeat"),
+ config.tryGetProperty(String8("keyboard.handlesKeyRepeat"),
mParameters.handlesKeyRepeat);
}
@@ -2329,6 +2372,35 @@
|| (scanCode >= BTN_JOYSTICK && scanCode < BTN_DIGI);
}
+bool KeyboardInputMapper::isMediaKey(int32_t keyCode) {
+ switch (keyCode) {
+ case AKEYCODE_MEDIA_PLAY:
+ case AKEYCODE_MEDIA_PAUSE:
+ case AKEYCODE_MEDIA_PLAY_PAUSE:
+ case AKEYCODE_MUTE:
+ case AKEYCODE_HEADSETHOOK:
+ case AKEYCODE_MEDIA_STOP:
+ case AKEYCODE_MEDIA_NEXT:
+ case AKEYCODE_MEDIA_PREVIOUS:
+ case AKEYCODE_MEDIA_REWIND:
+ case AKEYCODE_MEDIA_RECORD:
+ case AKEYCODE_MEDIA_FAST_FORWARD:
+ case AKEYCODE_MEDIA_SKIP_FORWARD:
+ case AKEYCODE_MEDIA_SKIP_BACKWARD:
+ case AKEYCODE_MEDIA_STEP_FORWARD:
+ case AKEYCODE_MEDIA_STEP_BACKWARD:
+ case AKEYCODE_MEDIA_AUDIO_TRACK:
+ case AKEYCODE_VOLUME_UP:
+ case AKEYCODE_VOLUME_DOWN:
+ case AKEYCODE_VOLUME_MUTE:
+ case AKEYCODE_TV_AUDIO_DESCRIPTION:
+ case AKEYCODE_TV_AUDIO_DESCRIPTION_MIX_UP:
+ case AKEYCODE_TV_AUDIO_DESCRIPTION_MIX_DOWN:
+ return true;
+ }
+ return false;
+}
+
void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t scanCode,
int32_t usageCode) {
int32_t keyCode;
@@ -2402,7 +2474,7 @@
// For internal keyboards, the key layout file should specify the policy flags for
// each wake key individually.
// TODO: Use the input device configuration to control this behavior more finely.
- if (down && getDevice()->isExternal()) {
+ if (down && getDevice()->isExternal() && !isMediaKey(keyCode)) {
policyFlags |= POLICY_FLAG_WAKE;
}
@@ -2547,7 +2619,7 @@
dump.appendFormat(INDENT3 "Orientation: %d\n", mOrientation);
dump.appendFormat(INDENT3 "ButtonState: 0x%08x\n", mButtonState);
dump.appendFormat(INDENT3 "Down: %s\n", toString(isPointerDown(mButtonState)));
- dump.appendFormat(INDENT3 "DownTime: %lld\n", (long long)mDownTime);
+ dump.appendFormat(INDENT3 "DownTime: %" PRId64 "\n", mDownTime);
}
void CursorInputMapper::configure(nsecs_t when,
@@ -2897,7 +2969,7 @@
// --- RotaryEncoderInputMapper ---
RotaryEncoderInputMapper::RotaryEncoderInputMapper(InputDevice* device) :
- InputMapper(device) {
+ InputMapper(device), mOrientation(DISPLAY_ORIENTATION_0) {
mSource = AINPUT_SOURCE_ROTARY_ENCODER;
}
@@ -2939,6 +3011,14 @@
if (!changes) {
mRotaryEncoderScrollAccumulator.configure(getDevice());
}
+ if (!changes || (InputReaderConfiguration::CHANGE_DISPLAY_INFO)) {
+ DisplayViewport v;
+ if (config->getDisplayViewport(ViewportType::VIEWPORT_INTERNAL, NULL, &v)) {
+ mOrientation = v.orientation;
+ } else {
+ mOrientation = DISPLAY_ORIENTATION_0;
+ }
+ }
}
void RotaryEncoderInputMapper::reset(nsecs_t when) {
@@ -2976,6 +3056,10 @@
policyFlags |= POLICY_FLAG_WAKE;
}
+ if (mOrientation == DISPLAY_ORIENTATION_180) {
+ scroll = -scroll;
+ }
+
// Send motion event.
if (scrolled) {
int32_t metaState = mContext->getGlobalMetaState();
@@ -5424,18 +5508,15 @@
// Otherwise choose an arbitrary remaining pointer.
// This guarantees we always have an active touch id when there is at least one pointer.
// We keep the same active touch id for as long as possible.
- bool activeTouchChanged = false;
int32_t lastActiveTouchId = mPointerGesture.activeTouchId;
int32_t activeTouchId = lastActiveTouchId;
if (activeTouchId < 0) {
if (!mCurrentCookedState.fingerIdBits.isEmpty()) {
- activeTouchChanged = true;
activeTouchId = mPointerGesture.activeTouchId =
mCurrentCookedState.fingerIdBits.firstMarkedBit();
mPointerGesture.firstTouchTime = when;
}
} else if (!mCurrentCookedState.fingerIdBits.hasBit(activeTouchId)) {
- activeTouchChanged = true;
if (!mCurrentCookedState.fingerIdBits.isEmpty()) {
activeTouchId = mPointerGesture.activeTouchId =
mCurrentCookedState.fingerIdBits.firstMarkedBit();
@@ -5531,7 +5612,6 @@
}
if (bestId >= 0 && bestId != activeTouchId) {
mPointerGesture.activeTouchId = activeTouchId = bestId;
- activeTouchChanged = true;
#if DEBUG_GESTURES
ALOGD("Gestures: BUTTON_CLICK_OR_DRAG switched pointers, "
"bestId=%d, bestSpeed=%0.3f", bestId, bestSpeed);
@@ -6546,7 +6626,7 @@
#if DEBUG_POINTER_ASSIGNMENT
ALOGD("assignPointerIds - initial distance min-heap: size=%d", heapSize);
for (size_t i = 0; i < heapSize; i++) {
- ALOGD(" heap[%d]: cur=%d, last=%d, distance=%lld",
+ ALOGD(" heap[%zu]: cur=%" PRIu32 ", last=%" PRIu32 ", distance=%" PRIu64,
i, heap[i].currentPointerIndex, heap[i].lastPointerIndex,
heap[i].distance);
}
@@ -6592,7 +6672,7 @@
#if DEBUG_POINTER_ASSIGNMENT
ALOGD("assignPointerIds - reduced distance min-heap: size=%d", heapSize);
for (size_t i = 0; i < heapSize; i++) {
- ALOGD(" heap[%d]: cur=%d, last=%d, distance=%lld",
+ ALOGD(" heap[%zu]: cur=%" PRIu32 ", last=%" PRIu32 ", distance=%" PRIu64,
i, heap[i].currentPointerIndex, heap[i].lastPointerIndex,
heap[i].distance);
}
@@ -6618,7 +6698,8 @@
usedIdBits.markBit(id);
#if DEBUG_POINTER_ASSIGNMENT
- ALOGD("assignPointerIds - matched: cur=%d, last=%d, id=%d, distance=%lld",
+ ALOGD("assignPointerIds - matched: cur=%" PRIu32 ", last=%" PRIu32
+ ", id=%" PRIu32 ", distance=%" PRIu64,
lastPointerIndex, currentPointerIndex, id, heap[0].distance);
#endif
break;
@@ -6636,8 +6717,7 @@
current->rawPointerData.isHovering(currentPointerIndex));
#if DEBUG_POINTER_ASSIGNMENT
- ALOGD("assignPointerIds - assigned: cur=%d, id=%d",
- currentPointerIndex, id);
+ ALOGD("assignPointerIds - assigned: cur=%" PRIu32 ", id=%" PRIu32, currentPointerIndex, id);
#endif
}
}
diff --git a/services/inputflinger/InputReader.h b/services/inputflinger/InputReader.h
index 157fa4f..a6b9798 100644
--- a/services/inputflinger/InputReader.h
+++ b/services/inputflinger/InputReader.h
@@ -1128,6 +1128,7 @@
void dumpParameters(String8& dump);
bool isKeyboardOrGamepadKey(int32_t scanCode);
+ bool isMediaKey(int32_t keyCode);
void processKey(nsecs_t when, bool down, int32_t scanCode, int32_t usageCode);
@@ -1226,6 +1227,7 @@
int32_t mSource;
float mScalingFactor;
+ int32_t mOrientation;
void sync(nsecs_t when);
};
diff --git a/services/inputflinger/InputWindow.cpp b/services/inputflinger/InputWindow.cpp
index 5e82d75..3ae7972 100644
--- a/services/inputflinger/InputWindow.cpp
+++ b/services/inputflinger/InputWindow.cpp
@@ -46,8 +46,11 @@
|| layoutParamsType == TYPE_MAGNIFICATION_OVERLAY
|| layoutParamsType == TYPE_STATUS_BAR
|| layoutParamsType == TYPE_NAVIGATION_BAR
+ || layoutParamsType == TYPE_NAVIGATION_BAR_PANEL
|| layoutParamsType == TYPE_SECURE_SYSTEM_OVERLAY
- || layoutParamsType == TYPE_DOCK_DIVIDER;
+ || layoutParamsType == TYPE_DOCK_DIVIDER
+ || layoutParamsType == TYPE_ACCESSIBILITY_OVERLAY
+ || layoutParamsType == TYPE_INPUT_CONSUMER;
}
bool InputWindowInfo::supportsSplitTouch() const {
diff --git a/services/inputflinger/InputWindow.h b/services/inputflinger/InputWindow.h
index feca6cf..9eb2798 100644
--- a/services/inputflinger/InputWindow.h
+++ b/services/inputflinger/InputWindow.h
@@ -101,7 +101,10 @@
TYPE_NAVIGATION_BAR = FIRST_SYSTEM_WINDOW+19,
TYPE_VOLUME_OVERLAY = FIRST_SYSTEM_WINDOW+20,
TYPE_BOOT_PROGRESS = FIRST_SYSTEM_WINDOW+21,
- TYPE_MAGNIFICATION_OVERLAY = FIRST_SYSTEM_WINDOW+22,
+ TYPE_INPUT_CONSUMER = FIRST_SYSTEM_WINDOW+22,
+ TYPE_NAVIGATION_BAR_PANEL = FIRST_SYSTEM_WINDOW+24,
+ TYPE_MAGNIFICATION_OVERLAY = FIRST_SYSTEM_WINDOW+27,
+ TYPE_ACCESSIBILITY_OVERLAY = FIRST_SYSTEM_WINDOW+32,
TYPE_DOCK_DIVIDER = FIRST_SYSTEM_WINDOW+34,
LAST_SYSTEM_WINDOW = 2999,
};
diff --git a/services/inputflinger/host/Android.bp b/services/inputflinger/host/Android.bp
index b8e9bce..775dbdc 100644
--- a/services/inputflinger/host/Android.bp
+++ b/services/inputflinger/host/Android.bp
@@ -32,6 +32,8 @@
],
cflags: [
+ "-Wall",
+ "-Werror",
"-Wno-unused-parameter",
// TODO: Move inputflinger to its own process and mark it hidden
//-fvisibility=hidden
@@ -47,6 +49,8 @@
srcs: ["main.cpp"],
+ cflags: ["-Wall", "-Werror"],
+
shared_libs: [
"libbinder",
"libinputflingerhost",
diff --git a/services/inputflinger/tests/Android.bp b/services/inputflinger/tests/Android.bp
index 29d93f0..8a35509 100644
--- a/services/inputflinger/tests/Android.bp
+++ b/services/inputflinger/tests/Android.bp
@@ -7,7 +7,11 @@
"InputDispatcher_test.cpp",
],
test_per_src: true,
- cflags: ["-Wno-unused-parameter"],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wno-unused-parameter",
+ ],
shared_libs = [
"libcutils",
"liblog",
@@ -15,7 +19,6 @@
"libhardware",
"libhardware_legacy",
"libui",
- "libskia",
"libinput",
"libinputflinger",
"libinputservice",
diff --git a/services/schedulerservice/Android.bp b/services/schedulerservice/Android.bp
index ca91b8e..0227164 100644
--- a/services/schedulerservice/Android.bp
+++ b/services/schedulerservice/Android.bp
@@ -3,6 +3,7 @@
srcs: [
"SchedulingPolicyService.cpp",
],
+ cflags: ["-Wall", "-Werror"],
shared_libs: [
"libhidlbase",
"libhidltransport",
diff --git a/services/schedulerservice/SchedulingPolicyService.cpp b/services/schedulerservice/SchedulingPolicyService.cpp
index 1f6ed57..a1106cf 100644
--- a/services/schedulerservice/SchedulingPolicyService.cpp
+++ b/services/schedulerservice/SchedulingPolicyService.cpp
@@ -17,6 +17,8 @@
#include "SchedulingPolicyService.h"
+#include <private/android_filesystem_config.h> // for AID_CAMERASERVER
+
#include <log/log.h>
#include <hwbinder/IPCThreadState.h>
#include <mediautils/SchedulingPolicyService.h>
@@ -28,8 +30,9 @@
namespace implementation {
bool SchedulingPolicyService::isAllowed() {
- // TODO(b/37291237)
- return true;
+ using ::android::hardware::IPCThreadState;
+
+ return IPCThreadState::self()->getCallingUid() == AID_CAMERASERVER;
}
Return<bool> SchedulingPolicyService::requestPriority(int32_t pid, int32_t tid, int32_t priority) {
diff --git a/services/sensorservice/Android.bp b/services/sensorservice/Android.bp
index 8d381b1..a7f3a52 100644
--- a/services/sensorservice/Android.bp
+++ b/services/sensorservice/Android.bp
@@ -14,6 +14,7 @@
"RecentEventLogger.cpp",
"RotationVectorSensor.cpp",
"SensorDevice.cpp",
+ "SensorDeviceUtils.cpp",
"SensorDirectConnection.cpp",
"SensorEventConnection.cpp",
"SensorFusion.cpp",
diff --git a/services/sensorservice/BatteryService.cpp b/services/sensorservice/BatteryService.cpp
index 452c8c6..330861d 100644
--- a/services/sensorservice/BatteryService.cpp
+++ b/services/sensorservice/BatteryService.cpp
@@ -78,12 +78,13 @@
if (checkService()) {
Mutex::Autolock _l(mActivationsLock);
int64_t identity = IPCThreadState::self()->clearCallingIdentity();
- for (size_t i=0 ; i<mActivations.size() ; i++) {
+ for (size_t i=0 ; i<mActivations.size() ; ) {
const Info& info(mActivations[i]);
if (info.uid == uid) {
mBatteryStatService->noteStopSensor(info.uid, info.handle);
mActivations.removeAt(i);
- i--;
+ } else {
+ i++;
}
}
IPCThreadState::self()->restoreCallingIdentity(identity);
@@ -105,4 +106,3 @@
// ---------------------------------------------------------------------------
}; // namespace android
-
diff --git a/services/sensorservice/OWNERS b/services/sensorservice/OWNERS
new file mode 100644
index 0000000..6a38a1f
--- /dev/null
+++ b/services/sensorservice/OWNERS
@@ -0,0 +1,2 @@
+ashutoshj@google.com
+pengxu@google.com
diff --git a/services/sensorservice/SensorDevice.cpp b/services/sensorservice/SensorDevice.cpp
index 7d9b0b7..fdb69d3 100644
--- a/services/sensorservice/SensorDevice.cpp
+++ b/services/sensorservice/SensorDevice.cpp
@@ -26,11 +26,10 @@
#include <cinttypes>
#include <thread>
-using android::hardware::hidl_vec;
-
using namespace android::hardware::sensors::V1_0;
using namespace android::hardware::sensors::V1_0::implementation;
-
+using android::hardware::hidl_vec;
+using android::SensorDeviceUtils::HidlServiceRegistrationWaiter;
namespace android {
// ---------------------------------------------------------------------------
@@ -52,7 +51,8 @@
}
}
-SensorDevice::SensorDevice() : mHidlTransportErrors(20) {
+SensorDevice::SensorDevice()
+ : mHidlTransportErrors(20), mRestartWaiter(new HidlServiceRegistrationWaiter()) {
if (!connectHidlService()) {
return;
}
@@ -87,35 +87,29 @@
}
bool SensorDevice::connectHidlService() {
- // SensorDevice may wait upto 100ms * 10 = 1s for hidl service.
- constexpr auto RETRY_DELAY = std::chrono::milliseconds(100);
+ // SensorDevice will wait for HAL service to start if HAL is declared in device manifest.
size_t retry = 10;
- while (true) {
- int initStep = 0;
+ while (retry-- > 0) {
mSensors = ISensors::getService();
- if (mSensors != nullptr) {
- ++initStep;
- // Poke ISensor service. If it has lingering connection from previous generation of
- // system server, it will kill itself. There is no intention to handle the poll result,
- // which will be done since the size is 0.
- if(mSensors->poll(0, [](auto, const auto &, const auto &) {}).isOk()) {
- // ok to continue
- break;
- }
- // hidl service is restarting, pointer is invalid.
- mSensors = nullptr;
- }
-
- if (--retry <= 0) {
- ALOGE("Cannot connect to ISensors hidl service!");
+ if (mSensors == nullptr) {
+ // no sensor hidl service found
break;
}
- // Delay 100ms before retry, hidl service is expected to come up in short time after
- // crash.
- ALOGI("%s unsuccessful, try again soon (remaining retry %zu).",
- (initStep == 0) ? "getService()" : "poll() check", retry);
- std::this_thread::sleep_for(RETRY_DELAY);
+
+ mRestartWaiter->reset();
+ // Poke ISensor service. If it has lingering connection from previous generation of
+ // system server, it will kill itself. There is no intention to handle the poll result,
+ // which will be done since the size is 0.
+ if(mSensors->poll(0, [](auto, const auto &, const auto &) {}).isOk()) {
+ // ok to continue
+ break;
+ }
+
+ // hidl service is restarting, pointer is invalid.
+ mSensors = nullptr;
+ ALOGI("%s unsuccessful, remaining retry %zu.", __FUNCTION__, retry);
+ mRestartWaiter->wait();
}
return (mSensors != nullptr);
}
@@ -173,7 +167,7 @@
}
status_t SensorDevice::initCheck() const {
- return mSensors != NULL ? NO_ERROR : NO_INIT;
+ return mSensors != nullptr ? NO_ERROR : NO_INIT;
}
ssize_t SensorDevice::poll(sensors_event_t* buffer, size_t count) {
@@ -223,8 +217,13 @@
}
void SensorDevice::autoDisable(void *ident, int handle) {
- Info& info( mActivationCount.editValueFor(handle) );
Mutex::Autolock _l(mLock);
+ ssize_t activationIndex = mActivationCount.indexOfKey(handle);
+ if (activationIndex < 0) {
+ ALOGW("Handle %d cannot be found in activation record", handle);
+ return;
+ }
+ Info& info(mActivationCount.editValueAt(activationIndex));
info.removeBatchParamsForIdent(ident);
}
@@ -235,7 +234,12 @@
bool actuateHardware = false;
Mutex::Autolock _l(mLock);
- Info& info( mActivationCount.editValueFor(handle) );
+ ssize_t activationIndex = mActivationCount.indexOfKey(handle);
+ if (activationIndex < 0) {
+ ALOGW("Handle %d cannot be found in activation record", handle);
+ return BAD_VALUE;
+ }
+ Info& info(mActivationCount.editValueAt(activationIndex));
ALOGD_IF(DEBUG_CONNECTIONS,
"SensorDevice::activate: ident=%p, handle=0x%08x, enabled=%d, count=%zu",
@@ -329,7 +333,12 @@
ident, handle, flags, samplingPeriodNs, maxBatchReportLatencyNs);
Mutex::Autolock _l(mLock);
- Info& info(mActivationCount.editValueFor(handle));
+ ssize_t activationIndex = mActivationCount.indexOfKey(handle);
+ if (activationIndex < 0) {
+ ALOGW("Handle %d cannot be found in activation record", handle);
+ return BAD_VALUE;
+ }
+ Info& info(mActivationCount.editValueAt(activationIndex));
if (info.batchParams.indexOfKey(ident) < 0) {
BatchParams params(samplingPeriodNs, maxBatchReportLatencyNs);
diff --git a/services/sensorservice/SensorDevice.h b/services/sensorservice/SensorDevice.h
index fd6cee6..6d75051 100644
--- a/services/sensorservice/SensorDevice.h
+++ b/services/sensorservice/SensorDevice.h
@@ -17,6 +17,7 @@
#ifndef ANDROID_SENSOR_DEVICE_H
#define ANDROID_SENSOR_DEVICE_H
+#include "SensorDeviceUtils.h"
#include "SensorServiceUtils.h"
#include <sensor/Sensor.h>
@@ -39,12 +40,9 @@
namespace android {
// ---------------------------------------------------------------------------
-using SensorServiceUtil::Dumpable;
-using hardware::Return;
-class SensorDevice : public Singleton<SensorDevice>, public Dumpable {
+class SensorDevice : public Singleton<SensorDevice>, public SensorServiceUtil::Dumpable {
public:
-
class HidlTransportErrorLog {
public:
@@ -105,7 +103,7 @@
private:
friend class Singleton<SensorDevice>;
- sp<android::hardware::sensors::V1_0::ISensors> mSensors;
+ sp<hardware::sensors::V1_0::ISensors> mSensors;
Vector<sensor_t> mSensorList;
std::unordered_map<int32_t, sensor_t*> mConnectedDynamicSensors;
@@ -174,6 +172,8 @@
}
return std::move(ret);
}
+ //TODO(b/67425500): remove waiter after bug is resolved.
+ sp<SensorDeviceUtils::HidlServiceRegistrationWaiter> mRestartWaiter;
bool isClientDisabled(void* ident);
bool isClientDisabledLocked(void* ident);
diff --git a/services/sensorservice/SensorDeviceUtils.cpp b/services/sensorservice/SensorDeviceUtils.cpp
new file mode 100644
index 0000000..dbafffe
--- /dev/null
+++ b/services/sensorservice/SensorDeviceUtils.cpp
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 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 "SensorDeviceUtils.h"
+
+#include <android/hardware/sensors/1.0/ISensors.h>
+#include <utils/Log.h>
+
+#include <chrono>
+#include <thread>
+
+using ::android::hardware::Void;
+using namespace android::hardware::sensors::V1_0;
+
+namespace android {
+namespace SensorDeviceUtils {
+
+HidlServiceRegistrationWaiter::HidlServiceRegistrationWaiter() {
+}
+
+void HidlServiceRegistrationWaiter::onFirstRef() {
+ // Creating sp<...>(this) in the constructor should be avoided, hence
+ // registerForNotifications is called in onFirstRef callback.
+ mRegistered = ISensors::registerForNotifications("default", this);
+}
+
+Return<void> HidlServiceRegistrationWaiter::onRegistration(
+ const hidl_string &fqName, const hidl_string &name, bool preexisting) {
+ ALOGV("onRegistration fqName %s, name %s, preexisting %d",
+ fqName.c_str(), name.c_str(), preexisting);
+
+ {
+ std::lock_guard<std::mutex> lk(mLock);
+ mRestartObserved = true;
+ }
+ mCondition.notify_all();
+ return Void();
+}
+
+void HidlServiceRegistrationWaiter::reset() {
+ std::lock_guard<std::mutex> lk(mLock);
+ mRestartObserved = false;
+}
+
+bool HidlServiceRegistrationWaiter::wait() {
+ constexpr int DEFAULT_WAIT_MS = 100;
+ constexpr int TIMEOUT_MS = 1000;
+
+ if (!mRegistered) {
+ ALOGW("Cannot register service notification, use default wait(%d ms)", DEFAULT_WAIT_MS);
+ std::this_thread::sleep_for(std::chrono::milliseconds(DEFAULT_WAIT_MS));
+ // not sure if service is actually restarted
+ return false;
+ }
+
+ std::unique_lock<std::mutex> lk(mLock);
+ return mCondition.wait_for(lk, std::chrono::milliseconds(TIMEOUT_MS),
+ [this]{return mRestartObserved;});
+}
+
+} // namespace SensorDeviceUtils
+} // namespace android
diff --git a/services/sensorservice/SensorDeviceUtils.h b/services/sensorservice/SensorDeviceUtils.h
new file mode 100644
index 0000000..e2eb606
--- /dev/null
+++ b/services/sensorservice/SensorDeviceUtils.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef ANDROID_SENSOR_DEVICE_UTIL
+#define ANDROID_SENSOR_DEVICE_UTIL
+
+#include <android/hidl/manager/1.0/IServiceNotification.h>
+
+#include <condition_variable>
+#include <thread>
+
+using ::android::hardware::hidl_string;
+using ::android::hardware::Return;
+using ::android::hidl::manager::V1_0::IServiceNotification;
+
+namespace android {
+namespace SensorDeviceUtils {
+
+class HidlServiceRegistrationWaiter : public IServiceNotification {
+public:
+
+ HidlServiceRegistrationWaiter();
+
+ Return<void> onRegistration(const hidl_string &fqName,
+ const hidl_string &name,
+ bool preexisting) override;
+
+ void reset();
+
+ /**
+ * Wait for service restart
+ *
+ * @return true if service is restart since last reset(); false otherwise.
+ */
+ bool wait();
+protected:
+ void onFirstRef() override;
+private:
+ bool mRegistered;
+
+ std::mutex mLock;
+ std::condition_variable mCondition;
+ bool mRestartObserved;
+};
+
+} // namespace SensorDeviceUtils
+} // namespace android;
+
+#endif // ANDROID_SENSOR_SERVICE_UTIL
diff --git a/services/sensorservice/SensorDirectConnection.cpp b/services/sensorservice/SensorDirectConnection.cpp
index 870635b..538d728 100644
--- a/services/sensorservice/SensorDirectConnection.cpp
+++ b/services/sensorservice/SensorDirectConnection.cpp
@@ -27,12 +27,21 @@
const String16& opPackageName)
: mService(service), mUid(uid), mMem(*mem),
mHalChannelHandle(halChannelHandle),
- mOpPackageName(opPackageName) {
+ mOpPackageName(opPackageName), mDestroyed(false) {
ALOGD_IF(DEBUG_CONNECTIONS, "Created SensorDirectConnection");
}
SensorService::SensorDirectConnection::~SensorDirectConnection() {
ALOGD_IF(DEBUG_CONNECTIONS, "~SensorDirectConnection %p", this);
+ destroy();
+}
+
+void SensorService::SensorDirectConnection::destroy() {
+ Mutex::Autolock _l(mDestroyLock);
+ // destroy once only
+ if (mDestroyed) {
+ return;
+ }
stopAll();
mService->cleanupConnection(this);
@@ -40,6 +49,7 @@
native_handle_close(mMem.handle);
native_handle_delete(const_cast<struct native_handle*>(mMem.handle));
}
+ mDestroyed = true;
}
void SensorService::SensorDirectConnection::onFirstRef() {
diff --git a/services/sensorservice/SensorDirectConnection.h b/services/sensorservice/SensorDirectConnection.h
index 27458d4..5c398a8 100644
--- a/services/sensorservice/SensorDirectConnection.h
+++ b/services/sensorservice/SensorDirectConnection.h
@@ -47,7 +47,7 @@
// stop all active sensor report. if backupRecord is set to false,
// those report can be recovered by recoverAll
// called by SensorService when enter restricted mode
- void stopAll(bool clearRecord = false);
+ void stopAll(bool backupRecord = false);
// recover sensor reports previously stopped by stopAll(true)
// called by SensorService when return to NORMAL mode.
@@ -63,7 +63,7 @@
virtual status_t setEventRate(int handle, nsecs_t samplingPeriodNs);
virtual status_t flush();
virtual int32_t configureChannel(int handle, int rateLevel);
-
+ virtual void destroy();
private:
const sp<SensorService> mService;
const uid_t mUid;
@@ -74,6 +74,9 @@
mutable Mutex mConnectionLock;
std::unordered_map<int, int> mActivated;
std::unordered_map<int, int> mActivatedBackup;
+
+ mutable Mutex mDestroyLock;
+ bool mDestroyed;
};
} // namepsace android
diff --git a/services/sensorservice/SensorEventConnection.cpp b/services/sensorservice/SensorEventConnection.cpp
index fad046c..0a05dd1 100644
--- a/services/sensorservice/SensorEventConnection.cpp
+++ b/services/sensorservice/SensorEventConnection.cpp
@@ -32,7 +32,8 @@
const String16& opPackageName)
: mService(service), mUid(uid), mWakeLockRefCount(0), mHasLooperCallbacks(false),
mDead(false), mDataInjectionMode(isDataInjectionMode), mEventCache(NULL),
- mCacheSize(0), mMaxCacheSize(0), mPackageName(packageName), mOpPackageName(opPackageName) {
+ mCacheSize(0), mMaxCacheSize(0), mPackageName(packageName), mOpPackageName(opPackageName),
+ mDestroyed(false) {
mChannel = new BitTube(mService->mSocketBufferSize);
#if DEBUG_CONNECTIONS
mEventsReceived = mEventsSentFromCache = mEventsSent = 0;
@@ -42,10 +43,22 @@
SensorService::SensorEventConnection::~SensorEventConnection() {
ALOGD_IF(DEBUG_CONNECTIONS, "~SensorEventConnection(%p)", this);
+ destroy();
+}
+
+void SensorService::SensorEventConnection::destroy() {
+ Mutex::Autolock _l(mDestroyLock);
+
+ // destroy once only
+ if (mDestroyed) {
+ return;
+ }
+
mService->cleanupConnection(this);
if (mEventCache != NULL) {
delete mEventCache;
}
+ mDestroyed = true;
}
void SensorService::SensorEventConnection::onFirstRef() {
@@ -477,7 +490,14 @@
// separately before the next batch of events.
for (int j = 0; j < numEventsDropped; ++j) {
if (scratch[j].type == SENSOR_TYPE_META_DATA) {
- FlushInfo& flushInfo = mSensorInfo.editValueFor(scratch[j].meta_data.sensor);
+ ssize_t index = mSensorInfo.indexOfKey(scratch[j].meta_data.sensor);
+ if (index < 0) {
+ ALOGW("%s: sensor 0x%x is not found in connection",
+ __func__, scratch[j].meta_data.sensor);
+ continue;
+ }
+
+ FlushInfo& flushInfo = mSensorInfo.editValueAt(index);
flushInfo.mPendingFlushEventsToSend++;
ALOGD_IF(DEBUG_CONNECTIONS, "increment pendingFlushCount %d",
flushInfo.mPendingFlushEventsToSend);
diff --git a/services/sensorservice/SensorEventConnection.h b/services/sensorservice/SensorEventConnection.h
index c81e015..6f282cd 100644
--- a/services/sensorservice/SensorEventConnection.h
+++ b/services/sensorservice/SensorEventConnection.h
@@ -75,6 +75,7 @@
virtual status_t setEventRate(int handle, nsecs_t samplingPeriodNs);
virtual status_t flush();
virtual int32_t configureChannel(int handle, int rateLevel);
+ virtual void destroy();
// Count the number of flush complete events which are about to be dropped in the buffer.
// Increment mPendingFlushEventsToSend in mSensorInfo. These flush complete events will be sent
@@ -164,6 +165,8 @@
int mTotalAcksNeeded, mTotalAcksReceived;
#endif
+ mutable Mutex mDestroyLock;
+ bool mDestroyed;
};
} // namepsace android
diff --git a/services/sensorservice/SensorList.cpp b/services/sensorservice/SensorList.cpp
index ab08cac..aa306d8 100644
--- a/services/sensorservice/SensorList.cpp
+++ b/services/sensorservice/SensorList.cpp
@@ -124,14 +124,15 @@
forEachSensor([&result] (const Sensor& s) -> bool {
result.appendFormat(
"%#010x) %-25s | %-15s | ver: %" PRId32 " | type: %20s(%" PRId32
- ") | perm: %s\n",
+ ") | perm: %s | flags: 0x%08x\n",
s.getHandle(),
s.getName().string(),
s.getVendor().string(),
s.getVersion(),
s.getStringType().string(),
s.getType(),
- s.getRequiredPermission().size() ? s.getRequiredPermission().string() : "n/a");
+ s.getRequiredPermission().size() ? s.getRequiredPermission().string() : "n/a",
+ static_cast<int>(s.getFlags()));
result.append("\t");
const int reportingMode = s.getReportingMode();
@@ -173,9 +174,14 @@
result.appendFormat("non-wakeUp | ");
}
+ if (s.isDataInjectionSupported()) {
+ result.appendFormat("data-injection, ");
+ }
+
if (s.isDynamicSensor()) {
result.appendFormat("dynamic, ");
}
+
if (s.hasAdditionalInfo()) {
result.appendFormat("has-additional-info, ");
}
@@ -190,7 +196,6 @@
if (s.isDirectChannelTypeSupported(SENSOR_DIRECT_MEM_TYPE_GRALLOC)) {
result.append("gralloc, ");
}
- result.appendFormat("flag =0x%08x", static_cast<int>(s.getFlags()));
result.append("\n");
}
return true;
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index 209eea5..dc491d9 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -394,7 +394,7 @@
}
} else if (!mSensors.hasAnySensor()) {
result.append("No Sensors on the device\n");
- result.append("devInitCheck : %d\n", SensorDevice::getInstance().initCheck());
+ result.appendFormat("devInitCheck : %d\n", SensorDevice::getInstance().initCheck());
} else {
// Default dump the sensor list and debugging information.
//
@@ -933,8 +933,14 @@
}
uid_t uid = IPCThreadState::self()->getCallingUid();
- sp<SensorEventConnection> result(new SensorEventConnection(this, uid, packageName,
- requestedMode == DATA_INJECTION, opPackageName));
+ pid_t pid = IPCThreadState::self()->getCallingPid();
+
+ String8 connPackageName =
+ (packageName == "") ? String8::format("unknown_package_pid_%d", pid) : packageName;
+ String16 connOpPackageName =
+ (opPackageName == String16("")) ? String16(connPackageName) : opPackageName;
+ sp<SensorEventConnection> result(new SensorEventConnection(this, uid, connPackageName,
+ requestedMode == DATA_INJECTION, connOpPackageName));
if (requestedMode == DATA_INJECTION) {
if (mActiveConnections.indexOf(result) < 0) {
mActiveConnections.add(result);
diff --git a/services/sensorservice/hidl/Android.bp b/services/sensorservice/hidl/Android.bp
index 8bbc4c5..02c13fa 100644
--- a/services/sensorservice/hidl/Android.bp
+++ b/services/sensorservice/hidl/Android.bp
@@ -14,6 +14,7 @@
"libbase",
"libhidlbase",
"libhidltransport",
+ "libhwbinder",
"libutils",
"libsensor",
"android.frameworks.sensorservice@1.0",
diff --git a/services/sensorservice/hidl/SensorManager.cpp b/services/sensorservice/hidl/SensorManager.cpp
index 991944e..fee6da1 100644
--- a/services/sensorservice/hidl/SensorManager.cpp
+++ b/services/sensorservice/hidl/SensorManager.cpp
@@ -24,12 +24,14 @@
#include <sched.h>
-#include <thread>
#include "EventQueue.h"
#include "DirectReportChannel.h"
#include "utils.h"
+#include <hwbinder/IPCThreadState.h>
+#include <utils/String8.h>
+
namespace android {
namespace frameworks {
namespace sensorservice {
@@ -40,17 +42,24 @@
using ::android::hardware::sensors::V1_0::SensorsEventFormatOffset;
using ::android::hardware::hidl_vec;
using ::android::hardware::Void;
-using ::android::sp;
-SensorManager::SensorManager() {
+static const char* POLL_THREAD_NAME = "hidl_ssvc_poll";
+
+SensorManager::SensorManager(JavaVM* vm)
+ : mLooper(new Looper(false /*allowNonCallbacks*/)), mStopThread(true), mJavaVm(vm) {
}
SensorManager::~SensorManager() {
// Stops pollAll inside the thread.
- std::unique_lock<std::mutex> lock(mLooperMutex);
+ std::lock_guard<std::mutex> lock(mThreadMutex);
+
+ mStopThread = true;
if (mLooper != nullptr) {
mLooper->wake();
}
+ if (mPollThread.joinable()) {
+ mPollThread.join();
+ }
}
// Methods from ::android::frameworks::sensorservice::V1_0::ISensorManager follow.
@@ -125,12 +134,13 @@
}
/* One global looper for all event queues created from this SensorManager. */
-sp<::android::Looper> SensorManager::getLooper() {
- std::unique_lock<std::mutex> lock(mLooperMutex);
- if (mLooper == nullptr) {
- std::condition_variable looperSet;
+sp<Looper> SensorManager::getLooper() {
+ std::lock_guard<std::mutex> lock(mThreadMutex);
- std::thread{[&mutex = mLooperMutex, &looper = mLooper, &looperSet] {
+ if (!mPollThread.joinable()) {
+ // if thread not initialized, start thread
+ mStopThread = false;
+ std::thread pollThread{[&stopThread = mStopThread, looper = mLooper, javaVm = mJavaVm] {
struct sched_param p = {0};
p.sched_priority = 10;
@@ -139,18 +149,45 @@
<< strerror(errno);
}
- std::unique_lock<std::mutex> lock(mutex);
- looper = Looper::prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS /* opts */);
- lock.unlock();
+ // set looper
+ Looper::setForThread(looper);
- looperSet.notify_one();
- int pollResult = looper->pollAll(-1 /* timeout */);
- if (pollResult != ALOOPER_POLL_WAKE) {
- LOG(ERROR) << "Looper::pollAll returns unexpected " << pollResult;
+ // Attach the thread to JavaVM so that pollAll do not crash if the thread
+ // eventually calls into Java.
+ JavaVMAttachArgs args{
+ .version = JNI_VERSION_1_2,
+ .name = POLL_THREAD_NAME,
+ .group = NULL
+ };
+ JNIEnv* env;
+ if (javaVm->AttachCurrentThread(&env, &args) != JNI_OK) {
+ LOG(FATAL) << "Cannot attach SensorManager looper thread to Java VM.";
}
- LOG(INFO) << "Looper thread is terminated.";
- }}.detach();
- looperSet.wait(lock, [this]{ return this->mLooper != nullptr; });
+
+ LOG(INFO) << POLL_THREAD_NAME << " started.";
+ for (;;) {
+ int pollResult = looper->pollAll(-1 /* timeout */);
+ if (pollResult == Looper::POLL_WAKE) {
+ if (stopThread == true) {
+ LOG(INFO) << POLL_THREAD_NAME << ": requested to stop";
+ break;
+ } else {
+ LOG(INFO) << POLL_THREAD_NAME << ": spurious wake up, back to work";
+ }
+ } else {
+ LOG(ERROR) << POLL_THREAD_NAME << ": Looper::pollAll returns unexpected "
+ << pollResult;
+ break;
+ }
+ }
+
+ if (javaVm->DetachCurrentThread() != JNI_OK) {
+ LOG(ERROR) << "Cannot detach SensorManager looper thread from Java VM.";
+ }
+
+ LOG(INFO) << POLL_THREAD_NAME << " is terminated.";
+ }};
+ mPollThread = std::move(pollThread);
}
return mLooper;
}
@@ -172,7 +209,15 @@
}
sp<::android::Looper> looper = getLooper();
- sp<::android::SensorEventQueue> internalQueue = getInternalManager().createEventQueue();
+ if (looper == nullptr) {
+ LOG(ERROR) << "::android::SensorManager::createEventQueue cannot initialize looper";
+ _hidl_cb(nullptr, Result::UNKNOWN_ERROR);
+ return Void();
+ }
+
+ String8 package(String8::format("hidl_client_pid_%d",
+ android::hardware::IPCThreadState::self()->getCallingPid()));
+ sp<::android::SensorEventQueue> internalQueue = getInternalManager().createEventQueue(package);
if (internalQueue == nullptr) {
LOG(WARNING) << "::android::SensorManager::createEventQueue returns nullptr.";
_hidl_cb(nullptr, Result::UNKNOWN_ERROR);
diff --git a/services/sensorservice/hidl/include/sensorservicehidl/SensorManager.h b/services/sensorservice/hidl/include/sensorservicehidl/SensorManager.h
index cc044bf..ddcee28 100644
--- a/services/sensorservice/hidl/include/sensorservicehidl/SensorManager.h
+++ b/services/sensorservice/hidl/include/sensorservicehidl/SensorManager.h
@@ -17,7 +17,10 @@
#ifndef ANDROID_FRAMEWORKS_SENSORSERVICE_V1_0_SENSORMANAGER_H
#define ANDROID_FRAMEWORKS_SENSORSERVICE_V1_0_SENSORMANAGER_H
+#include <jni.h>
+
#include <mutex>
+#include <thread>
#include <android/frameworks/sensorservice/1.0/ISensorManager.h>
#include <android/frameworks/sensorservice/1.0/types.h>
@@ -36,10 +39,11 @@
using ::android::hardware::hidl_handle;
using ::android::hardware::hidl_memory;
using ::android::hardware::Return;
+using ::android::sp;
struct SensorManager final : public ISensorManager {
- SensorManager();
+ SensorManager(JavaVM* vm);
~SensorManager();
// Methods from ::android::frameworks::sensorservice::V1_0::ISensorManager follow.
@@ -52,13 +56,17 @@
private:
// Block until ::android::SensorManager is initialized.
::android::SensorManager& getInternalManager();
- sp<::android::Looper> getLooper();
+ sp<Looper> getLooper();
std::mutex mInternalManagerMutex;
::android::SensorManager* mInternalManager = nullptr; // does not own
+ sp<Looper> mLooper;
- std::mutex mLooperMutex;
- sp<::android::Looper> mLooper;
+ volatile bool mStopThread;
+ std::mutex mThreadMutex; //protects mPollThread
+ std::thread mPollThread;
+
+ JavaVM* mJavaVm;
};
} // namespace implementation
diff --git a/services/sensorservice/tests/Android.mk b/services/sensorservice/tests/Android.mk
index e894655..8a9c36b 100644
--- a/services/sensorservice/tests/Android.mk
+++ b/services/sensorservice/tests/Android.mk
@@ -4,6 +4,8 @@
LOCAL_SRC_FILES:= \
sensorservicetest.cpp
+LOCAL_CFLAGS := -Wall -Werror
+
LOCAL_SHARED_LIBRARIES := \
libutils libsensor libandroid
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index cc93105..bd7f0ea 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -1,4 +1,8 @@
cc_library_static {
name: "libsurfaceflingerincludes",
export_include_dirs: ["."],
+ static_libs = ["libserviceutils"],
+ export_static_lib_headers = ["libserviceutils"],
}
+
+subdirs = ["tests/fakehwc", "layerproto"]
\ No newline at end of file
diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk
index 95a522d..7115ad6 100644
--- a/services/surfaceflinger/Android.mk
+++ b/services/surfaceflinger/Android.mk
@@ -9,18 +9,20 @@
DisplayDevice.cpp \
DispSync.cpp \
EventControlThread.cpp \
- StartBootAnimThread.cpp \
+ StartPropertySetThread.cpp \
EventThread.cpp \
FrameTracker.cpp \
GpuService.cpp \
Layer.cpp \
- LayerDim.cpp \
+ BufferLayer.cpp \
+ ColorLayer.cpp \
LayerRejecter.cpp \
LayerVector.cpp \
MessageQueue.cpp \
MonitoredProducer.cpp \
SurfaceFlingerConsumer.cpp \
SurfaceInterceptor.cpp \
+ SurfaceTracing.cpp \
Transform.cpp \
DisplayHardware/ComposerHal.cpp \
DisplayHardware/FramebufferSurface.cpp \
@@ -39,6 +41,8 @@
RenderEngine/RenderEngine.cpp \
RenderEngine/Texture.cpp \
RenderEngine/GLES20RenderEngine.cpp \
+ LayerProtoHelper.cpp \
+ RenderArea.cpp \
LOCAL_MODULE := libsurfaceflinger
LOCAL_C_INCLUDES := \
@@ -67,7 +71,10 @@
libtrace_proto \
libvkjson \
libvr_manager \
- libvrflinger
+ libvrflinger \
+ libserviceutils
+
+LOCAL_EXPORT_STATIC_LIBRARY_HEADERS := libserviceutils
LOCAL_SHARED_LIBRARIES := \
android.frameworks.vr.composer@1.0 \
@@ -95,7 +102,8 @@
libsync \
libprotobuf-cpp-lite \
libbase \
- android.hardware.power@1.0
+ android.hardware.power@1.0 \
+ liblayers_proto
LOCAL_EXPORT_SHARED_LIBRARY_HEADERS := \
android.hardware.graphics.allocator@2.0 \
@@ -104,7 +112,7 @@
libhidltransport \
libhwbinder
-LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
+LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code -std=c++1z
include $(BUILD_SHARED_LIBRARY)
@@ -142,10 +150,12 @@
libutils \
libui \
libgui \
- libdl
+ libdl \
+ liblayers_proto
LOCAL_WHOLE_STATIC_LIBRARIES := libsigchain
-LOCAL_STATIC_LIBRARIES := libtrace_proto
+LOCAL_STATIC_LIBRARIES := libtrace_proto \
+ libserviceutils
LOCAL_MODULE := surfaceflinger
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
new file mode 100644
index 0000000..fc0949d
--- /dev/null
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -0,0 +1,1002 @@
+/*
+ * Copyright (C) 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.
+ */
+
+//#define LOG_NDEBUG 0
+#undef LOG_TAG
+#define LOG_TAG "BufferLayer"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+#include "BufferLayer.h"
+#include "Colorizer.h"
+#include "DisplayDevice.h"
+#include "LayerRejecter.h"
+#include "clz.h"
+
+#include "RenderEngine/RenderEngine.h"
+
+#include <gui/BufferItem.h>
+#include <gui/BufferQueue.h>
+#include <gui/LayerDebugInfo.h>
+#include <gui/Surface.h>
+
+#include <ui/DebugUtils.h>
+
+#include <utils/Errors.h>
+#include <utils/Log.h>
+#include <utils/NativeHandle.h>
+#include <utils/StopWatch.h>
+#include <utils/Trace.h>
+
+#include <cutils/compiler.h>
+#include <cutils/native_handle.h>
+#include <cutils/properties.h>
+
+#include <math.h>
+#include <stdlib.h>
+#include <mutex>
+
+namespace android {
+
+BufferLayer::BufferLayer(SurfaceFlinger* flinger, const sp<Client>& client, const String8& name,
+ uint32_t w, uint32_t h, uint32_t flags)
+ : Layer(flinger, client, name, w, h, flags),
+ mSurfaceFlingerConsumer(nullptr),
+ mTextureName(UINT32_MAX),
+ mFormat(PIXEL_FORMAT_NONE),
+ mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
+ mBufferLatched(false),
+ mPreviousFrameNumber(0),
+ mUpdateTexImageFailed(false),
+ mRefreshPending(false) {
+#ifdef USE_HWC2
+ ALOGV("Creating Layer %s", name.string());
+#endif
+
+ mFlinger->getRenderEngine().genTextures(1, &mTextureName);
+ mTexture.init(Texture::TEXTURE_EXTERNAL, mTextureName);
+
+ if (flags & ISurfaceComposerClient::eNonPremultiplied) mPremultipliedAlpha = false;
+
+ mCurrentState.requested = mCurrentState.active;
+
+ // drawing state & current state are identical
+ mDrawingState = mCurrentState;
+}
+
+BufferLayer::~BufferLayer() {
+ sp<Client> c(mClientRef.promote());
+ if (c != 0) {
+ c->detachLayer(this);
+ }
+
+ for (auto& point : mRemoteSyncPoints) {
+ point->setTransactionApplied();
+ }
+ for (auto& point : mLocalSyncPoints) {
+ point->setFrameAvailable();
+ }
+ mFlinger->deleteTextureAsync(mTextureName);
+
+#ifdef USE_HWC2
+ if (!mHwcLayers.empty()) {
+ ALOGE("Found stale hardware composer layers when destroying "
+ "surface flinger layer %s",
+ mName.string());
+ destroyAllHwcLayers();
+ }
+#endif
+}
+
+void BufferLayer::useSurfaceDamage() {
+ if (mFlinger->mForceFullDamage) {
+ surfaceDamageRegion = Region::INVALID_REGION;
+ } else {
+ surfaceDamageRegion = mSurfaceFlingerConsumer->getSurfaceDamage();
+ }
+}
+
+void BufferLayer::useEmptyDamage() {
+ surfaceDamageRegion.clear();
+}
+
+bool BufferLayer::isProtected() const {
+ const sp<GraphicBuffer>& activeBuffer(mActiveBuffer);
+ return (activeBuffer != 0) && (activeBuffer->getUsage() & GRALLOC_USAGE_PROTECTED);
+}
+
+bool BufferLayer::isVisible() const {
+ return !(isHiddenByPolicy()) && getAlpha() > 0.0f &&
+ (mActiveBuffer != NULL || mSidebandStream != NULL);
+}
+
+bool BufferLayer::isFixedSize() const {
+ return getEffectiveScalingMode() != NATIVE_WINDOW_SCALING_MODE_FREEZE;
+}
+
+status_t BufferLayer::setBuffers(uint32_t w, uint32_t h, PixelFormat format, uint32_t flags) {
+ uint32_t const maxSurfaceDims =
+ min(mFlinger->getMaxTextureSize(), mFlinger->getMaxViewportDims());
+
+ // never allow a surface larger than what our underlying GL implementation
+ // can handle.
+ if ((uint32_t(w) > maxSurfaceDims) || (uint32_t(h) > maxSurfaceDims)) {
+ ALOGE("dimensions too large %u x %u", uint32_t(w), uint32_t(h));
+ return BAD_VALUE;
+ }
+
+ mFormat = format;
+
+ mPotentialCursor = (flags & ISurfaceComposerClient::eCursorWindow) ? true : false;
+ mProtectedByApp = (flags & ISurfaceComposerClient::eProtectedByApp) ? true : false;
+ mCurrentOpacity = getOpacityForFormat(format);
+
+ mSurfaceFlingerConsumer->setDefaultBufferSize(w, h);
+ mSurfaceFlingerConsumer->setDefaultBufferFormat(format);
+ mSurfaceFlingerConsumer->setConsumerUsageBits(getEffectiveUsage(0));
+
+ return NO_ERROR;
+}
+
+static constexpr mat4 inverseOrientation(uint32_t transform) {
+ const mat4 flipH(-1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1);
+ const mat4 flipV(1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1);
+ const mat4 rot90(0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1);
+ mat4 tr;
+
+ if (transform & NATIVE_WINDOW_TRANSFORM_ROT_90) {
+ tr = tr * rot90;
+ }
+ if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_H) {
+ tr = tr * flipH;
+ }
+ if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_V) {
+ tr = tr * flipV;
+ }
+ return inverse(tr);
+}
+
+/*
+ * onDraw will draw the current layer onto the presentable buffer
+ */
+void BufferLayer::onDraw(const RenderArea& renderArea, const Region& clip,
+ bool useIdentityTransform) const {
+ ATRACE_CALL();
+
+ if (CC_UNLIKELY(mActiveBuffer == 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
+ // has drawn the first time.
+
+ // If there is nothing under us, we paint the screen in black, otherwise
+ // we just skip this update.
+
+ // figure out if there is something below us
+ Region under;
+ bool finished = false;
+ mFlinger->mDrawingState.traverseInZOrder([&](Layer* layer) {
+ if (finished || layer == static_cast<BufferLayer const*>(this)) {
+ finished = true;
+ return;
+ }
+ under.orSelf(renderArea.getTransform().transform(layer->visibleRegion));
+ });
+ // if not everything below us is covered, we plug the holes!
+ Region holes(clip.subtract(under));
+ if (!holes.isEmpty()) {
+ clearWithOpenGL(renderArea, 0, 0, 0, 1);
+ }
+ return;
+ }
+
+ // Bind the current buffer to the GL texture, and wait for it to be
+ // ready for us to draw into.
+ status_t err = mSurfaceFlingerConsumer->bindTextureImage();
+ if (err != NO_ERROR) {
+ ALOGW("onDraw: bindTextureImage failed (err=%d)", err);
+ // Go ahead and draw the buffer anyway; no matter what we do the screen
+ // is probably going to have something visibly wrong.
+ }
+
+ bool blackOutLayer = isProtected() || (isSecure() && !renderArea.isSecure());
+
+ RenderEngine& engine(mFlinger->getRenderEngine());
+
+ if (!blackOutLayer) {
+ // TODO: we could be more subtle with isFixedSize()
+ const bool useFiltering = getFiltering() || needsFiltering(renderArea) || isFixedSize();
+
+ // Query the texture matrix given our current filtering mode.
+ float textureMatrix[16];
+ mSurfaceFlingerConsumer->setFilteringEnabled(useFiltering);
+ mSurfaceFlingerConsumer->getTransformMatrix(textureMatrix);
+
+ if (getTransformToDisplayInverse()) {
+ /*
+ * the code below applies the primary display's inverse transform to
+ * the texture transform
+ */
+ uint32_t transform = DisplayDevice::getPrimaryDisplayOrientationTransform();
+ mat4 tr = inverseOrientation(transform);
+
+ /**
+ * TODO(b/36727915): This is basically a hack.
+ *
+ * Ensure that regardless of the parent transformation,
+ * this buffer is always transformed from native display
+ * orientation to display orientation. For example, in the case
+ * of a camera where the buffer remains in native orientation,
+ * we want the pixels to always be upright.
+ */
+ sp<Layer> p = mDrawingParent.promote();
+ if (p != nullptr) {
+ const auto parentTransform = p->getTransform();
+ tr = tr * inverseOrientation(parentTransform.getOrientation());
+ }
+
+ // and finally apply it to the original texture matrix
+ const mat4 texTransform(mat4(static_cast<const float*>(textureMatrix)) * tr);
+ memcpy(textureMatrix, texTransform.asArray(), sizeof(textureMatrix));
+ }
+
+ // Set things up for texturing.
+ mTexture.setDimensions(mActiveBuffer->getWidth(), mActiveBuffer->getHeight());
+ mTexture.setFiltering(useFiltering);
+ mTexture.setMatrix(textureMatrix);
+
+ engine.setupLayerTexturing(mTexture);
+ } else {
+ engine.setupLayerBlackedOut();
+ }
+ drawWithOpenGL(renderArea, useIdentityTransform);
+ engine.disableTexturing();
+}
+
+#ifdef USE_HWC2
+void BufferLayer::onLayerDisplayed(const sp<Fence>& releaseFence) {
+ if (mHwcLayers.empty()) {
+ return;
+ }
+ mSurfaceFlingerConsumer->setReleaseFence(releaseFence);
+}
+#else
+void BufferLayer::onLayerDisplayed(const sp<const DisplayDevice>& /*hw*/,
+ HWComposer::HWCLayerInterface* layer) {
+ if (layer) {
+ layer->onDisplayed();
+ mSurfaceFlingerConsumer->setReleaseFence(layer->getAndResetReleaseFence());
+ }
+}
+#endif
+
+void BufferLayer::abandon() {
+ mSurfaceFlingerConsumer->abandon();
+}
+
+bool BufferLayer::shouldPresentNow(const DispSync& dispSync) const {
+ if (mSidebandStreamChanged || mAutoRefresh) {
+ return true;
+ }
+
+ Mutex::Autolock lock(mQueueItemLock);
+ if (mQueueItems.empty()) {
+ return false;
+ }
+ auto timestamp = mQueueItems[0].mTimestamp;
+ nsecs_t expectedPresent = mSurfaceFlingerConsumer->computeExpectedPresent(dispSync);
+
+ // Ignore timestamps more than a second in the future
+ bool isPlausible = timestamp < (expectedPresent + s2ns(1));
+ ALOGW_IF(!isPlausible,
+ "[%s] Timestamp %" PRId64 " seems implausible "
+ "relative to expectedPresent %" PRId64,
+ mName.string(), timestamp, expectedPresent);
+
+ bool isDue = timestamp < expectedPresent;
+ return isDue || !isPlausible;
+}
+
+void BufferLayer::setTransformHint(uint32_t orientation) const {
+ mSurfaceFlingerConsumer->setTransformHint(orientation);
+}
+
+bool BufferLayer::onPreComposition(nsecs_t refreshStartTime) {
+ if (mBufferLatched) {
+ Mutex::Autolock lock(mFrameEventHistoryMutex);
+ mFrameEventHistory.addPreComposition(mCurrentFrameNumber, refreshStartTime);
+ }
+ mRefreshPending = false;
+ return mQueuedFrames > 0 || mSidebandStreamChanged || mAutoRefresh;
+}
+bool BufferLayer::onPostComposition(const std::shared_ptr<FenceTime>& glDoneFence,
+ const std::shared_ptr<FenceTime>& presentFence,
+ const CompositorTiming& compositorTiming) {
+ // mFrameLatencyNeeded is true when a new frame was latched for the
+ // composition.
+ if (!mFrameLatencyNeeded) return false;
+
+ // Update mFrameEventHistory.
+ {
+ Mutex::Autolock lock(mFrameEventHistoryMutex);
+ mFrameEventHistory.addPostComposition(mCurrentFrameNumber, glDoneFence, presentFence,
+ compositorTiming);
+ }
+
+ // Update mFrameTracker.
+ nsecs_t desiredPresentTime = mSurfaceFlingerConsumer->getTimestamp();
+ mFrameTracker.setDesiredPresentTime(desiredPresentTime);
+
+ std::shared_ptr<FenceTime> frameReadyFence = mSurfaceFlingerConsumer->getCurrentFenceTime();
+ if (frameReadyFence->isValid()) {
+ mFrameTracker.setFrameReadyFence(std::move(frameReadyFence));
+ } else {
+ // There was no fence for this frame, so assume that it was ready
+ // to be presented at the desired present time.
+ mFrameTracker.setFrameReadyTime(desiredPresentTime);
+ }
+
+ if (presentFence->isValid()) {
+ mFrameTracker.setActualPresentFence(std::shared_ptr<FenceTime>(presentFence));
+ } else {
+ // The HWC doesn't support present fences, so use the refresh
+ // timestamp instead.
+ mFrameTracker.setActualPresentTime(
+ mFlinger->getHwComposer().getRefreshTimestamp(HWC_DISPLAY_PRIMARY));
+ }
+
+ mFrameTracker.advanceFrame();
+ mFrameLatencyNeeded = false;
+ return true;
+}
+
+std::vector<OccupancyTracker::Segment> BufferLayer::getOccupancyHistory(bool forceFlush) {
+ std::vector<OccupancyTracker::Segment> history;
+ status_t result = mSurfaceFlingerConsumer->getOccupancyHistory(forceFlush, &history);
+ if (result != NO_ERROR) {
+ ALOGW("[%s] Failed to obtain occupancy history (%d)", mName.string(), result);
+ return {};
+ }
+ return history;
+}
+
+bool BufferLayer::getTransformToDisplayInverse() const {
+ return mSurfaceFlingerConsumer->getTransformToDisplayInverse();
+}
+
+#ifdef USE_HWC2
+void BufferLayer::releasePendingBuffer(nsecs_t dequeueReadyTime) {
+ if (!mSurfaceFlingerConsumer->releasePendingBuffer()) {
+ return;
+ }
+
+ auto releaseFenceTime =
+ std::make_shared<FenceTime>(mSurfaceFlingerConsumer->getPrevFinalReleaseFence());
+ mReleaseTimeline.updateSignalTimes();
+ mReleaseTimeline.push(releaseFenceTime);
+
+ Mutex::Autolock lock(mFrameEventHistoryMutex);
+ if (mPreviousFrameNumber != 0) {
+ mFrameEventHistory.addRelease(mPreviousFrameNumber, dequeueReadyTime,
+ std::move(releaseFenceTime));
+ }
+}
+#endif
+
+Region BufferLayer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime) {
+ ATRACE_CALL();
+
+ if (android_atomic_acquire_cas(true, false, &mSidebandStreamChanged) == 0) {
+ // mSidebandStreamChanged was true
+ mSidebandStream = mSurfaceFlingerConsumer->getSidebandStream();
+ if (mSidebandStream != NULL) {
+ setTransactionFlags(eTransactionNeeded);
+ mFlinger->setTransactionFlags(eTraversalNeeded);
+ }
+ recomputeVisibleRegions = true;
+
+ const State& s(getDrawingState());
+ return getTransform().transform(Region(Rect(s.active.w, s.active.h)));
+ }
+
+ Region outDirtyRegion;
+ if (mQueuedFrames <= 0 && !mAutoRefresh) {
+ return outDirtyRegion;
+ }
+
+ // if we've already called updateTexImage() without going through
+ // a composition step, we have to skip this layer at this point
+ // because we cannot call updateTeximage() without a corresponding
+ // compositionComplete() call.
+ // we'll trigger an update in onPreComposition().
+ if (mRefreshPending) {
+ return outDirtyRegion;
+ }
+
+ // If the head buffer's acquire fence hasn't signaled yet, return and
+ // try again later
+ if (!headFenceHasSignaled()) {
+ mFlinger->signalLayerUpdate();
+ return outDirtyRegion;
+ }
+
+ // Capture the old state of the layer for comparisons later
+ const State& s(getDrawingState());
+ const bool oldOpacity = isOpaque(s);
+ sp<GraphicBuffer> oldActiveBuffer = mActiveBuffer;
+
+ if (!allTransactionsSignaled()) {
+ mFlinger->signalLayerUpdate();
+ return outDirtyRegion;
+ }
+
+ // This boolean is used to make sure that SurfaceFlinger's shadow copy
+ // of the buffer queue isn't modified when the buffer queue is returning
+ // BufferItem's that weren't actually queued. This can happen in shared
+ // buffer mode.
+ bool queuedBuffer = false;
+ LayerRejecter r(mDrawingState, getCurrentState(), recomputeVisibleRegions,
+ getProducerStickyTransform() != 0, mName.string(), mOverrideScalingMode,
+ mFreezeGeometryUpdates);
+ status_t updateResult =
+ mSurfaceFlingerConsumer->updateTexImage(&r, mFlinger->mPrimaryDispSync, &mAutoRefresh,
+ &queuedBuffer, mLastFrameNumberReceived);
+ if (updateResult == BufferQueue::PRESENT_LATER) {
+ // Producer doesn't want buffer to be displayed yet. Signal a
+ // layer update so we check again at the next opportunity.
+ mFlinger->signalLayerUpdate();
+ return outDirtyRegion;
+ } else if (updateResult == SurfaceFlingerConsumer::BUFFER_REJECTED) {
+ // If the buffer has been rejected, remove it from the shadow queue
+ // and return early
+ if (queuedBuffer) {
+ Mutex::Autolock lock(mQueueItemLock);
+ mQueueItems.removeAt(0);
+ android_atomic_dec(&mQueuedFrames);
+ }
+ return outDirtyRegion;
+ } else if (updateResult != NO_ERROR || mUpdateTexImageFailed) {
+ // This can occur if something goes wrong when trying to create the
+ // EGLImage for this buffer. If this happens, the buffer has already
+ // been released, so we need to clean up the queue and bug out
+ // early.
+ if (queuedBuffer) {
+ Mutex::Autolock lock(mQueueItemLock);
+ mQueueItems.clear();
+ android_atomic_and(0, &mQueuedFrames);
+ }
+
+ // Once we have hit this state, the shadow queue may no longer
+ // correctly reflect the incoming BufferQueue's contents, so even if
+ // updateTexImage starts working, the only safe course of action is
+ // to continue to ignore updates.
+ mUpdateTexImageFailed = true;
+
+ return outDirtyRegion;
+ }
+
+ if (queuedBuffer) {
+ // Autolock scope
+ auto currentFrameNumber = mSurfaceFlingerConsumer->getFrameNumber();
+
+ Mutex::Autolock lock(mQueueItemLock);
+
+ // Remove any stale buffers that have been dropped during
+ // updateTexImage
+ while (mQueueItems[0].mFrameNumber != currentFrameNumber) {
+ mQueueItems.removeAt(0);
+ android_atomic_dec(&mQueuedFrames);
+ }
+
+ mQueueItems.removeAt(0);
+ }
+
+ // Decrement the queued-frames count. Signal another event if we
+ // have more frames pending.
+ if ((queuedBuffer && android_atomic_dec(&mQueuedFrames) > 1) || mAutoRefresh) {
+ mFlinger->signalLayerUpdate();
+ }
+
+ // update the active buffer
+ mActiveBuffer = mSurfaceFlingerConsumer->getCurrentBuffer(&mActiveBufferSlot);
+ if (mActiveBuffer == NULL) {
+ // this can only happen if the very first buffer was rejected.
+ return outDirtyRegion;
+ }
+
+ mBufferLatched = true;
+ mPreviousFrameNumber = mCurrentFrameNumber;
+ mCurrentFrameNumber = mSurfaceFlingerConsumer->getFrameNumber();
+
+ {
+ Mutex::Autolock lock(mFrameEventHistoryMutex);
+ mFrameEventHistory.addLatch(mCurrentFrameNumber, latchTime);
+#ifndef USE_HWC2
+ auto releaseFenceTime =
+ std::make_shared<FenceTime>(mSurfaceFlingerConsumer->getPrevFinalReleaseFence());
+ mReleaseTimeline.updateSignalTimes();
+ mReleaseTimeline.push(releaseFenceTime);
+ if (mPreviousFrameNumber != 0) {
+ mFrameEventHistory.addRelease(mPreviousFrameNumber, latchTime,
+ std::move(releaseFenceTime));
+ }
+#endif
+ }
+
+ mRefreshPending = true;
+ mFrameLatencyNeeded = true;
+ if (oldActiveBuffer == NULL) {
+ // the first time we receive a buffer, we need to trigger a
+ // geometry invalidation.
+ recomputeVisibleRegions = true;
+ }
+
+ setDataSpace(mSurfaceFlingerConsumer->getCurrentDataSpace());
+
+ Rect crop(mSurfaceFlingerConsumer->getCurrentCrop());
+ const uint32_t transform(mSurfaceFlingerConsumer->getCurrentTransform());
+ const uint32_t scalingMode(mSurfaceFlingerConsumer->getCurrentScalingMode());
+ if ((crop != mCurrentCrop) || (transform != mCurrentTransform) ||
+ (scalingMode != mCurrentScalingMode)) {
+ mCurrentCrop = crop;
+ mCurrentTransform = transform;
+ mCurrentScalingMode = scalingMode;
+ 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)) {
+ recomputeVisibleRegions = true;
+ }
+ }
+
+ mCurrentOpacity = getOpacityForFormat(mActiveBuffer->format);
+ if (oldOpacity != isOpaque(s)) {
+ recomputeVisibleRegions = true;
+ }
+
+ // Remove any sync points corresponding to the buffer which was just
+ // latched
+ {
+ Mutex::Autolock lock(mLocalSyncPointMutex);
+ auto point = mLocalSyncPoints.begin();
+ while (point != mLocalSyncPoints.end()) {
+ if (!(*point)->frameIsAvailable() || !(*point)->transactionIsApplied()) {
+ // This sync point must have been added since we started
+ // latching. Don't drop it yet.
+ ++point;
+ continue;
+ }
+
+ if ((*point)->getFrameNumber() <= mCurrentFrameNumber) {
+ point = mLocalSyncPoints.erase(point);
+ } else {
+ ++point;
+ }
+ }
+ }
+
+ // FIXME: postedRegion should be dirty & bounds
+ Region dirtyRegion(Rect(s.active.w, s.active.h));
+
+ // transform the dirty region to window-manager space
+ outDirtyRegion = (getTransform().transform(dirtyRegion));
+
+ return outDirtyRegion;
+}
+
+void BufferLayer::setDefaultBufferSize(uint32_t w, uint32_t h) {
+ mSurfaceFlingerConsumer->setDefaultBufferSize(w, h);
+}
+
+#ifdef USE_HWC2
+void BufferLayer::setPerFrameData(const sp<const DisplayDevice>& displayDevice) {
+ // Apply this display's projection's viewport to the visible region
+ // before giving it to the HWC HAL.
+ const Transform& tr = displayDevice->getTransform();
+ const auto& viewport = displayDevice->getViewport();
+ Region visible = tr.transform(visibleRegion.intersect(viewport));
+ auto hwcId = displayDevice->getHwcDisplayId();
+ auto& hwcInfo = mHwcLayers[hwcId];
+ auto& hwcLayer = hwcInfo.layer;
+ auto error = hwcLayer->setVisibleRegion(visible);
+ if (error != HWC2::Error::None) {
+ ALOGE("[%s] Failed to set visible region: %s (%d)", mName.string(),
+ to_string(error).c_str(), static_cast<int32_t>(error));
+ visible.dump(LOG_TAG);
+ }
+
+ error = hwcLayer->setSurfaceDamage(surfaceDamageRegion);
+ if (error != HWC2::Error::None) {
+ ALOGE("[%s] Failed to set surface damage: %s (%d)", mName.string(),
+ to_string(error).c_str(), static_cast<int32_t>(error));
+ surfaceDamageRegion.dump(LOG_TAG);
+ }
+
+ // Sideband layers
+ if (mSidebandStream.get()) {
+ setCompositionType(hwcId, HWC2::Composition::Sideband);
+ ALOGV("[%s] Requesting Sideband composition", mName.string());
+ error = hwcLayer->setSidebandStream(mSidebandStream->handle());
+ if (error != HWC2::Error::None) {
+ ALOGE("[%s] Failed to set sideband stream %p: %s (%d)", mName.string(),
+ mSidebandStream->handle(), to_string(error).c_str(), static_cast<int32_t>(error));
+ }
+ return;
+ }
+
+ // Client layers
+ if (hwcInfo.forceClientComposition ||
+ (mActiveBuffer != nullptr && mActiveBuffer->handle == nullptr)) {
+ ALOGV("[%s] Requesting Client composition", mName.string());
+ setCompositionType(hwcId, HWC2::Composition::Client);
+ return;
+ }
+
+ // Device or Cursor layers
+ if (mPotentialCursor) {
+ ALOGV("[%s] Requesting Cursor composition", mName.string());
+ setCompositionType(hwcId, HWC2::Composition::Cursor);
+ } else {
+ ALOGV("[%s] Requesting Device composition", mName.string());
+ setCompositionType(hwcId, HWC2::Composition::Device);
+ }
+
+ ALOGV("setPerFrameData: dataspace = %d", mCurrentState.dataSpace);
+ error = hwcLayer->setDataspace(mCurrentState.dataSpace);
+ if (error != HWC2::Error::None) {
+ ALOGE("[%s] Failed to set dataspace %d: %s (%d)", mName.string(), mCurrentState.dataSpace,
+ to_string(error).c_str(), static_cast<int32_t>(error));
+ }
+
+ uint32_t hwcSlot = 0;
+ sp<GraphicBuffer> hwcBuffer;
+ hwcInfo.bufferCache.getHwcBuffer(mActiveBufferSlot, mActiveBuffer, &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(), static_cast<int32_t>(error));
+ }
+}
+
+#else
+void BufferLayer::setAcquireFence(const sp<const DisplayDevice>& /* hw */,
+ HWComposer::HWCLayerInterface& layer) {
+ int fenceFd = -1;
+
+ // TODO: there is a possible optimization here: we only need to set the
+ // acquire fence the first time a new buffer is acquired on EACH display.
+
+ if (layer.getCompositionType() == HWC_OVERLAY ||
+ layer.getCompositionType() == HWC_CURSOR_OVERLAY) {
+ sp<Fence> fence = mSurfaceFlingerConsumer->getCurrentFence();
+ if (fence->isValid()) {
+ fenceFd = fence->dup();
+ if (fenceFd == -1) {
+ ALOGW("failed to dup layer fence, skipping sync: %d", errno);
+ }
+ }
+ }
+ layer.setAcquireFenceFd(fenceFd);
+}
+#endif
+
+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 ((mSidebandStream == nullptr) && (mActiveBuffer == nullptr)) {
+ return false;
+ }
+
+ // if the layer has the opaque flag, then we're always opaque,
+ // otherwise we use the current buffer's format.
+ return ((s.flags & layer_state_t::eLayerOpaque) != 0) || mCurrentOpacity;
+}
+
+void BufferLayer::onFirstRef() {
+ // Creates a custom BufferQueue for SurfaceFlingerConsumer to use
+ sp<IGraphicBufferProducer> producer;
+ sp<IGraphicBufferConsumer> consumer;
+ BufferQueue::createBufferQueue(&producer, &consumer, true);
+ mProducer = new MonitoredProducer(producer, mFlinger, this);
+ mSurfaceFlingerConsumer = new SurfaceFlingerConsumer(consumer, mTextureName, this);
+ mSurfaceFlingerConsumer->setConsumerUsageBits(getEffectiveUsage(0));
+ mSurfaceFlingerConsumer->setContentsChangedListener(this);
+ mSurfaceFlingerConsumer->setName(mName);
+
+ if (mFlinger->isLayerTripleBufferingDisabled()) {
+ mProducer->setMaxDequeuedBufferCount(2);
+ }
+
+ const sp<const DisplayDevice> hw(mFlinger->getDefaultDisplayDevice());
+ updateTransformHint(hw);
+}
+
+// ---------------------------------------------------------------------------
+// Interface implementation for SurfaceFlingerConsumer::ContentsChangedListener
+// ---------------------------------------------------------------------------
+
+void BufferLayer::onFrameAvailable(const BufferItem& item) {
+ // Add this buffer from our internal queue tracker
+ { // Autolock scope
+ Mutex::Autolock lock(mQueueItemLock);
+ mFlinger->mInterceptor.saveBufferUpdate(this, item.mGraphicBuffer->getWidth(),
+ item.mGraphicBuffer->getHeight(),
+ item.mFrameNumber);
+ // Reset the frame number tracker when we receive the first buffer after
+ // a frame number reset
+ if (item.mFrameNumber == 1) {
+ mLastFrameNumberReceived = 0;
+ }
+
+ // Ensure that callbacks are handled in order
+ while (item.mFrameNumber != mLastFrameNumberReceived + 1) {
+ status_t result = mQueueItemCondition.waitRelative(mQueueItemLock, ms2ns(500));
+ if (result != NO_ERROR) {
+ ALOGE("[%s] Timed out waiting on callback", mName.string());
+ }
+ }
+
+ mQueueItems.push_back(item);
+ android_atomic_inc(&mQueuedFrames);
+
+ // Wake up any pending callbacks
+ mLastFrameNumberReceived = item.mFrameNumber;
+ mQueueItemCondition.broadcast();
+ }
+
+ mFlinger->signalLayerUpdate();
+}
+
+void BufferLayer::onFrameReplaced(const BufferItem& item) {
+ { // Autolock scope
+ Mutex::Autolock lock(mQueueItemLock);
+
+ // Ensure that callbacks are handled in order
+ while (item.mFrameNumber != mLastFrameNumberReceived + 1) {
+ status_t result = mQueueItemCondition.waitRelative(mQueueItemLock, ms2ns(500));
+ if (result != NO_ERROR) {
+ ALOGE("[%s] Timed out waiting on callback", mName.string());
+ }
+ }
+
+ if (mQueueItems.empty()) {
+ ALOGE("Can't replace a frame on an empty queue");
+ return;
+ }
+ mQueueItems.editItemAt(mQueueItems.size() - 1) = item;
+
+ // Wake up any pending callbacks
+ mLastFrameNumberReceived = item.mFrameNumber;
+ mQueueItemCondition.broadcast();
+ }
+}
+
+void BufferLayer::onSidebandStreamChanged() {
+ if (android_atomic_release_cas(false, true, &mSidebandStreamChanged) == 0) {
+ // mSidebandStreamChanged was false
+ mFlinger->signalLayerUpdate();
+ }
+}
+
+bool BufferLayer::needsFiltering(const RenderArea& renderArea) const {
+ return mNeedsFiltering || renderArea.needsFiltering();
+}
+
+// As documented in libhardware header, formats in the range
+// 0x100 - 0x1FF are specific to the HAL implementation, and
+// are known to have no alpha channel
+// TODO: move definition for device-specific range into
+// hardware.h, instead of using hard-coded values here.
+#define HARDWARE_IS_DEVICE_FORMAT(f) ((f) >= 0x100 && (f) <= 0x1FF)
+
+bool BufferLayer::getOpacityForFormat(uint32_t format) {
+ if (HARDWARE_IS_DEVICE_FORMAT(format)) {
+ return true;
+ }
+ switch (format) {
+ case HAL_PIXEL_FORMAT_RGBA_8888:
+ case HAL_PIXEL_FORMAT_BGRA_8888:
+ case HAL_PIXEL_FORMAT_RGBA_FP16:
+ case HAL_PIXEL_FORMAT_RGBA_1010102:
+ return false;
+ }
+ // in all other case, we have no blending (also for unknown formats)
+ return true;
+}
+
+void BufferLayer::drawWithOpenGL(const RenderArea& renderArea, bool useIdentityTransform) const {
+ const State& s(getDrawingState());
+
+ computeGeometry(renderArea, mMesh, useIdentityTransform);
+
+ /*
+ * NOTE: the way we compute the texture coordinates here produces
+ * different results than when we take the HWC path -- in the later case
+ * the "source crop" is rounded to texel boundaries.
+ * This can produce significantly different results when the texture
+ * is scaled by a large amount.
+ *
+ * The GL code below is more logical (imho), and the difference with
+ * HWC is due to a limitation of the HWC API to integers -- a question
+ * is suspend is whether we should ignore this problem or revert to
+ * GL composition when a buffer scaling is applied (maybe with some
+ * minimal value)? Or, we could make GL behave like HWC -- but this feel
+ * like more of a hack.
+ */
+ Rect win(computeBounds());
+
+ Transform t = getTransform();
+ if (!s.finalCrop.isEmpty()) {
+ win = t.transform(win);
+ if (!win.intersect(s.finalCrop, &win)) {
+ win.clear();
+ }
+ win = t.inverse().transform(win);
+ if (!win.intersect(computeBounds(), &win)) {
+ win.clear();
+ }
+ }
+
+ float left = float(win.left) / float(s.active.w);
+ float top = float(win.top) / float(s.active.h);
+ float right = float(win.right) / float(s.active.w);
+ float bottom = float(win.bottom) / float(s.active.h);
+
+ // TODO: we probably want to generate the texture coords with the mesh
+ // here we assume that we only have 4 vertices
+ Mesh::VertexArray<vec2> texCoords(mMesh.getTexCoordArray<vec2>());
+ texCoords[0] = vec2(left, 1.0f - top);
+ texCoords[1] = vec2(left, 1.0f - bottom);
+ texCoords[2] = vec2(right, 1.0f - bottom);
+ texCoords[3] = vec2(right, 1.0f - top);
+
+ RenderEngine& engine(mFlinger->getRenderEngine());
+ engine.setupLayerBlending(mPremultipliedAlpha, isOpaque(s), false /* disableTexture */,
+ getColor());
+#ifdef USE_HWC2
+ engine.setSourceDataSpace(mCurrentState.dataSpace);
+#endif
+ engine.drawMesh(mMesh);
+ engine.disableBlending();
+}
+
+uint32_t BufferLayer::getProducerStickyTransform() const {
+ int producerStickyTransform = 0;
+ int ret = mProducer->query(NATIVE_WINDOW_STICKY_TRANSFORM, &producerStickyTransform);
+ if (ret != OK) {
+ ALOGW("%s: Error %s (%d) while querying window sticky transform.", __FUNCTION__,
+ strerror(-ret), ret);
+ return 0;
+ }
+ return static_cast<uint32_t>(producerStickyTransform);
+}
+
+bool BufferLayer::latchUnsignaledBuffers() {
+ static bool propertyLoaded = false;
+ static bool latch = false;
+ static std::mutex mutex;
+ std::lock_guard<std::mutex> lock(mutex);
+ if (!propertyLoaded) {
+ char value[PROPERTY_VALUE_MAX] = {};
+ property_get("debug.sf.latch_unsignaled", value, "0");
+ latch = atoi(value);
+ propertyLoaded = true;
+ }
+ return latch;
+}
+
+uint64_t BufferLayer::getHeadFrameNumber() const {
+ Mutex::Autolock lock(mQueueItemLock);
+ if (!mQueueItems.empty()) {
+ return mQueueItems[0].mFrameNumber;
+ } else {
+ return mCurrentFrameNumber;
+ }
+}
+
+bool BufferLayer::headFenceHasSignaled() const {
+#ifdef USE_HWC2
+ if (latchUnsignaledBuffers()) {
+ return true;
+ }
+
+ Mutex::Autolock lock(mQueueItemLock);
+ if (mQueueItems.empty()) {
+ return true;
+ }
+ if (mQueueItems[0].mIsDroppable) {
+ // Even though this buffer's fence may not have signaled yet, it could
+ // be replaced by another buffer before it has a chance to, which means
+ // that it's possible to get into a situation where a buffer is never
+ // able to be latched. To avoid this, grab this buffer anyway.
+ return true;
+ }
+ return mQueueItems[0].mFenceTime->getSignalTime() != Fence::SIGNAL_TIME_PENDING;
+#else
+ return true;
+#endif
+}
+
+uint32_t BufferLayer::getEffectiveScalingMode() const {
+ if (mOverrideScalingMode >= 0) {
+ return mOverrideScalingMode;
+ }
+ return mCurrentScalingMode;
+}
+
+// ----------------------------------------------------------------------------
+// transaction
+// ----------------------------------------------------------------------------
+
+void BufferLayer::notifyAvailableFrames() {
+ auto headFrameNumber = getHeadFrameNumber();
+ bool headFenceSignaled = headFenceHasSignaled();
+ Mutex::Autolock lock(mLocalSyncPointMutex);
+ for (auto& point : mLocalSyncPoints) {
+ if (headFrameNumber >= point->getFrameNumber() && headFenceSignaled) {
+ point->setFrameAvailable();
+ }
+ }
+}
+
+sp<IGraphicBufferProducer> BufferLayer::getProducer() const {
+ return mProducer;
+}
+
+// ---------------------------------------------------------------------------
+// h/w composer set-up
+// ---------------------------------------------------------------------------
+
+bool BufferLayer::allTransactionsSignaled() {
+ auto headFrameNumber = getHeadFrameNumber();
+ bool matchingFramesFound = false;
+ bool allTransactionsApplied = true;
+ Mutex::Autolock lock(mLocalSyncPointMutex);
+
+ for (auto& point : mLocalSyncPoints) {
+ if (point->getFrameNumber() > headFrameNumber) {
+ break;
+ }
+ matchingFramesFound = true;
+
+ if (!point->frameIsAvailable()) {
+ // We haven't notified the remote layer that the frame for
+ // this point is available yet. Notify it now, and then
+ // abort this attempt to latch.
+ point->setFrameAvailable();
+ allTransactionsApplied = false;
+ break;
+ }
+
+ allTransactionsApplied = allTransactionsApplied && point->transactionIsApplied();
+ }
+ return !matchingFramesFound || allTransactionsApplied;
+}
+
+} // namespace android
+
+#if defined(__gl_h_)
+#error "don't include gl/gl.h in this file"
+#endif
+
+#if defined(__gl2_h_)
+#error "don't include gl2/gl2.h in this file"
+#endif
diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h
new file mode 100644
index 0000000..418f032
--- /dev/null
+++ b/services/surfaceflinger/BufferLayer.h
@@ -0,0 +1,211 @@
+/*
+ * Copyright (C) 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 "Client.h"
+#include "Layer.h"
+#include "DisplayHardware/HWComposer.h"
+#include "DisplayHardware/HWComposerBufferCache.h"
+#include "FrameTracker.h"
+#include "LayerVector.h"
+#include "MonitoredProducer.h"
+#include "RenderEngine/Mesh.h"
+#include "RenderEngine/Texture.h"
+#include "SurfaceFlinger.h"
+#include "SurfaceFlingerConsumer.h"
+#include "Transform.h"
+
+#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>
+#include <ui/Region.h>
+
+#include <utils/RefBase.h>
+#include <utils/String8.h>
+#include <utils/Timers.h>
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <list>
+
+namespace android {
+
+/*
+ * A new BufferQueue and a new SurfaceFlingerConsumer are created when the
+ * BufferLayer is first referenced.
+ *
+ * This also implements onFrameAvailable(), which notifies SurfaceFlinger
+ * that new data has arrived.
+ */
+class BufferLayer : public Layer, public SurfaceFlingerConsumer::ContentsChangedListener {
+public:
+ BufferLayer(SurfaceFlinger* flinger, const sp<Client>& client, const String8& name, uint32_t w,
+ uint32_t h, uint32_t flags);
+
+ ~BufferLayer() override;
+
+ // If we have received a new buffer this frame, we will pass its surface
+ // damage down to hardware composer. Otherwise, we must send a region with
+ // one empty rect.
+ void useSurfaceDamage();
+ void useEmptyDamage();
+
+ // -----------------------------------------------------------------------
+ // Overriden from Layer
+ // -----------------------------------------------------------------------
+
+ /*
+ * getTypeId - Provide unique string for each class type in the Layer
+ * hierarchy
+ */
+ const char* getTypeId() const override { return "BufferLayer"; }
+
+ /*
+ * isProtected - true if the layer may contain protected content in the
+ * GRALLOC_USAGE_PROTECTED sense.
+ */
+ bool isProtected() const;
+
+ /*
+ * isVisible - true if this layer is visible, false otherwise
+ */
+ bool isVisible() const override;
+
+ /*
+ * isFixedSize - true if content has a fixed size
+ */
+ bool isFixedSize() const override;
+
+ // the this layer's size and format
+ status_t setBuffers(uint32_t w, uint32_t h, PixelFormat format, uint32_t flags);
+
+ /*
+ * onDraw - draws the surface.
+ */
+ void onDraw(const RenderArea& renderArea, const Region& clip,
+ bool useIdentityTransform) const override;
+
+#ifdef USE_HWC2
+ void onLayerDisplayed(const sp<Fence>& releaseFence) override;
+#else
+ void onLayerDisplayed(const sp<const DisplayDevice>& hw,
+ HWComposer::HWCLayerInterface* layer) override;
+#endif
+
+ void abandon() override;
+ bool shouldPresentNow(const DispSync& dispSync) const override;
+ void setTransformHint(uint32_t orientation) const override;
+ bool onPostComposition(const std::shared_ptr<FenceTime>& glDoneFence,
+ const std::shared_ptr<FenceTime>& presentFence,
+ const CompositorTiming& compositorTiming) override;
+ std::vector<OccupancyTracker::Segment> getOccupancyHistory(bool forceFlush) override;
+ bool getTransformToDisplayInverse() const override;
+
+public:
+ bool onPreComposition(nsecs_t refreshStartTime) override;
+
+#ifdef USE_HWC2
+ // If a buffer was replaced this frame, release the former buffer
+ void releasePendingBuffer(nsecs_t dequeueReadyTime);
+#endif
+
+ /*
+ * latchBuffer - called each time the screen is redrawn and returns whether
+ * the visible regions need to be recomputed (this is a fairly heavy
+ * operation, so this should be set only if needed). Typically this is used
+ * to figure out if the content or size of a surface has changed.
+ */
+ Region latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime) override;
+ bool isBufferLatched() const override { return mRefreshPending; }
+ void setDefaultBufferSize(uint32_t w, uint32_t h) override;
+
+#ifdef USE_HWC2
+ void setPerFrameData(const sp<const DisplayDevice>& displayDevice) override;
+#else
+ void setAcquireFence(const sp<const DisplayDevice>& hw,
+ HWComposer::HWCLayerInterface& layer) override;
+#endif
+
+ bool isOpaque(const Layer::State& s) const override;
+
+private:
+ void onFirstRef() override;
+
+ // Interface implementation for
+ // SurfaceFlingerConsumer::ContentsChangedListener
+ void onFrameAvailable(const BufferItem& item) override;
+ void onFrameReplaced(const BufferItem& item) override;
+ void onSidebandStreamChanged() override;
+
+ // needsLinearFiltering - true if this surface's state requires filtering
+ bool needsFiltering(const RenderArea& renderArea) const;
+
+ static bool getOpacityForFormat(uint32_t format);
+
+ // drawing
+ void drawWithOpenGL(const RenderArea& renderArea, bool useIdentityTransform) const;
+
+ // Temporary - Used only for LEGACY camera mode.
+ uint32_t getProducerStickyTransform() const;
+
+ // Loads the corresponding system property once per process
+ static bool latchUnsignaledBuffers();
+
+ uint64_t getHeadFrameNumber() const;
+ bool headFenceHasSignaled() const;
+
+ // Returns the current scaling mode, unless mOverrideScalingMode
+ // is set, in which case, it returns mOverrideScalingMode
+ uint32_t getEffectiveScalingMode() const override;
+
+public:
+ void notifyAvailableFrames() override;
+
+ PixelFormat getPixelFormat() const override { return mFormat; }
+ sp<IGraphicBufferProducer> getProducer() const;
+
+private:
+ sp<SurfaceFlingerConsumer> mSurfaceFlingerConsumer;
+
+ // Check all of the local sync points to ensure that all transactions
+ // which need to have been applied prior to the frame which is about to
+ // be latched have signaled
+ bool allTransactionsSignaled();
+ sp<IGraphicBufferProducer> mProducer;
+
+ // constants
+ uint32_t mTextureName; // from GLES
+ PixelFormat mFormat;
+
+ // main thread
+ uint32_t mCurrentScalingMode;
+ bool mBufferLatched = false; // TODO: Use mActiveBuffer?
+ uint64_t mPreviousFrameNumber; // Only accessed on the main thread.
+ // The texture used to draw the layer in GLES composition mode
+ mutable Texture mTexture;
+
+ bool mUpdateTexImageFailed; // This is only accessed on the main thread.
+ bool mRefreshPending;
+};
+
+} // namespace android
diff --git a/services/surfaceflinger/Client.cpp b/services/surfaceflinger/Client.cpp
index e9a2513..ea6541a 100644
--- a/services/surfaceflinger/Client.cpp
+++ b/services/surfaceflinger/Client.cpp
@@ -57,9 +57,19 @@
}
void Client::setParentLayer(const sp<Layer>& parentLayer) {
+ Mutex::Autolock _l(mLock);
mParentLayer = parentLayer;
}
+sp<Layer> Client::getParentLayer(bool* outParentDied) const {
+ Mutex::Autolock _l(mLock);
+ sp<Layer> parent = mParentLayer.promote();
+ if (outParentDied != nullptr) {
+ *outParentDied = (mParentLayer != nullptr && parent == nullptr);
+ }
+ return parent;
+}
+
status_t Client::initCheck() const {
return NO_ERROR;
}
@@ -108,7 +118,7 @@
// We grant an exception in the case that the Client has a "parent layer", as its
// effects will be scoped to that layer.
if (CC_UNLIKELY(pid != self_pid && uid != AID_GRAPHICS && uid != AID_SYSTEM && uid != 0)
- && (mParentLayer.promote() == nullptr)) {
+ && (getParentLayer() == nullptr)) {
// we're called from a different process, do the real check
if (!PermissionCache::checkCallingPermission(sAccessSurfaceFlinger))
{
@@ -130,16 +140,18 @@
{
sp<Layer> parent = nullptr;
if (parentHandle != nullptr) {
- parent = getLayerUser(parentHandle);
+ auto layerHandle = reinterpret_cast<Layer::Handle*>(parentHandle.get());
+ parent = layerHandle->owner.promote();
if (parent == nullptr) {
return NAME_NOT_FOUND;
}
}
- if (parent == nullptr && mParentLayer != nullptr) {
- parent = mParentLayer.promote();
+ if (parent == nullptr) {
+ bool parentDied;
+ parent = getParentLayer(&parentDied);
// If we had a parent, but it died, we've lost all
// our capabilities.
- if (parent == nullptr) {
+ if (parentDied) {
return NAME_NOT_FOUND;
}
}
diff --git a/services/surfaceflinger/Client.h b/services/surfaceflinger/Client.h
index b5f98b8..2aab28f 100644
--- a/services/surfaceflinger/Client.h
+++ b/services/surfaceflinger/Client.h
@@ -71,12 +71,13 @@
virtual status_t onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);
+ sp<Layer> getParentLayer(bool* outParentDied = nullptr) const;
+
// constant
sp<SurfaceFlinger> mFlinger;
// protected by mLock
DefaultKeyedVector< wp<IBinder>, wp<Layer> > mLayers;
-
wp<Layer> mParentLayer;
// thread-safe
diff --git a/services/surfaceflinger/ColorLayer.cpp b/services/surfaceflinger/ColorLayer.cpp
new file mode 100644
index 0000000..8a17f88
--- /dev/null
+++ b/services/surfaceflinger/ColorLayer.cpp
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// #define LOG_NDEBUG 0
+#undef LOG_TAG
+#define LOG_TAG "ColorLayer"
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <sys/types.h>
+
+#include <utils/Errors.h>
+#include <utils/Log.h>
+
+#include <ui/GraphicBuffer.h>
+
+#include "ColorLayer.h"
+#include "DisplayDevice.h"
+#include "RenderEngine/RenderEngine.h"
+#include "SurfaceFlinger.h"
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+ColorLayer::ColorLayer(SurfaceFlinger* flinger, const sp<Client>& client, const String8& name,
+ uint32_t w, uint32_t h, uint32_t flags)
+ : Layer(flinger, client, name, w, h, flags) {
+ // drawing state & current state are identical
+ mDrawingState = mCurrentState;
+}
+
+void ColorLayer::onDraw(const RenderArea& renderArea, const Region& /* clip */,
+ bool useIdentityTransform) const {
+ const State& s(getDrawingState());
+ if (s.color.a > 0) {
+ Mesh mesh(Mesh::TRIANGLE_FAN, 4, 2);
+ computeGeometry(renderArea, mesh, useIdentityTransform);
+ RenderEngine& engine(mFlinger->getRenderEngine());
+ engine.setupLayerBlending(getPremultipledAlpha(), false /* opaque */,
+ true /* disableTexture */, s.color);
+ engine.drawMesh(mesh);
+ engine.disableBlending();
+ }
+}
+
+bool ColorLayer::isVisible() const {
+ const Layer::State& s(getDrawingState());
+ return !isHiddenByPolicy() && s.color.a;
+}
+
+#ifdef USE_HWC2
+void ColorLayer::setPerFrameData(const sp<const DisplayDevice>& displayDevice) {
+ const Transform& tr = displayDevice->getTransform();
+ const auto& viewport = displayDevice->getViewport();
+ Region visible = tr.transform(visibleRegion.intersect(viewport));
+ auto hwcId = displayDevice->getHwcDisplayId();
+ auto& hwcInfo = mHwcLayers[hwcId];
+ auto& hwcLayer = hwcInfo.layer;
+ auto error = hwcLayer->setVisibleRegion(visible);
+
+ setCompositionType(hwcId, HWC2::Composition::SolidColor);
+
+ half4 color = getColor();
+ error = hwcLayer->setColor({static_cast<uint8_t>(std::round(255.0f * color.r)),
+ static_cast<uint8_t>(std::round(255.0f * color.g)),
+ static_cast<uint8_t>(std::round(255.0f * color.b)), 255});
+ if (error != HWC2::Error::None) {
+ ALOGE("[%s] Failed to set color: %s (%d)", mName.string(), to_string(error).c_str(),
+ static_cast<int32_t>(error));
+ }
+
+ // Clear out the transform, because it doesn't make sense absent a source buffer
+ error = hwcLayer->setTransform(HWC2::Transform::None);
+ if (error != HWC2::Error::None) {
+ ALOGE("[%s] Failed to clear transform: %s (%d)", mName.string(), to_string(error).c_str(),
+ static_cast<int32_t>(error));
+ }
+}
+#endif
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/services/surfaceflinger/ColorLayer.h b/services/surfaceflinger/ColorLayer.h
new file mode 100644
index 0000000..debd3c3
--- /dev/null
+++ b/services/surfaceflinger/ColorLayer.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_COLOR_LAYER_H
+#define ANDROID_COLOR_LAYER_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include "Layer.h"
+
+// ---------------------------------------------------------------------------
+
+namespace android {
+
+class ColorLayer : public Layer {
+public:
+ ColorLayer(SurfaceFlinger* flinger, const sp<Client>& client, const String8& name, uint32_t w,
+ uint32_t h, uint32_t flags);
+ virtual ~ColorLayer() = default;
+
+ virtual const char* getTypeId() const { return "ColorLayer"; }
+ virtual void onDraw(const RenderArea& renderArea, const Region& clip,
+ bool useIdentityTransform) const;
+ bool isVisible() const override;
+ virtual bool isOpaque(const Layer::State&) const { return false; }
+ virtual bool isFixedSize() const { return true; }
+
+ void notifyAvailableFrames() override {}
+ PixelFormat getPixelFormat() const override { return PIXEL_FORMAT_NONE; }
+ uint32_t getEffectiveScalingMode() const override { return 0; }
+#ifdef USE_HWC2
+ void releasePendingBuffer(nsecs_t) override {}
+#endif
+ Region latchBuffer(bool&, nsecs_t) override { return Region(); }
+ void useSurfaceDamage() override {}
+ void useEmptyDamage() override {}
+ bool isBufferLatched() const override { return false; }
+ bool onPreComposition(nsecs_t) override { return true; }
+ void abandon() override {}
+#ifdef USE_HWC2
+ void setPerFrameData(const sp<const DisplayDevice>& displayDevice) override;
+#else
+ void setAcquireFence(const sp<const DisplayDevice>& /*hw*/,
+ HWComposer::HWCLayerInterface& /*layer*/) override {}
+#endif
+ void setDefaultBufferSize(uint32_t /*w*/, uint32_t /*h*/) override {}
+ bool shouldPresentNow(const DispSync& /*dispSync*/) const override { return false; }
+ bool onPostComposition(const std::shared_ptr<FenceTime>& /*glDoneFence*/,
+ const std::shared_ptr<FenceTime>& /*presentFence*/,
+ const CompositorTiming& /*compositorTiming*/) override {
+ return false;
+ }
+ void setTransformHint(uint32_t /*orientation*/) const override {}
+ std::vector<OccupancyTracker::Segment> getOccupancyHistory(bool /*forceFlush*/) override {
+ return {};
+ }
+ bool getTransformToDisplayInverse() const override { return false; }
+};
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_COLOR_LAYER_H
diff --git a/services/surfaceflinger/DispSync.cpp b/services/surfaceflinger/DispSync.cpp
index bd9b8aa..bef12ea 100644
--- a/services/surfaceflinger/DispSync.cpp
+++ b/services/surfaceflinger/DispSync.cpp
@@ -30,7 +30,7 @@
#include <utils/Trace.h>
#include <utils/Vector.h>
-#include <ui/Fence.h>
+#include <ui/FenceTime.h>
#include "DispSync.h"
#include "SurfaceFlinger.h"
@@ -377,11 +377,16 @@
DispSync::DispSync(const char* name) :
mName(name),
mRefreshSkipCount(0),
- mThread(new DispSyncThread(name)),
- mIgnorePresentFences(!SurfaceFlinger::hasSyncFramework){
+ mThread(new DispSyncThread(name)) {
+}
- mPresentTimeOffset = SurfaceFlinger::dispSyncPresentTimeOffset;
+DispSync::~DispSync() {}
+
+void DispSync::init(bool hasSyncFramework, int64_t dispSyncPresentTimeOffset) {
+ mIgnorePresentFences = !hasSyncFramework;
+ mPresentTimeOffset = dispSyncPresentTimeOffset;
mThread->run("DispSync", PRIORITY_URGENT_DISPLAY + PRIORITY_MORE_FAVORABLE);
+
// set DispSync to SCHED_FIFO to minimize jitter
struct sched_param param = {0};
param.sched_priority = 2;
@@ -389,7 +394,6 @@
ALOGE("Couldn't set SCHED_FIFO for DispSyncThread");
}
-
reset();
beginResync();
@@ -405,8 +409,6 @@
}
}
-DispSync::~DispSync() {}
-
void DispSync::reset() {
Mutex::Autolock lock(mMutex);
@@ -419,25 +421,13 @@
resetErrorLocked();
}
-bool DispSync::addPresentFence(const sp<Fence>& fence) {
+bool DispSync::addPresentFence(const std::shared_ptr<FenceTime>& fenceTime) {
Mutex::Autolock lock(mMutex);
- mPresentFences[mPresentSampleOffset] = fence;
- mPresentTimes[mPresentSampleOffset] = 0;
+ mPresentFences[mPresentSampleOffset] = fenceTime;
mPresentSampleOffset = (mPresentSampleOffset + 1) % NUM_PRESENT_SAMPLES;
mNumResyncSamplesSincePresent = 0;
- for (size_t i = 0; i < NUM_PRESENT_SAMPLES; i++) {
- const sp<Fence>& f(mPresentFences[i]);
- if (f != NULL) {
- nsecs_t t = f->getSignalTime();
- if (t < INT64_MAX) {
- mPresentFences[i].clear();
- mPresentTimes[i] = t + mPresentTimeOffset;
- }
- }
- }
-
updateErrorLocked();
return !mModelUpdated || mError > kErrorThreshold;
@@ -602,21 +592,39 @@
nsecs_t sqErrSum = 0;
for (size_t i = 0; i < NUM_PRESENT_SAMPLES; i++) {
- nsecs_t sample = mPresentTimes[i] - mReferenceTime;
- if (sample > mPhase) {
- nsecs_t sampleErr = (sample - mPhase) % period;
- if (sampleErr > period / 2) {
- sampleErr -= period;
- }
- sqErrSum += sampleErr * sampleErr;
- numErrSamples++;
+ // Only check for the cached value of signal time to avoid unecessary
+ // syscalls. It is the responsibility of the DispSync owner to
+ // call getSignalTime() periodically so the cache is updated when the
+ // fence signals.
+ nsecs_t time = mPresentFences[i]->getCachedSignalTime();
+ if (time == Fence::SIGNAL_TIME_PENDING ||
+ time == Fence::SIGNAL_TIME_INVALID) {
+ continue;
}
+
+ nsecs_t sample = time - mReferenceTime;
+ if (sample <= mPhase) {
+ continue;
+ }
+
+ nsecs_t sampleErr = (sample - mPhase) % period;
+ if (sampleErr > period / 2) {
+ sampleErr -= period;
+ }
+ sqErrSum += sampleErr * sampleErr;
+ numErrSamples++;
}
if (numErrSamples > 0) {
mError = sqErrSum / numErrSamples;
+ mZeroErrSamplesCount = 0;
} else {
mError = 0;
+ // Use mod ACCEPTABLE_ZERO_ERR_SAMPLES_COUNT to avoid log spam.
+ mZeroErrSamplesCount++;
+ ALOGE_IF(
+ (mZeroErrSamplesCount % ACCEPTABLE_ZERO_ERR_SAMPLES_COUNT) == 0,
+ "No present times for model error.");
}
if (kTraceDetailedInfo) {
@@ -627,9 +635,9 @@
void DispSync::resetErrorLocked() {
mPresentSampleOffset = 0;
mError = 0;
+ mZeroErrSamplesCount = 0;
for (size_t i = 0; i < NUM_PRESENT_SAMPLES; i++) {
- mPresentFences[i].clear();
- mPresentTimes[i] = 0;
+ mPresentFences[i] = FenceTime::NO_FENCE;
}
}
@@ -668,19 +676,19 @@
previous = sampleTime;
}
- result.appendFormat("mPresentFences / mPresentTimes [%d]:\n",
+ result.appendFormat("mPresentFences [%d]:\n",
NUM_PRESENT_SAMPLES);
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
- previous = 0;
+ previous = Fence::SIGNAL_TIME_INVALID;
for (size_t i = 0; i < NUM_PRESENT_SAMPLES; i++) {
size_t idx = (i + mPresentSampleOffset) % NUM_PRESENT_SAMPLES;
- bool signaled = mPresentFences[idx] == NULL;
- nsecs_t presentTime = mPresentTimes[idx];
- if (!signaled) {
+ nsecs_t presentTime = mPresentFences[idx]->getSignalTime();
+ if (presentTime == Fence::SIGNAL_TIME_PENDING) {
result.appendFormat(" [unsignaled fence]\n");
- } else if (presentTime == 0) {
- result.appendFormat(" 0\n");
- } else if (previous == 0) {
+ } else if(presentTime == Fence::SIGNAL_TIME_INVALID) {
+ result.appendFormat(" [invalid fence]\n");
+ } else if (previous == Fence::SIGNAL_TIME_PENDING ||
+ previous == Fence::SIGNAL_TIME_INVALID) {
result.appendFormat(" %" PRId64 " (%.3f ms ago)\n", presentTime,
(now - presentTime) / 1000000.0);
} else {
diff --git a/services/surfaceflinger/DispSync.h b/services/surfaceflinger/DispSync.h
index 82ae795..880a24d 100644
--- a/services/surfaceflinger/DispSync.h
+++ b/services/surfaceflinger/DispSync.h
@@ -23,10 +23,14 @@
#include <utils/Timers.h>
#include <utils/RefBase.h>
+#include <ui/FenceTime.h>
+
+#include <memory>
+
namespace android {
class String8;
-class Fence;
+class FenceTime;
class DispSyncThread;
// DispSync maintains a model of the periodic hardware-based vsync events of a
@@ -55,6 +59,8 @@
explicit DispSync(const char* name);
~DispSync();
+ void init(bool hasSyncFramework, int64_t dispSyncPresentTimeOffset);
+
// reset clears the resync samples and error value.
void reset();
@@ -67,7 +73,7 @@
//
// This method should be called with the retire fence from each HWComposer
// set call that affects the display.
- bool addPresentFence(const sp<Fence>& fence);
+ bool addPresentFence(const std::shared_ptr<FenceTime>& fenceTime);
// The beginResync, addResyncSample, and endResync methods are used to re-
// synchronize the DispSync's model to the hardware vsync events. The re-
@@ -129,6 +135,7 @@
enum { MIN_RESYNC_SAMPLES_FOR_UPDATE = 6 };
enum { NUM_PRESENT_SAMPLES = 8 };
enum { MAX_RESYNC_SAMPLES_WITHOUT_PRESENT = 4 };
+ enum { ACCEPTABLE_ZERO_ERR_SAMPLES_COUNT = 64 };
const char* const mName;
@@ -146,9 +153,14 @@
// mError is the computed model error. It is based on the difference
// between the estimated vsync event times and those observed in the
- // mPresentTimes array.
+ // mPresentFences array.
nsecs_t mError;
+ // mZeroErrSamplesCount keeps track of how many times in a row there were
+ // zero timestamps available in the mPresentFences array.
+ // Used to sanity check that we are able to calculate the model error.
+ size_t mZeroErrSamplesCount;
+
// Whether we have updated the vsync event model since the last resync.
bool mModelUpdated;
@@ -162,8 +174,8 @@
// These member variables store information about the present fences used
// to validate the currently computed model.
- sp<Fence> mPresentFences[NUM_PRESENT_SAMPLES];
- nsecs_t mPresentTimes[NUM_PRESENT_SAMPLES];
+ std::shared_ptr<FenceTime>
+ mPresentFences[NUM_PRESENT_SAMPLES] {FenceTime::NO_FENCE};
size_t mPresentSampleOffset;
int mRefreshSkipCount;
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index a0abf12..0244c1b 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -28,6 +28,7 @@
#include <utils/RefBase.h>
#include <utils/Log.h>
+#include <ui/DebugUtils.h>
#include <ui/DisplayInfo.h>
#include <ui/PixelFormat.h>
@@ -65,7 +66,7 @@
using namespace android::hardware::configstore::V1_0;
static bool useTripleFramebuffer = getInt64< ISurfaceFlingerConfigs,
- &ISurfaceFlingerConfigs::maxFrameBufferAcquiredBuffers>(2) == 3;
+ &ISurfaceFlingerConfigs::maxFrameBufferAcquiredBuffers>(2) >= 3;
#if !defined(EGL_EGLEXT_PROTOTYPES) || !defined(EGL_ANDROID_swap_rectangle)
// Dummy implementation in case it is missing.
@@ -134,9 +135,11 @@
EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
if (config == EGL_NO_CONFIG) {
#ifdef USE_HWC2
- config = RenderEngine::chooseEglConfig(display, PIXEL_FORMAT_RGBA_8888);
+ config = RenderEngine::chooseEglConfig(display, PIXEL_FORMAT_RGBA_8888,
+ /*logConfig*/ false);
#else
- config = RenderEngine::chooseEglConfig(display, format);
+ config = RenderEngine::chooseEglConfig(display, format,
+ /*logConfig*/ false);
#endif
}
eglSurface = eglCreateWindowSurface(display, config, window, NULL);
@@ -442,6 +445,11 @@
android_color_mode_t DisplayDevice::getActiveColorMode() const {
return mActiveColorMode;
}
+
+void DisplayDevice::setCompositionDataSpace(android_dataspace dataspace) {
+ ANativeWindow* const window = mNativeWindow.get();
+ native_window_set_buffers_data_space(window, dataspace);
+}
#endif
// ----------------------------------------------------------------------------
@@ -610,6 +618,7 @@
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);
@@ -619,9 +628,9 @@
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,
- mNativeWindow.get(), redSize, greenSize, blueSize, alphaSize, mOrientation,
- tr.getType(), getPageFlipCount(), mIsSecure, mPowerMode, mActiveConfig,
+ mType, mHwcDisplayId, mLayerStack, mDisplayWidth, mDisplayHeight, window,
+ redSize, greenSize, blueSize, alphaSize, 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],"
"transform:[[%0.3f,%0.3f,%0.3f][%0.3f,%0.3f,%0.3f][%0.3f,%0.3f,%0.3f]]\n",
@@ -629,6 +638,9 @@
mFrame.left, mFrame.top, mFrame.right, mFrame.bottom, mScissor.left,
mScissor.top, mScissor.right, mScissor.bottom, tr[0][0], tr[1][0], tr[2][0],
tr[0][1], tr[1][1], tr[2][1], tr[0][2], tr[1][2], tr[2][2]);
+ auto const surface = static_cast<Surface*>(window);
+ android_dataspace dataspace = surface->getBuffersDataSpace();
+ result.appendFormat(" dataspace: %s (%d)\n", dataspaceDetails(dataspace).c_str(), dataspace);
String8 surfaceDump;
mDisplaySurface->dumpAsString(surfaceDump);
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index e2852a7..49fef58 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -37,7 +37,9 @@
#include <utils/String8.h>
#include <utils/Timers.h>
+#include <gui/ISurfaceComposer.h>
#include <hardware/hwcomposer_defs.h>
+#include "RenderArea.h"
#ifdef USE_HWC2
#include <memory>
@@ -141,6 +143,7 @@
uint32_t getLayerStack() const { return mLayerStack; }
int32_t getDisplayType() const { return mType; }
+ bool isPrimary() const { return mType == DISPLAY_PRIMARY; }
int32_t getHwcDisplayId() const { return mHwcDisplayId; }
const wp<IBinder>& getDisplayToken() const { return mDisplayToken; }
@@ -189,6 +192,7 @@
#ifdef USE_HWC2
android_color_mode_t getActiveColorMode() const;
void setActiveColorMode(android_color_mode_t mode);
+ void setCompositionDataSpace(android_dataspace dataspace);
#endif
/* ------------------------------------------------------------------------
@@ -298,6 +302,35 @@
bool isSecure = false;
};
+class DisplayRenderArea : public RenderArea {
+public:
+ DisplayRenderArea(const sp<const DisplayDevice> device,
+ ISurfaceComposer::Rotation rotation = ISurfaceComposer::eRotateNone)
+ : DisplayRenderArea(device, device->getBounds(), device->getHeight(), device->getWidth(),
+ rotation) {}
+ DisplayRenderArea(const sp<const DisplayDevice> device, Rect sourceCrop, uint32_t reqHeight,
+ uint32_t reqWidth, ISurfaceComposer::Rotation rotation)
+ : RenderArea(reqHeight, reqWidth, rotation), mDevice(device), mSourceCrop(sourceCrop) {}
+
+ const Transform& getTransform() const override { return mDevice->getTransform(); }
+ Rect getBounds() const override { return mDevice->getBounds(); }
+ int getHeight() const override { return mDevice->getHeight(); }
+ int getWidth() const override { return mDevice->getWidth(); }
+ bool isSecure() const override { return mDevice->isSecure(); }
+ bool needsFiltering() const override { return mDevice->needsFiltering(); }
+ Rect getSourceCrop() const override { return mSourceCrop; }
+#ifdef USE_HWC2
+ bool getWideColorSupport() const override { return mDevice->getWideColorSupport(); }
+ android_color_mode_t getActiveColorMode() const override {
+ return mDevice->getActiveColorMode();
+ }
+#endif
+
+private:
+ const sp<const DisplayDevice> mDevice;
+ const Rect mSourceCrop;
+};
+
}; // namespace android
#endif // ANDROID_DISPLAY_DEVICE_H
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
index ae628e1..c707e3c 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
@@ -157,15 +157,11 @@
write64(metadata.usage);
}
-Composer::Composer(bool useVrComposer)
+Composer::Composer(const std::string& serviceName)
: mWriter(kWriterInitialSize),
- mIsUsingVrComposer(useVrComposer)
+ mIsUsingVrComposer(serviceName == std::string("vr"))
{
- if (mIsUsingVrComposer) {
- mComposer = IComposer::getService("vr");
- } else {
- mComposer = IComposer::getService(); // use default name
- }
+ mComposer = IComposer::getService(serviceName);
if (mComposer == nullptr) {
LOG_ALWAYS_FATAL("failed to get hwcomposer service");
@@ -219,10 +215,18 @@
}
}
+bool Composer::isRemote() {
+ return mClient->isRemote();
+}
+
void Composer::resetCommands() {
mWriter.reset();
}
+Error Composer::executeCommands() {
+ return execute();
+}
+
uint32_t Composer::getMaxVirtualDisplayCount()
{
auto ret = mClient->getMaxVirtualDisplayCount();
@@ -553,6 +557,29 @@
return Error::NONE;
}
+Error Composer::presentOrValidateDisplay(Display display, uint32_t* outNumTypes,
+ uint32_t* outNumRequests, int* outPresentFence, uint32_t* state) {
+ mWriter.selectDisplay(display);
+ mWriter.presentOrvalidateDisplay();
+
+ Error error = execute();
+ if (error != Error::NONE) {
+ return error;
+ }
+
+ mReader.takePresentOrValidateStage(display, state);
+
+ if (*state == 1) { // Present succeeded
+ mReader.takePresentFence(display, outPresentFence);
+ }
+
+ if (*state == 0) { // Validate succeeded.
+ mReader.hasChanges(display, outNumTypes, outNumRequests);
+ }
+
+ return Error::NONE;
+}
+
Error Composer::setCursorPosition(Display display, Layer layer,
int32_t x, int32_t y)
{
@@ -727,8 +754,13 @@
}
}
+ if (commandLength == 0) {
+ mWriter.reset();
+ return Error::NONE;
+ }
+
Error error = kDefaultError;
- mClient->executeCommands(commandLength, commandHandles,
+ auto ret = mClient->executeCommands(commandLength, commandHandles,
[&](const auto& tmpError, const auto& tmpOutChanged,
const auto& tmpOutLength, const auto& tmpOutHandles)
{
@@ -761,6 +793,11 @@
error = Error::NO_RESOURCES;
}
});
+ // executeCommands can fail because of out-of-fd and we do not want to
+ // abort() in that case
+ if (!ret.isOk()) {
+ ALOGE("executeCommands failed because of %s", ret.description().c_str());
+ }
if (error == Error::NONE) {
std::vector<CommandReader::CommandError> commandErrors =
@@ -770,7 +807,8 @@
auto command = mWriter.getCommand(cmdErr.location);
if (command == IComposerClient::Command::VALIDATE_DISPLAY ||
- command == IComposerClient::Command::PRESENT_DISPLAY) {
+ command == IComposerClient::Command::PRESENT_DISPLAY ||
+ command == IComposerClient::Command::PRESENT_OR_VALIDATE_DISPLAY) {
error = cmdErr.error;
} else {
ALOGW("command 0x%x generated error %d",
@@ -821,6 +859,9 @@
case IComposerClient::Command::SET_RELEASE_FENCES:
parsed = parseSetReleaseFences(length);
break;
+ case IComposerClient::Command ::SET_PRESENT_OR_VALIDATE_DISPLAY_RESULT:
+ parsed = parseSetPresentOrValidateDisplayResult(length);
+ break;
default:
parsed = false;
break;
@@ -949,6 +990,15 @@
return true;
}
+bool CommandReader::parseSetPresentOrValidateDisplayResult(uint16_t length)
+{
+ if (length != CommandWriterBase::kPresentOrValidateDisplayResultLength || !mCurrentReturnData) {
+ return false;
+ }
+ mCurrentReturnData->presentOrValidateState = read();
+ return true;
+}
+
void CommandReader::resetData()
{
mErrors.clear();
@@ -1058,6 +1108,16 @@
data.presentFence = -1;
}
+void CommandReader::takePresentOrValidateStage(Display display, uint32_t* state) {
+ auto found = mReturnData.find(display);
+ if (found == mReturnData.end()) {
+ *state= -1;
+ return;
+ }
+ ReturnData& data = found->second;
+ *state = data.presentOrValidateState;
+}
+
} // namespace Hwc2
} // namespace android
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.h b/services/surfaceflinger/DisplayHardware/ComposerHal.h
index 68d6e6f..104ca60 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.h
@@ -93,6 +93,9 @@
// Get and clear saved present fence.
void takePresentFence(Display display, int* outPresentFence);
+ // Get what stage succeeded during PresentOrValidate: Present or Validate
+ void takePresentOrValidateStage(Display display, uint32_t * state);
+
private:
void resetData();
@@ -102,6 +105,7 @@
bool parseSetDisplayRequests(uint16_t length);
bool parseSetPresentFence(uint16_t length);
bool parseSetReleaseFences(uint16_t length);
+ bool parseSetPresentOrValidateDisplayResult(uint16_t length);
struct ReturnData {
uint32_t displayRequests = 0;
@@ -116,6 +120,8 @@
std::vector<Layer> releasedLayers;
std::vector<int> releaseFences;
+
+ uint32_t presentOrValidateState;
};
std::vector<CommandError> mErrors;
@@ -130,17 +136,25 @@
// Composer is a wrapper to IComposer, a proxy to server-side composer.
class Composer {
public:
- Composer(bool useVrComposer);
+ Composer(const std::string& serviceName);
std::vector<IComposer::Capability> getCapabilities();
std::string dumpDebugInfo();
void registerCallback(const sp<IComposerCallback>& callback);
+ // Returns true if the connected composer service is running in a remote
+ // process, false otherwise. This will return false if the service is
+ // configured in passthrough mode, for example.
+ bool isRemote();
+
// Reset all pending commands in the command buffer. Useful if you want to
// skip a frame but have already queued some commands.
void resetCommands();
+ // Explicitly flush all pending commands in the command buffer.
+ Error executeCommands();
+
uint32_t getMaxVirtualDisplayCount();
bool isUsingVrComposer() const { return mIsUsingVrComposer; }
Error createVirtualDisplay(uint32_t width, uint32_t height,
@@ -202,6 +216,11 @@
Error validateDisplay(Display display, uint32_t* outNumTypes,
uint32_t* outNumRequests);
+ Error presentOrValidateDisplay(Display display, uint32_t* outNumTypes,
+ uint32_t* outNumRequests,
+ int* outPresentFence,
+ uint32_t* state);
+
Error setCursorPosition(Display display, Layer layer,
int32_t x, int32_t y);
/* see setClientTarget for the purpose of slot */
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
index 5b869e1..93c6d54 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
@@ -34,6 +34,7 @@
#include <gui/BufferQueue.h>
#include <gui/Surface.h>
+#include <ui/DebugUtils.h>
#include <ui/GraphicBuffer.h>
#include <ui/Rect.h>
@@ -103,15 +104,10 @@
sp<Fence> acquireFence(Fence::NO_FENCE);
android_dataspace_t dataspace = HAL_DATASPACE_UNKNOWN;
status_t result = nextBuffer(slot, buf, acquireFence, dataspace);
+ mDataSpace = dataspace;
if (result != NO_ERROR) {
ALOGE("error latching next FramebufferSurface buffer: %s (%d)",
strerror(-result), result);
- return result;
- }
- result = mHwc.setClientTarget(mDisplayType, slot,
- acquireFence, buf, dataspace);
- if (result != NO_ERROR) {
- ALOGE("error posting framebuffer: %d", result);
}
return result;
#else
@@ -179,9 +175,16 @@
mHwcBufferCache.getHwcBuffer(mCurrentBufferSlot, mCurrentBuffer,
&outSlot, &outBuffer);
outDataspace = item.mDataSpace;
+ status_t result =
+ mHwc.setClientTarget(mDisplayType, outSlot, outFence, outBuffer, outDataspace);
+ if (result != NO_ERROR) {
+ ALOGE("error posting framebuffer: %d", result);
+ return result;
+ }
#else
outBuffer = mCurrentBuffer;
#endif
+
return NO_ERROR;
}
@@ -248,7 +251,10 @@
#endif
void FramebufferSurface::dumpAsString(String8& result) const {
- ConsumerBase::dumpState(result);
+ Mutex::Autolock lock(mMutex);
+ result.appendFormat("FramebufferSurface: dataspace: %s(%d)\n",
+ dataspaceDetails(mDataSpace).c_str(), mDataSpace);
+ ConsumerBase::dumpLocked(result, "");
}
void FramebufferSurface::dumpLocked(String8& result, const char* prefix) const
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
index 69a72d7..a1756ca 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
@@ -83,6 +83,13 @@
// or the buffer is not associated with a slot.
int mCurrentBufferSlot;
+ // mDataSpace is the dataspace of the current composition buffer for
+ // this FramebufferSurface. It will be 0 when HWC is doing the
+ // compositing. Otherwise it will display the dataspace of the buffer
+ // use for compositing which can change as wide-color content is
+ // on/off.
+ android_dataspace mDataSpace;
+
// mCurrentBuffer is the current buffer or NULL to indicate that there is
// no current buffer.
sp<GraphicBuffer> mCurrentBuffer;
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp
index 0366630..ab4a4b2 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp
@@ -33,45 +33,6 @@
#include <algorithm>
#include <inttypes.h>
-extern "C" {
- static void hotplug_hook(hwc2_callback_data_t callbackData,
- hwc2_display_t displayId, int32_t intConnected) {
- auto device = static_cast<HWC2::Device*>(callbackData);
- auto display = device->getDisplayById(displayId);
- if (display) {
- auto connected = static_cast<HWC2::Connection>(intConnected);
- device->callHotplug(std::move(display), connected);
- } else {
- ALOGE("Hotplug callback called with unknown display %" PRIu64,
- displayId);
- }
- }
-
- static void refresh_hook(hwc2_callback_data_t callbackData,
- hwc2_display_t displayId) {
- auto device = static_cast<HWC2::Device*>(callbackData);
- auto display = device->getDisplayById(displayId);
- if (display) {
- device->callRefresh(std::move(display));
- } else {
- ALOGE("Refresh callback called with unknown display %" PRIu64,
- displayId);
- }
- }
-
- static void vsync_hook(hwc2_callback_data_t callbackData,
- hwc2_display_t displayId, int64_t timestamp) {
- auto device = static_cast<HWC2::Device*>(callbackData);
- auto display = device->getDisplayById(displayId);
- if (display) {
- device->callVsync(std::move(display), timestamp);
- } else {
- ALOGE("Vsync callback called with unknown display %" PRIu64,
- displayId);
- }
- }
-}
-
using android::Fence;
using android::FloatRect;
using android::GraphicBuffer;
@@ -86,51 +47,78 @@
namespace Hwc2 = android::Hwc2;
+namespace {
+
+class ComposerCallbackBridge : public Hwc2::IComposerCallback {
+public:
+ ComposerCallbackBridge(ComposerCallback* callback, int32_t sequenceId)
+ : mCallback(callback), mSequenceId(sequenceId),
+ mHasPrimaryDisplay(false) {}
+
+ Return<void> onHotplug(Hwc2::Display display,
+ IComposerCallback::Connection conn) override
+ {
+ HWC2::Connection connection = static_cast<HWC2::Connection>(conn);
+ if (!mHasPrimaryDisplay) {
+ LOG_ALWAYS_FATAL_IF(connection != HWC2::Connection::Connected,
+ "Initial onHotplug callback should be "
+ "primary display connected");
+ mHasPrimaryDisplay = true;
+ mCallback->onHotplugReceived(mSequenceId, display,
+ connection, true);
+ } else {
+ mCallback->onHotplugReceived(mSequenceId, display,
+ connection, false);
+ }
+ return Void();
+ }
+
+ Return<void> onRefresh(Hwc2::Display display) override
+ {
+ mCallback->onRefreshReceived(mSequenceId, display);
+ return Void();
+ }
+
+ Return<void> onVsync(Hwc2::Display display, int64_t timestamp) override
+ {
+ mCallback->onVsyncReceived(mSequenceId, display, timestamp);
+ return Void();
+ }
+
+ bool HasPrimaryDisplay() { return mHasPrimaryDisplay; }
+
+private:
+ ComposerCallback* mCallback;
+ int32_t mSequenceId;
+ bool mHasPrimaryDisplay;
+};
+
+} // namespace anonymous
+
+
// Device methods
-Device::Device(bool useVrComposer)
- : mComposer(std::make_unique<Hwc2::Composer>(useVrComposer)),
+Device::Device(const std::string& serviceName)
+ : mComposer(std::make_unique<Hwc2::Composer>(serviceName)),
mCapabilities(),
mDisplays(),
- mHotplug(),
- mPendingHotplugs(),
- mRefresh(),
- mPendingRefreshes(),
- mVsync(),
- mPendingVsyncs()
+ mRegisteredCallback(false)
{
loadCapabilities();
- registerCallbacks();
}
-Device::~Device()
-{
- for (auto element : mDisplays) {
- auto display = element.second.lock();
- if (!display) {
- ALOGE("~Device: Found a display (%" PRId64 " that has already been"
- " destroyed", element.first);
- continue;
- }
-
- DisplayType displayType = HWC2::DisplayType::Invalid;
- auto error = display->getType(&displayType);
- if (error != Error::None) {
- ALOGE("~Device: Failed to determine type of display %" PRIu64
- ": %s (%d)", display->getId(), to_string(error).c_str(),
- static_cast<int32_t>(error));
- continue;
- }
-
- if (displayType == HWC2::DisplayType::Physical) {
- error = display->setVsyncEnabled(HWC2::Vsync::Disable);
- if (error != Error::None) {
- ALOGE("~Device: Failed to disable vsync for display %" PRIu64
- ": %s (%d)", display->getId(), to_string(error).c_str(),
- static_cast<int32_t>(error));
- }
- }
+void Device::registerCallback(ComposerCallback* callback, int32_t sequenceId) {
+ if (mRegisteredCallback) {
+ ALOGW("Callback already registered. Ignored extra registration "
+ "attempt.");
+ return;
}
+ mRegisteredCallback = true;
+ sp<ComposerCallbackBridge> callbackBridge(
+ new ComposerCallbackBridge(callback, sequenceId));
+ mComposer->registerCallback(callbackBridge);
+ LOG_ALWAYS_FATAL_IF(!callbackBridge->HasPrimaryDisplay(),
+ "Registered composer callback but didn't get primary display");
}
// Required by HWC2 device
@@ -146,7 +134,7 @@
}
Error Device::createVirtualDisplay(uint32_t width, uint32_t height,
- android_pixel_format_t* format, std::shared_ptr<Display>* outDisplay)
+ android_pixel_format_t* format, Display** outDisplay)
{
ALOGI("Creating virtual display");
@@ -159,104 +147,66 @@
return error;
}
- ALOGI("Created virtual display");
+ auto display = std::make_unique<Display>(
+ *mComposer.get(), mCapabilities, displayId, DisplayType::Virtual);
+ *outDisplay = display.get();
*format = static_cast<android_pixel_format_t>(intFormat);
- *outDisplay = getDisplayById(displayId);
- if (!*outDisplay) {
- ALOGE("Failed to get display by id");
- return Error::BadDisplay;
- }
- (*outDisplay)->setConnected(true);
+ mDisplays.emplace(displayId, std::move(display));
+ ALOGI("Created virtual display");
return Error::None;
}
-void Device::registerHotplugCallback(HotplugCallback hotplug)
+void Device::destroyDisplay(hwc2_display_t displayId)
{
- ALOGV("registerHotplugCallback");
- mHotplug = hotplug;
- for (auto& pending : mPendingHotplugs) {
- auto& display = pending.first;
- auto connected = pending.second;
- ALOGV("Sending pending hotplug(%" PRIu64 ", %s)", display->getId(),
- to_string(connected).c_str());
- mHotplug(std::move(display), connected);
- }
+ ALOGI("Destroying display %" PRIu64, displayId);
+ mDisplays.erase(displayId);
}
-void Device::registerRefreshCallback(RefreshCallback refresh)
-{
- mRefresh = refresh;
- for (auto& pending : mPendingRefreshes) {
- mRefresh(std::move(pending));
- }
-}
+void Device::onHotplug(hwc2_display_t displayId, Connection connection) {
+ if (connection == Connection::Connected) {
+ auto display = getDisplayById(displayId);
+ if (display) {
+ if (display->isConnected()) {
+ ALOGW("Attempt to hotplug connect display %" PRIu64
+ " , which is already connected.", displayId);
+ } else {
+ display->setConnected(true);
+ }
+ } else {
+ DisplayType displayType;
+ auto intError = mComposer->getDisplayType(displayId,
+ reinterpret_cast<Hwc2::IComposerClient::DisplayType *>(
+ &displayType));
+ auto error = static_cast<Error>(intError);
+ if (error != Error::None) {
+ ALOGE("getDisplayType(%" PRIu64 ") failed: %s (%d). "
+ "Aborting hotplug attempt.",
+ displayId, to_string(error).c_str(), intError);
+ return;
+ }
-void Device::registerVsyncCallback(VsyncCallback vsync)
-{
- mVsync = vsync;
- for (auto& pending : mPendingVsyncs) {
- auto& display = pending.first;
- auto timestamp = pending.second;
- mVsync(std::move(display), timestamp);
- }
-}
-
-// For use by Device callbacks
-
-void Device::callHotplug(std::shared_ptr<Display> display, Connection connected)
-{
- if (connected == Connection::Connected) {
- if (!display->isConnected()) {
- mComposer->setClientTargetSlotCount(display->getId());
- display->loadConfigs();
- display->setConnected(true);
+ auto newDisplay = std::make_unique<Display>(
+ *mComposer.get(), mCapabilities, displayId, displayType);
+ mDisplays.emplace(displayId, std::move(newDisplay));
}
- } else {
- display->setConnected(false);
- mDisplays.erase(display->getId());
- }
-
- if (mHotplug) {
- mHotplug(std::move(display), connected);
- } else {
- ALOGV("callHotplug called, but no valid callback registered, storing");
- mPendingHotplugs.emplace_back(std::move(display), connected);
- }
-}
-
-void Device::callRefresh(std::shared_ptr<Display> display)
-{
- if (mRefresh) {
- mRefresh(std::move(display));
- } else {
- ALOGV("callRefresh called, but no valid callback registered, storing");
- mPendingRefreshes.emplace_back(std::move(display));
- }
-}
-
-void Device::callVsync(std::shared_ptr<Display> display, nsecs_t timestamp)
-{
- if (mVsync) {
- mVsync(std::move(display), timestamp);
- } else {
- ALOGV("callVsync called, but no valid callback registered, storing");
- mPendingVsyncs.emplace_back(std::move(display), timestamp);
+ } else if (connection == Connection::Disconnected) {
+ // The display will later be destroyed by a call to
+ // destroyDisplay(). For now we just mark it disconnected.
+ auto display = getDisplayById(displayId);
+ if (display) {
+ display->setConnected(false);
+ } else {
+ ALOGW("Attempted to disconnect unknown display %" PRIu64,
+ displayId);
+ }
}
}
// Other Device methods
-std::shared_ptr<Display> Device::getDisplayById(hwc2_display_t id) {
- if (mDisplays.count(id) != 0) {
- auto strongDisplay = mDisplays[id].lock();
- ALOGE_IF(!strongDisplay, "Display %" PRId64 " is in mDisplays but is no"
- " longer alive", id);
- return strongDisplay;
- }
-
- auto display = std::make_shared<Display>(*this, id);
- mDisplays.emplace(id, display);
- return display;
+Display* Device::getDisplayById(hwc2_display_t id) {
+ auto iter = mDisplays.find(id);
+ return iter == mDisplays.end() ? nullptr : iter->second.get();
}
// Device initialization methods
@@ -271,84 +221,42 @@
}
}
-bool Device::hasCapability(HWC2::Capability capability) const
+Error Device::flushCommands()
{
- return std::find(mCapabilities.cbegin(), mCapabilities.cend(),
- capability) != mCapabilities.cend();
-}
-
-namespace {
-class ComposerCallback : public Hwc2::IComposerCallback {
-public:
- ComposerCallback(Device* device) : mDevice(device) {}
-
- Return<void> onHotplug(Hwc2::Display display,
- Connection connected) override
- {
- hotplug_hook(mDevice, display, static_cast<int32_t>(connected));
- return Void();
- }
-
- Return<void> onRefresh(Hwc2::Display display) override
- {
- refresh_hook(mDevice, display);
- return Void();
- }
-
- Return<void> onVsync(Hwc2::Display display, int64_t timestamp) override
- {
- vsync_hook(mDevice, display, timestamp);
- return Void();
- }
-
-private:
- Device* mDevice;
-};
-} // namespace anonymous
-
-void Device::registerCallbacks()
-{
- sp<ComposerCallback> callback = new ComposerCallback(this);
- mComposer->registerCallback(callback);
-}
-
-
-// For use by Display
-
-void Device::destroyVirtualDisplay(hwc2_display_t display)
-{
- ALOGI("Destroying virtual display");
- auto intError = mComposer->destroyVirtualDisplay(display);
- auto error = static_cast<Error>(intError);
- ALOGE_IF(error != Error::None, "destroyVirtualDisplay(%" PRIu64 ") failed:"
- " %s (%d)", display, to_string(error).c_str(), intError);
- mDisplays.erase(display);
+ return static_cast<Error>(mComposer->executeCommands());
}
// Display methods
-Display::Display(Device& device, hwc2_display_t id)
- : mDevice(device),
+Display::Display(android::Hwc2::Composer& composer,
+ const std::unordered_set<Capability>& capabilities,
+ hwc2_display_t id, DisplayType type)
+ : mComposer(composer),
+ mCapabilities(capabilities),
mId(id),
mIsConnected(false),
- mType(DisplayType::Invalid)
+ mType(type)
{
ALOGV("Created display %" PRIu64, id);
-
- auto intError = mDevice.mComposer->getDisplayType(mId,
- reinterpret_cast<Hwc2::IComposerClient::DisplayType *>(&mType));
- auto error = static_cast<Error>(intError);
- if (error != Error::None) {
- ALOGE("getDisplayType(%" PRIu64 ") failed: %s (%d)",
- id, to_string(error).c_str(), intError);
- }
+ setConnected(true);
}
-Display::~Display()
-{
- ALOGV("Destroyed display %" PRIu64, mId);
+Display::~Display() {
+ mLayers.clear();
+
if (mType == DisplayType::Virtual) {
- mDevice.destroyVirtualDisplay(mId);
+ ALOGV("Destroying virtual display");
+ auto intError = mComposer.destroyVirtualDisplay(mId);
+ auto error = static_cast<Error>(intError);
+ ALOGE_IF(error != Error::None, "destroyVirtualDisplay(%" PRIu64
+ ") failed: %s (%d)", mId, to_string(error).c_str(), intError);
+ } else if (mType == DisplayType::Physical) {
+ auto error = setVsyncEnabled(HWC2::Vsync::Disable);
+ if (error != Error::None) {
+ ALOGE("~Display: Failed to disable vsync for display %" PRIu64
+ ": %s (%d)", mId, to_string(error).c_str(),
+ static_cast<int32_t>(error));
+ }
}
}
@@ -383,22 +291,35 @@
Error Display::acceptChanges()
{
- auto intError = mDevice.mComposer->acceptDisplayChanges(mId);
+ auto intError = mComposer.acceptDisplayChanges(mId);
return static_cast<Error>(intError);
}
-Error Display::createLayer(std::shared_ptr<Layer>* outLayer)
+Error Display::createLayer(Layer** outLayer)
{
+ if (!outLayer) {
+ return Error::BadParameter;
+ }
hwc2_layer_t layerId = 0;
- auto intError = mDevice.mComposer->createLayer(mId, &layerId);
+ auto intError = mComposer.createLayer(mId, &layerId);
auto error = static_cast<Error>(intError);
if (error != Error::None) {
return error;
}
- auto layer = std::make_shared<Layer>(shared_from_this(), layerId);
- mLayers.emplace(layerId, layer);
- *outLayer = std::move(layer);
+ auto layer = std::make_unique<Layer>(
+ mComposer, mCapabilities, mId, layerId);
+ *outLayer = layer.get();
+ mLayers.emplace(layerId, std::move(layer));
+ return Error::None;
+}
+
+Error Display::destroyLayer(Layer* layer)
+{
+ if (!layer) {
+ return Error::BadParameter;
+ }
+ mLayers.erase(layer->getId());
return Error::None;
}
@@ -407,7 +328,7 @@
{
ALOGV("[%" PRIu64 "] getActiveConfig", mId);
hwc2_config_t configId = 0;
- auto intError = mDevice.mComposer->getActiveConfig(mId, &configId);
+ auto intError = mComposer.getActiveConfig(mId, &configId);
auto error = static_cast<Error>(intError);
if (error != Error::None) {
@@ -430,12 +351,12 @@
}
Error Display::getChangedCompositionTypes(
- std::unordered_map<std::shared_ptr<Layer>, Composition>* outTypes)
+ std::unordered_map<Layer*, Composition>* outTypes)
{
std::vector<Hwc2::Layer> layerIds;
std::vector<Hwc2::IComposerClient::Composition> types;
- auto intError = mDevice.mComposer->getChangedCompositionTypes(mId,
- &layerIds, &types);
+ auto intError = mComposer.getChangedCompositionTypes(
+ mId, &layerIds, &types);
uint32_t numElements = layerIds.size();
auto error = static_cast<Error>(intError);
error = static_cast<Error>(intError);
@@ -464,7 +385,7 @@
Error Display::getColorModes(std::vector<android_color_mode_t>* outModes) const
{
std::vector<Hwc2::ColorMode> modes;
- auto intError = mDevice.mComposer->getColorModes(mId, &modes);
+ auto intError = mComposer.getColorModes(mId, &modes);
uint32_t numModes = modes.size();
auto error = static_cast<Error>(intError);
if (error != Error::None) {
@@ -489,19 +410,18 @@
Error Display::getName(std::string* outName) const
{
- auto intError = mDevice.mComposer->getDisplayName(mId, outName);
+ auto intError = mComposer.getDisplayName(mId, outName);
return static_cast<Error>(intError);
}
Error Display::getRequests(HWC2::DisplayRequest* outDisplayRequests,
- std::unordered_map<std::shared_ptr<Layer>, LayerRequest>*
- outLayerRequests)
+ std::unordered_map<Layer*, LayerRequest>* outLayerRequests)
{
uint32_t intDisplayRequests;
std::vector<Hwc2::Layer> layerIds;
std::vector<uint32_t> layerRequests;
- auto intError = mDevice.mComposer->getDisplayRequests(mId,
- &intDisplayRequests, &layerIds, &layerRequests);
+ auto intError = mComposer.getDisplayRequests(
+ mId, &intDisplayRequests, &layerIds, &layerRequests);
uint32_t numElements = layerIds.size();
auto error = static_cast<Error>(intError);
if (error != Error::None) {
@@ -535,7 +455,7 @@
Error Display::supportsDoze(bool* outSupport) const
{
bool intSupport = false;
- auto intError = mDevice.mComposer->getDozeSupport(mId, &intSupport);
+ auto intError = mComposer.getDozeSupport(mId, &intSupport);
auto error = static_cast<Error>(intError);
if (error != Error::None) {
return error;
@@ -552,7 +472,7 @@
float maxAverageLuminance = -1.0f;
float minLuminance = -1.0f;
std::vector<Hwc2::Hdr> intTypes;
- auto intError = mDevice.mComposer->getHdrCapabilities(mId, &intTypes,
+ auto intError = mComposer.getHdrCapabilities(mId, &intTypes,
&maxLuminance, &maxAverageLuminance, &minLuminance);
auto error = static_cast<HWC2::Error>(intError);
@@ -571,25 +491,24 @@
}
Error Display::getReleaseFences(
- std::unordered_map<std::shared_ptr<Layer>, sp<Fence>>* outFences) const
+ std::unordered_map<Layer*, sp<Fence>>* outFences) const
{
std::vector<Hwc2::Layer> layerIds;
std::vector<int> fenceFds;
- auto intError = mDevice.mComposer->getReleaseFences(mId,
- &layerIds, &fenceFds);
+ auto intError = mComposer.getReleaseFences(mId, &layerIds, &fenceFds);
auto error = static_cast<Error>(intError);
uint32_t numElements = layerIds.size();
if (error != Error::None) {
return error;
}
- std::unordered_map<std::shared_ptr<Layer>, sp<Fence>> releaseFences;
+ std::unordered_map<Layer*, sp<Fence>> releaseFences;
releaseFences.reserve(numElements);
for (uint32_t element = 0; element < numElements; ++element) {
auto layer = getLayerById(layerIds[element]);
if (layer) {
sp<Fence> fence(new Fence(fenceFds[element]));
- releaseFences.emplace(std::move(layer), fence);
+ releaseFences.emplace(layer, fence);
} else {
ALOGE("getReleaseFences: invalid layer %" PRIu64
" found on display %" PRIu64, layerIds[element], mId);
@@ -607,7 +526,7 @@
Error Display::present(sp<Fence>* outPresentFence)
{
int32_t presentFenceFd = -1;
- auto intError = mDevice.mComposer->presentDisplay(mId, &presentFenceFd);
+ auto intError = mComposer.presentDisplay(mId, &presentFenceFd);
auto error = static_cast<Error>(intError);
if (error != Error::None) {
return error;
@@ -625,7 +544,7 @@
config->getDisplayId(), mId);
return Error::BadConfig;
}
- auto intError = mDevice.mComposer->setActiveConfig(mId, config->getId());
+ auto intError = mComposer.setActiveConfig(mId, config->getId());
return static_cast<Error>(intError);
}
@@ -634,7 +553,7 @@
{
// TODO: Properly encode client target surface damage
int32_t fenceFd = acquireFence->dup();
- auto intError = mDevice.mComposer->setClientTarget(mId, slot, target,
+ auto intError = mComposer.setClientTarget(mId, slot, target,
fenceFd, static_cast<Hwc2::Dataspace>(dataspace),
std::vector<Hwc2::IComposerClient::Rect>());
return static_cast<Error>(intError);
@@ -642,15 +561,15 @@
Error Display::setColorMode(android_color_mode_t mode)
{
- auto intError = mDevice.mComposer->setColorMode(mId,
- static_cast<Hwc2::ColorMode>(mode));
+ auto intError = mComposer.setColorMode(
+ mId, static_cast<Hwc2::ColorMode>(mode));
return static_cast<Error>(intError);
}
Error Display::setColorTransform(const android::mat4& matrix,
android_color_transform_t hint)
{
- auto intError = mDevice.mComposer->setColorTransform(mId,
+ auto intError = mComposer.setColorTransform(mId,
matrix.asArray(), static_cast<Hwc2::ColorTransform>(hint));
return static_cast<Error>(intError);
}
@@ -660,7 +579,7 @@
{
int32_t fenceFd = releaseFence->dup();
auto handle = buffer->getNativeBuffer()->handle;
- auto intError = mDevice.mComposer->setOutputBuffer(mId, handle, fenceFd);
+ auto intError = mComposer.setOutputBuffer(mId, handle, fenceFd);
close(fenceFd);
return static_cast<Error>(intError);
}
@@ -668,14 +587,14 @@
Error Display::setPowerMode(PowerMode mode)
{
auto intMode = static_cast<Hwc2::IComposerClient::PowerMode>(mode);
- auto intError = mDevice.mComposer->setPowerMode(mId, intMode);
+ auto intError = mComposer.setPowerMode(mId, intMode);
return static_cast<Error>(intError);
}
Error Display::setVsyncEnabled(Vsync enabled)
{
auto intEnabled = static_cast<Hwc2::IComposerClient::Vsync>(enabled);
- auto intError = mDevice.mComposer->setVsyncEnabled(mId, intEnabled);
+ auto intError = mComposer.setVsyncEnabled(mId, intEnabled);
return static_cast<Error>(intError);
}
@@ -683,8 +602,7 @@
{
uint32_t numTypes = 0;
uint32_t numRequests = 0;
- auto intError = mDevice.mComposer->validateDisplay(mId,
- &numTypes, &numRequests);
+ auto intError = mComposer.validateDisplay(mId, &numTypes, &numRequests);
auto error = static_cast<Error>(intError);
if (error != Error::None && error != Error::HasChanges) {
return error;
@@ -695,12 +613,44 @@
return error;
}
+Error Display::presentOrValidate(uint32_t* outNumTypes, uint32_t* outNumRequests,
+ sp<android::Fence>* outPresentFence, uint32_t* state) {
+
+ uint32_t numTypes = 0;
+ uint32_t numRequests = 0;
+ int32_t presentFenceFd = -1;
+ auto intError = mComposer.presentOrValidateDisplay(
+ mId, &numTypes, &numRequests, &presentFenceFd, state);
+ auto error = static_cast<Error>(intError);
+ if (error != Error::None && error != Error::HasChanges) {
+ return error;
+ }
+
+ if (*state == 1) {
+ *outPresentFence = new Fence(presentFenceFd);
+ }
+
+ if (*state == 0) {
+ *outNumTypes = numTypes;
+ *outNumRequests = numRequests;
+ }
+ return error;
+}
+
// For use by Device
+void Display::setConnected(bool connected) {
+ if (!mIsConnected && connected && mType == DisplayType::Physical) {
+ mComposer.setClientTargetSlotCount(mId);
+ loadConfigs();
+ }
+ mIsConnected = connected;
+}
+
int32_t Display::getAttribute(hwc2_config_t configId, Attribute attribute)
{
int32_t value = 0;
- auto intError = mDevice.mComposer->getDisplayAttribute(mId, configId,
+ auto intError = mComposer.getDisplayAttribute(mId, configId,
static_cast<Hwc2::IComposerClient::Attribute>(attribute),
&value);
auto error = static_cast<Error>(intError);
@@ -732,7 +682,7 @@
ALOGV("[%" PRIu64 "] loadConfigs", mId);
std::vector<Hwc2::Config> configIds;
- auto intError = mDevice.mComposer->getDisplayConfigs(mId, &configIds);
+ auto intError = mComposer.getDisplayConfigs(mId, &configIds);
auto error = static_cast<Error>(intError);
if (error != Error::None) {
ALOGE("[%" PRIu64 "] getDisplayConfigs [2] failed: %s (%d)", mId,
@@ -745,54 +695,51 @@
}
}
-// For use by Layer
-
-void Display::destroyLayer(hwc2_layer_t layerId)
-{
- auto intError =mDevice.mComposer->destroyLayer(mId, layerId);
- auto error = static_cast<Error>(intError);
- ALOGE_IF(error != Error::None, "destroyLayer(%" PRIu64 ", %" PRIu64 ")"
- " failed: %s (%d)", mId, layerId, to_string(error).c_str(),
- intError);
- mLayers.erase(layerId);
-}
-
// Other Display methods
-std::shared_ptr<Layer> Display::getLayerById(hwc2_layer_t id) const
+Layer* Display::getLayerById(hwc2_layer_t id) const
{
if (mLayers.count(id) == 0) {
return nullptr;
}
- auto layer = mLayers.at(id).lock();
- return layer;
+ return mLayers.at(id).get();
}
// Layer methods
-Layer::Layer(const std::shared_ptr<Display>& display, hwc2_layer_t id)
- : mDisplay(display),
- mDisplayId(display->getId()),
- mDevice(display->getDevice()),
- mId(id)
+Layer::Layer(android::Hwc2::Composer& composer,
+ const std::unordered_set<Capability>& capabilities,
+ hwc2_display_t displayId, hwc2_layer_t layerId)
+ : mComposer(composer),
+ mCapabilities(capabilities),
+ mDisplayId(displayId),
+ mId(layerId)
{
- ALOGV("Created layer %" PRIu64 " on display %" PRIu64, id,
- display->getId());
+ ALOGV("Created layer %" PRIu64 " on display %" PRIu64, layerId, displayId);
}
Layer::~Layer()
{
- auto display = mDisplay.lock();
- if (display) {
- display->destroyLayer(mId);
+ auto intError = mComposer.destroyLayer(mDisplayId, mId);
+ auto error = static_cast<Error>(intError);
+ ALOGE_IF(error != Error::None, "destroyLayer(%" PRIu64 ", %" PRIu64 ")"
+ " failed: %s (%d)", mDisplayId, mId, to_string(error).c_str(),
+ intError);
+ if (mLayerDestroyedListener) {
+ mLayerDestroyedListener(this);
}
}
+void Layer::setLayerDestroyedListener(std::function<void(Layer*)> listener) {
+ LOG_ALWAYS_FATAL_IF(mLayerDestroyedListener && listener,
+ "Attempt to set layer destroyed listener multiple times");
+ mLayerDestroyedListener = listener;
+}
+
Error Layer::setCursorPosition(int32_t x, int32_t y)
{
- auto intError = mDevice.mComposer->setCursorPosition(mDisplayId,
- mId, x, y);
+ auto intError = mComposer.setCursorPosition(mDisplayId, mId, x, y);
return static_cast<Error>(intError);
}
@@ -800,8 +747,8 @@
const sp<Fence>& acquireFence)
{
int32_t fenceFd = acquireFence->dup();
- auto intError = mDevice.mComposer->setLayerBuffer(mDisplayId,
- mId, slot, buffer, fenceFd);
+ auto intError = mComposer.setLayerBuffer(mDisplayId, mId, slot, buffer,
+ fenceFd);
return static_cast<Error>(intError);
}
@@ -811,7 +758,7 @@
// rects for HWC
Hwc2::Error intError = Hwc2::Error::NONE;
if (damage.isRect() && damage.getBounds() == Rect::INVALID_RECT) {
- intError = mDevice.mComposer->setLayerSurfaceDamage(mDisplayId,
+ intError = mComposer.setLayerSurfaceDamage(mDisplayId,
mId, std::vector<Hwc2::IComposerClient::Rect>());
} else {
size_t rectCount = 0;
@@ -823,8 +770,7 @@
rectArray[rect].right, rectArray[rect].bottom});
}
- intError = mDevice.mComposer->setLayerSurfaceDamage(mDisplayId,
- mId, hwcRects);
+ intError = mComposer.setLayerSurfaceDamage(mDisplayId, mId, hwcRects);
}
return static_cast<Error>(intError);
@@ -833,32 +779,33 @@
Error Layer::setBlendMode(BlendMode mode)
{
auto intMode = static_cast<Hwc2::IComposerClient::BlendMode>(mode);
- auto intError = mDevice.mComposer->setLayerBlendMode(mDisplayId,
- mId, intMode);
+ auto intError = mComposer.setLayerBlendMode(mDisplayId, mId, intMode);
return static_cast<Error>(intError);
}
Error Layer::setColor(hwc_color_t color)
{
Hwc2::IComposerClient::Color hwcColor{color.r, color.g, color.b, color.a};
- auto intError = mDevice.mComposer->setLayerColor(mDisplayId,
- mId, hwcColor);
+ auto intError = mComposer.setLayerColor(mDisplayId, mId, hwcColor);
return static_cast<Error>(intError);
}
Error Layer::setCompositionType(Composition type)
{
auto intType = static_cast<Hwc2::IComposerClient::Composition>(type);
- auto intError = mDevice.mComposer->setLayerCompositionType(mDisplayId,
- mId, intType);
+ auto intError = mComposer.setLayerCompositionType(
+ mDisplayId, mId, intType);
return static_cast<Error>(intError);
}
Error Layer::setDataspace(android_dataspace_t dataspace)
{
+ if (dataspace == mDataSpace) {
+ return Error::None;
+ }
+ mDataSpace = dataspace;
auto intDataspace = static_cast<Hwc2::Dataspace>(dataspace);
- auto intError = mDevice.mComposer->setLayerDataspace(mDisplayId,
- mId, intDataspace);
+ auto intError = mComposer.setLayerDataspace(mDisplayId, mId, intDataspace);
return static_cast<Error>(intError);
}
@@ -866,27 +813,24 @@
{
Hwc2::IComposerClient::Rect hwcRect{frame.left, frame.top,
frame.right, frame.bottom};
- auto intError = mDevice.mComposer->setLayerDisplayFrame(mDisplayId,
- mId, hwcRect);
+ auto intError = mComposer.setLayerDisplayFrame(mDisplayId, mId, hwcRect);
return static_cast<Error>(intError);
}
Error Layer::setPlaneAlpha(float alpha)
{
- auto intError = mDevice.mComposer->setLayerPlaneAlpha(mDisplayId,
- mId, alpha);
+ auto intError = mComposer.setLayerPlaneAlpha(mDisplayId, mId, alpha);
return static_cast<Error>(intError);
}
Error Layer::setSidebandStream(const native_handle_t* stream)
{
- if (!mDevice.hasCapability(Capability::SidebandStream)) {
+ if (mCapabilities.count(Capability::SidebandStream) == 0) {
ALOGE("Attempted to call setSidebandStream without checking that the "
"device supports sideband streams");
return Error::Unsupported;
}
- auto intError = mDevice.mComposer->setLayerSidebandStream(mDisplayId,
- mId, stream);
+ auto intError = mComposer.setLayerSidebandStream(mDisplayId, mId, stream);
return static_cast<Error>(intError);
}
@@ -894,16 +838,14 @@
{
Hwc2::IComposerClient::FRect hwcRect{
crop.left, crop.top, crop.right, crop.bottom};
- auto intError = mDevice.mComposer->setLayerSourceCrop(mDisplayId,
- mId, hwcRect);
+ auto intError = mComposer.setLayerSourceCrop(mDisplayId, mId, hwcRect);
return static_cast<Error>(intError);
}
Error Layer::setTransform(Transform transform)
{
auto intTransform = static_cast<Hwc2::Transform>(transform);
- auto intError = mDevice.mComposer->setLayerTransform(mDisplayId,
- mId, intTransform);
+ auto intError = mComposer.setLayerTransform(mDisplayId, mId, intTransform);
return static_cast<Error>(intError);
}
@@ -918,20 +860,19 @@
rectArray[rect].right, rectArray[rect].bottom});
}
- auto intError = mDevice.mComposer->setLayerVisibleRegion(mDisplayId,
- mId, hwcRects);
+ auto intError = mComposer.setLayerVisibleRegion(mDisplayId, mId, hwcRects);
return static_cast<Error>(intError);
}
Error Layer::setZOrder(uint32_t z)
{
- auto intError = mDevice.mComposer->setLayerZOrder(mDisplayId, mId, z);
+ auto intError = mComposer.setLayerZOrder(mDisplayId, mId, z);
return static_cast<Error>(intError);
}
Error Layer::setInfo(uint32_t type, uint32_t appId)
{
- auto intError = mDevice.mComposer->setLayerInfo(mDisplayId, mId, type, appId);
+ auto intError = mComposer.setLayerInfo(mDisplayId, mId, type, appId);
return static_cast<Error>(intError);
}
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h
index 97582a7..a15c6d9 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.h
+++ b/services/surfaceflinger/DisplayHardware/HWC2.h
@@ -35,6 +35,7 @@
#include <unordered_map>
#include <unordered_set>
#include <vector>
+#include <map>
namespace android {
class Fence;
@@ -52,24 +53,37 @@
class Display;
class Layer;
-typedef std::function<void(std::shared_ptr<Display>, Connection)>
- HotplugCallback;
-typedef std::function<void(std::shared_ptr<Display>)> RefreshCallback;
-typedef std::function<void(std::shared_ptr<Display>, nsecs_t)> VsyncCallback;
+// Implement this interface to receive hardware composer events.
+//
+// These callback functions will generally be called on a hwbinder thread, but
+// when first registering the callback the onHotplugReceived() function will
+// immediately be called on the thread calling registerCallback().
+//
+// All calls receive a sequenceId, which will be the value that was supplied to
+// HWC2::Device::registerCallback(). It's used to help differentiate callbacks
+// from different hardware composer instances.
+class ComposerCallback {
+ public:
+ virtual void onHotplugReceived(int32_t sequenceId, hwc2_display_t display,
+ Connection connection,
+ bool primaryDisplay) = 0;
+ virtual void onRefreshReceived(int32_t sequenceId,
+ hwc2_display_t display) = 0;
+ virtual void onVsyncReceived(int32_t sequenceId, hwc2_display_t display,
+ int64_t timestamp) = 0;
+ virtual ~ComposerCallback() = default;
+};
// C++ Wrapper around hwc2_device_t. Load all functions pointers
// and handle callback registration.
class Device
{
public:
- // useVrComposer is passed to the composer HAL. When true, the composer HAL
- // will use the vr composer service, otherwise it uses the real hardware
- // composer.
- Device(bool useVrComposer);
- ~Device();
+ // Service name is expected to be 'default' or 'vr' for normal use.
+ // 'vr' will slightly modify the behavior of the mComposer.
+ Device(const std::string& serviceName);
- friend class HWC2::Display;
- friend class HWC2::Layer;
+ void registerCallback(ComposerCallback* callback, int32_t sequenceId);
// Required by HWC2
@@ -81,65 +95,43 @@
uint32_t getMaxVirtualDisplayCount() const;
Error createVirtualDisplay(uint32_t width, uint32_t height,
- android_pixel_format_t* format,
- std::shared_ptr<Display>* outDisplay);
+ android_pixel_format_t* format, Display** outDisplay);
+ void destroyDisplay(hwc2_display_t displayId);
- void registerHotplugCallback(HotplugCallback hotplug);
- void registerRefreshCallback(RefreshCallback refresh);
- void registerVsyncCallback(VsyncCallback vsync);
-
- // For use by callbacks
-
- void callHotplug(std::shared_ptr<Display> display, Connection connected);
- void callRefresh(std::shared_ptr<Display> display);
- void callVsync(std::shared_ptr<Display> display, nsecs_t timestamp);
+ void onHotplug(hwc2_display_t displayId, Connection connection);
// Other Device methods
- // This will create a Display if one is not found, but it will not be marked
- // as connected. This Display may be null if the display has been torn down
- // but has not been removed from the map yet.
- std::shared_ptr<Display> getDisplayById(hwc2_display_t id);
-
- bool hasCapability(HWC2::Capability capability) const;
+ Display* getDisplayById(hwc2_display_t id);
android::Hwc2::Composer* getComposer() { return mComposer.get(); }
+ // We buffer most state changes and flush them implicitly with
+ // Display::validate, Display::present, and Display::presentOrValidate.
+ // This method provides an explicit way to flush state changes to HWC.
+ Error flushCommands();
+
private:
// Initialization methods
void loadCapabilities();
- void registerCallbacks();
-
- // For use by Display
-
- void destroyVirtualDisplay(hwc2_display_t display);
// Member variables
std::unique_ptr<android::Hwc2::Composer> mComposer;
-
std::unordered_set<Capability> mCapabilities;
- std::unordered_map<hwc2_display_t, std::weak_ptr<Display>> mDisplays;
-
- HotplugCallback mHotplug;
- std::vector<std::pair<std::shared_ptr<Display>, Connection>>
- mPendingHotplugs;
- RefreshCallback mRefresh;
- std::vector<std::shared_ptr<Display>> mPendingRefreshes;
- VsyncCallback mVsync;
- std::vector<std::pair<std::shared_ptr<Display>, nsecs_t>> mPendingVsyncs;
+ std::unordered_map<hwc2_display_t, std::unique_ptr<Display>> mDisplays;
+ bool mRegisteredCallback;
};
// Convenience C++ class to access hwc2_device_t Display functions directly.
-class Display : public std::enable_shared_from_this<Display>
+class Display
{
public:
- Display(Device& device, hwc2_display_t id);
+ Display(android::Hwc2::Composer& composer,
+ const std::unordered_set<Capability>& capabilities,
+ hwc2_display_t id, DisplayType type);
~Display();
- friend class HWC2::Device;
- friend class HWC2::Layer;
-
class Config
{
public:
@@ -212,12 +204,12 @@
// Required by HWC2
[[clang::warn_unused_result]] Error acceptChanges();
- [[clang::warn_unused_result]] Error createLayer(
- std::shared_ptr<Layer>* outLayer);
+ [[clang::warn_unused_result]] Error createLayer(Layer** outLayer);
+ [[clang::warn_unused_result]] Error destroyLayer(Layer* layer);
[[clang::warn_unused_result]] Error getActiveConfig(
std::shared_ptr<const Config>* outConfig) const;
[[clang::warn_unused_result]] Error getChangedCompositionTypes(
- std::unordered_map<std::shared_ptr<Layer>, Composition>* outTypes);
+ std::unordered_map<Layer*, Composition>* outTypes);
[[clang::warn_unused_result]] Error getColorModes(
std::vector<android_color_mode_t>* outModes) const;
@@ -227,14 +219,13 @@
[[clang::warn_unused_result]] Error getName(std::string* outName) const;
[[clang::warn_unused_result]] Error getRequests(
DisplayRequest* outDisplayRequests,
- std::unordered_map<std::shared_ptr<Layer>, LayerRequest>*
- outLayerRequests);
+ std::unordered_map<Layer*, LayerRequest>* outLayerRequests);
[[clang::warn_unused_result]] Error getType(DisplayType* outType) const;
[[clang::warn_unused_result]] Error supportsDoze(bool* outSupport) const;
[[clang::warn_unused_result]] Error getHdrCapabilities(
std::unique_ptr<android::HdrCapabilities>* outCapabilities) const;
[[clang::warn_unused_result]] Error getReleaseFences(
- std::unordered_map<std::shared_ptr<Layer>,
+ std::unordered_map<Layer*,
android::sp<android::Fence>>* outFences) const;
[[clang::warn_unused_result]] Error present(
android::sp<android::Fence>* outPresentFence);
@@ -254,48 +245,58 @@
[[clang::warn_unused_result]] Error setVsyncEnabled(Vsync enabled);
[[clang::warn_unused_result]] Error validate(uint32_t* outNumTypes,
uint32_t* outNumRequests);
+ [[clang::warn_unused_result]] Error presentOrValidate(uint32_t* outNumTypes,
+ uint32_t* outNumRequests,
+ android::sp<android::Fence>* outPresentFence, uint32_t* state);
// Other Display methods
- Device& getDevice() const { return mDevice; }
hwc2_display_t getId() const { return mId; }
bool isConnected() const { return mIsConnected; }
+ void setConnected(bool connected); // For use by Device only
private:
- // For use by Device
-
- void setConnected(bool connected) { mIsConnected = connected; }
int32_t getAttribute(hwc2_config_t configId, Attribute attribute);
void loadConfig(hwc2_config_t configId);
void loadConfigs();
- // For use by Layer
- void destroyLayer(hwc2_layer_t layerId);
-
// This may fail (and return a null pointer) if no layer with this ID exists
// on this display
- std::shared_ptr<Layer> getLayerById(hwc2_layer_t id) const;
+ Layer* getLayerById(hwc2_layer_t id) const;
// Member variables
- Device& mDevice;
+ // These are references to data owned by HWC2::Device, which will outlive
+ // this HWC2::Display, so these references are guaranteed to be valid for
+ // the lifetime of this object.
+ android::Hwc2::Composer& mComposer;
+ const std::unordered_set<Capability>& mCapabilities;
+
hwc2_display_t mId;
bool mIsConnected;
DisplayType mType;
- std::unordered_map<hwc2_layer_t, std::weak_ptr<Layer>> mLayers;
- std::unordered_map<hwc2_config_t, std::shared_ptr<const Config>> mConfigs;
+ std::unordered_map<hwc2_layer_t, std::unique_ptr<Layer>> mLayers;
+ // The ordering in this map matters, for getConfigs(), when it is
+ // converted to a vector
+ std::map<hwc2_config_t, std::shared_ptr<const Config>> mConfigs;
};
// Convenience C++ class to access hwc2_device_t Layer functions directly.
class Layer
{
public:
- Layer(const std::shared_ptr<Display>& display, hwc2_layer_t id);
+ Layer(android::Hwc2::Composer& composer,
+ const std::unordered_set<Capability>& capabilities,
+ hwc2_display_t displayId, hwc2_layer_t layerId);
~Layer();
- bool isAbandoned() const { return mDisplay.expired(); }
hwc2_layer_t getId() const { return mId; }
+ // Register a listener to be notified when the layer is destroyed. When the
+ // listener function is called, the Layer will be in the process of being
+ // destroyed, so it's not safe to call methods on it.
+ void setLayerDestroyedListener(std::function<void(Layer*)> listener);
+
[[clang::warn_unused_result]] Error setCursorPosition(int32_t x, int32_t y);
[[clang::warn_unused_result]] Error setBuffer(uint32_t slot,
const android::sp<android::GraphicBuffer>& buffer,
@@ -322,10 +323,16 @@
[[clang::warn_unused_result]] Error setInfo(uint32_t type, uint32_t appId);
private:
- std::weak_ptr<Display> mDisplay;
+ // These are references to data owned by HWC2::Device, which will outlive
+ // this HWC2::Layer, so these references are guaranteed to be valid for
+ // the lifetime of this object.
+ android::Hwc2::Composer& mComposer;
+ const std::unordered_set<Capability>& mCapabilities;
+
hwc2_display_t mDisplayId;
- Device& mDevice;
hwc2_layer_t mId;
+ android_dataspace mDataSpace = HAL_DATASPACE_UNKNOWN;
+ std::function<void(Layer*)> mLayerDestroyedListener;
};
} // namespace HWC2
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 42be935..5328a22 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -59,13 +59,12 @@
// ---------------------------------------------------------------------------
-HWComposer::HWComposer(bool useVrComposer)
+HWComposer::HWComposer(const std::string& serviceName)
: mHwcDevice(),
mDisplayData(2),
mFreeDisplaySlots(),
mHwcDisplaySlots(),
mCBContext(),
- mEventHandler(nullptr),
mVSyncCounts(),
mRemainingHwcVirtualDisplays(0)
{
@@ -74,40 +73,15 @@
mVSyncCounts[i] = 0;
}
- loadHwcModule(useVrComposer);
+ mHwcDevice = std::make_unique<HWC2::Device>(serviceName);
+ mRemainingHwcVirtualDisplays = mHwcDevice->getMaxVirtualDisplayCount();
}
HWComposer::~HWComposer() {}
-void HWComposer::setEventHandler(EventHandler* handler)
-{
- if (handler == nullptr) {
- ALOGE("setEventHandler: Rejected attempt to clear handler");
- return;
- }
-
- bool wasNull = (mEventHandler == nullptr);
- mEventHandler = handler;
-
- if (wasNull) {
- auto hotplugHook = std::bind(&HWComposer::hotplug, this,
- std::placeholders::_1, std::placeholders::_2);
- mHwcDevice->registerHotplugCallback(hotplugHook);
- auto invalidateHook = std::bind(&HWComposer::invalidate, this,
- std::placeholders::_1);
- mHwcDevice->registerRefreshCallback(invalidateHook);
- auto vsyncHook = std::bind(&HWComposer::vsync, this,
- std::placeholders::_1, std::placeholders::_2);
- mHwcDevice->registerVsyncCallback(vsyncHook);
- }
-}
-
-// Load and prepare the hardware composer module. Sets mHwc.
-void HWComposer::loadHwcModule(bool useVrComposer)
-{
- ALOGV("loadHwcModule");
- mHwcDevice = std::make_unique<HWC2::Device>(useVrComposer);
- mRemainingHwcVirtualDisplays = mHwcDevice->getMaxVirtualDisplayCount();
+void HWComposer::registerCallback(HWC2::ComposerCallback* callback,
+ int32_t sequenceId) {
+ mHwcDevice->registerCallback(callback, sequenceId);
}
bool HWComposer::hasCapability(HWC2::Capability capability) const
@@ -145,54 +119,51 @@
}
}
-void HWComposer::hotplug(const std::shared_ptr<HWC2::Display>& display,
- HWC2::Connection connected) {
- ALOGV("hotplug: %" PRIu64 ", %s", display->getId(),
- to_string(connected).c_str());
- int32_t disp = 0;
+void HWComposer::onHotplug(hwc2_display_t displayId,
+ HWC2::Connection connection) {
+ ALOGV("hotplug: %" PRIu64 ", %s", displayId,
+ to_string(connection).c_str());
+ mHwcDevice->onHotplug(displayId, connection);
if (!mDisplayData[0].hwcDisplay) {
- ALOGE_IF(connected != HWC2::Connection::Connected, "Assumed primary"
+ ALOGE_IF(connection != HWC2::Connection::Connected, "Assumed primary"
" display would be connected");
- mDisplayData[0].hwcDisplay = display;
- mHwcDisplaySlots[display->getId()] = 0;
- disp = DisplayDevice::DISPLAY_PRIMARY;
+ mDisplayData[0].hwcDisplay = mHwcDevice->getDisplayById(displayId);
+ mHwcDisplaySlots[displayId] = 0;
} else {
// Disconnect is handled through HWComposer::disconnectDisplay via
// SurfaceFlinger's onHotplugReceived callback handling
- if (connected == HWC2::Connection::Connected) {
- mDisplayData[1].hwcDisplay = display;
- mHwcDisplaySlots[display->getId()] = 1;
+ if (connection == HWC2::Connection::Connected) {
+ mDisplayData[1].hwcDisplay = mHwcDevice->getDisplayById(displayId);
+ mHwcDisplaySlots[displayId] = 1;
}
- disp = DisplayDevice::DISPLAY_EXTERNAL;
}
- mEventHandler->onHotplugReceived(this, disp,
- connected == HWC2::Connection::Connected);
}
-void HWComposer::invalidate(const std::shared_ptr<HWC2::Display>& /*display*/) {
- mEventHandler->onInvalidateReceived(this);
-}
-
-void HWComposer::vsync(const std::shared_ptr<HWC2::Display>& display,
- int64_t timestamp) {
+bool HWComposer::onVsync(hwc2_display_t displayId, int64_t timestamp,
+ int32_t* outDisplay) {
+ auto display = mHwcDevice->getDisplayById(displayId);
+ if (!display) {
+ ALOGE("onVsync Failed to find display %" PRIu64, displayId);
+ return false;
+ }
auto displayType = HWC2::DisplayType::Invalid;
auto error = display->getType(&displayType);
if (error != HWC2::Error::None) {
- ALOGE("vsync: Failed to determine type of display %" PRIu64,
+ ALOGE("onVsync: Failed to determine type of display %" PRIu64,
display->getId());
- return;
+ return false;
}
if (displayType == HWC2::DisplayType::Virtual) {
ALOGE("Virtual display %" PRIu64 " passed to vsync callback",
display->getId());
- return;
+ return false;
}
if (mHwcDisplaySlots.count(display->getId()) == 0) {
ALOGE("Unknown physical display %" PRIu64 " passed to vsync callback",
display->getId());
- return;
+ return false;
}
int32_t disp = mHwcDisplaySlots[display->getId()];
@@ -206,17 +177,21 @@
if (timestamp == mLastHwVSync[disp]) {
ALOGW("Ignoring duplicate VSYNC event from HWC (t=%" PRId64 ")",
timestamp);
- return;
+ return false;
}
mLastHwVSync[disp] = timestamp;
}
+ if (outDisplay) {
+ *outDisplay = disp;
+ }
+
char tag[16];
snprintf(tag, sizeof(tag), "HW_VSYNC_%1u", disp);
ATRACE_INT(tag, ++mVSyncCounts[disp] & 1);
- mEventHandler->onVSyncReceived(this, disp, timestamp);
+ return true;
}
status_t HWComposer::allocateVirtualDisplay(uint32_t width, uint32_t height,
@@ -235,7 +210,7 @@
return INVALID_OPERATION;
}
- std::shared_ptr<HWC2::Display> display;
+ HWC2::Display* display;
auto error = mHwcDevice->createVirtualDisplay(width, height, format,
&display);
if (error != HWC2::Error::None) {
@@ -264,13 +239,13 @@
return NO_ERROR;
}
-std::shared_ptr<HWC2::Layer> HWComposer::createLayer(int32_t displayId) {
+HWC2::Layer* HWComposer::createLayer(int32_t displayId) {
if (!isValidDisplay(displayId)) {
ALOGE("Failed to create layer on invalid display %d", displayId);
return nullptr;
}
auto display = mDisplayData[displayId].hwcDisplay;
- std::shared_ptr<HWC2::Layer> layer;
+ HWC2::Layer* layer;
auto error = display->createLayer(&layer);
if (error != HWC2::Error::None) {
ALOGE("Failed to create layer on display %d: %s (%d)", displayId,
@@ -280,6 +255,19 @@
return layer;
}
+void HWComposer::destroyLayer(int32_t displayId, HWC2::Layer* layer) {
+ if (!isValidDisplay(displayId)) {
+ ALOGE("Failed to destroy layer on invalid display %d", displayId);
+ return;
+ }
+ auto display = mDisplayData[displayId].hwcDisplay;
+ auto error = display->destroyLayer(layer);
+ if (error != HWC2::Error::None) {
+ ALOGE("Failed to destroy layer on display %d: %s (%d)", displayId,
+ to_string(error).c_str(), static_cast<int32_t>(error));
+ }
+}
+
nsecs_t HWComposer::getRefreshTimestamp(int32_t displayId) const {
// this returns the last refresh timestamp.
// if the last one is not available, we estimate it based on
@@ -347,10 +335,8 @@
displayId);
return modes;
}
- const std::shared_ptr<HWC2::Display>& hwcDisplay =
- mDisplayData[displayId].hwcDisplay;
- auto error = hwcDisplay->getColorModes(&modes);
+ auto error = mDisplayData[displayId].hwcDisplay->getColorModes(&modes);
if (error != HWC2::Error::None) {
ALOGE("getColorModes failed for display %d: %s (%d)", displayId,
to_string(error).c_str(), static_cast<int32_t>(error));
@@ -455,15 +441,41 @@
uint32_t numTypes = 0;
uint32_t numRequests = 0;
- auto error = hwcDisplay->validate(&numTypes, &numRequests);
+
+ HWC2::Error error = HWC2::Error::None;
+
+ // First try to skip validate altogether if the HWC supports it.
+ displayData.validateWasSkipped = false;
+ if (hasCapability(HWC2::Capability::SkipValidate) &&
+ !displayData.hasClientComposition) {
+ sp<android::Fence> outPresentFence;
+ uint32_t state = UINT32_MAX;
+ error = hwcDisplay->presentOrValidate(&numTypes, &numRequests, &outPresentFence , &state);
+ if (error != HWC2::Error::None && error != HWC2::Error::HasChanges) {
+ ALOGV("skipValidate: Failed to Present or Validate");
+ return UNKNOWN_ERROR;
+ }
+ if (state == 1) { //Present Succeeded.
+ std::unordered_map<HWC2::Layer*, sp<Fence>> releaseFences;
+ error = hwcDisplay->getReleaseFences(&releaseFences);
+ displayData.releaseFences = std::move(releaseFences);
+ displayData.lastPresentFence = outPresentFence;
+ displayData.validateWasSkipped = true;
+ displayData.presentError = error;
+ return NO_ERROR;
+ }
+ // Present failed but Validate ran.
+ } else {
+ error = hwcDisplay->validate(&numTypes, &numRequests);
+ }
+ ALOGV("SkipValidate failed, Falling back to SLOW validate/present");
if (error != HWC2::Error::None && error != HWC2::Error::HasChanges) {
ALOGE("prepare: validate failed for display %d: %s (%d)", displayId,
to_string(error).c_str(), static_cast<int32_t>(error));
return BAD_INDEX;
}
- std::unordered_map<std::shared_ptr<HWC2::Layer>, HWC2::Composition>
- changedTypes;
+ std::unordered_map<HWC2::Layer*, HWC2::Composition> changedTypes;
changedTypes.reserve(numTypes);
error = hwcDisplay->getChangedCompositionTypes(&changedTypes);
if (error != HWC2::Error::None) {
@@ -475,8 +487,7 @@
displayData.displayRequests = static_cast<HWC2::DisplayRequest>(0);
- std::unordered_map<std::shared_ptr<HWC2::Layer>, HWC2::LayerRequest>
- layerRequests;
+ std::unordered_map<HWC2::Layer*, HWC2::LayerRequest> layerRequests;
layerRequests.reserve(numRequests);
error = hwcDisplay->getRequests(&displayData.displayRequests,
&layerRequests);
@@ -570,7 +581,7 @@
}
sp<Fence> HWComposer::getLayerReleaseFence(int32_t displayId,
- const std::shared_ptr<HWC2::Layer>& layer) const {
+ HWC2::Layer* layer) const {
if (!isValidDisplay(displayId)) {
ALOGE("getLayerReleaseFence: Invalid display");
return Fence::NO_FENCE;
@@ -592,6 +603,21 @@
auto& displayData = mDisplayData[displayId];
auto& hwcDisplay = displayData.hwcDisplay;
+
+ if (displayData.validateWasSkipped) {
+ // explicitly flush all pending commands
+ auto error = mHwcDevice->flushCommands();
+ if (displayData.presentError != HWC2::Error::None) {
+ error = displayData.presentError;
+ }
+ if (error != HWC2::Error::None) {
+ ALOGE("skipValidate: failed for display %d: %s (%d)",
+ displayId, to_string(error).c_str(), static_cast<int32_t>(error));
+ return UNKNOWN_ERROR;
+ }
+ return NO_ERROR;
+ }
+
auto error = hwcDisplay->present(&displayData.lastPresentFence);
if (error != HWC2::Error::None) {
ALOGE("presentAndGetReleaseFences: failed for display %d: %s (%d)",
@@ -599,7 +625,7 @@
return UNKNOWN_ERROR;
}
- std::unordered_map<std::shared_ptr<HWC2::Layer>, sp<Fence>> releaseFences;
+ std::unordered_map<HWC2::Layer*, sp<Fence>> releaseFences;
error = hwcDisplay->getReleaseFences(&releaseFences);
if (error != HWC2::Error::None) {
ALOGE("presentAndGetReleaseFences: Failed to get release fences "
@@ -747,6 +773,8 @@
auto hwcId = displayData.hwcDisplay->getId();
mHwcDisplaySlots.erase(hwcId);
displayData.reset();
+
+ mHwcDevice->destroyDisplay(hwcId);
}
status_t HWComposer::setOutputBuffer(int32_t displayId,
@@ -845,7 +873,7 @@
HWComposer::DisplayData::DisplayData()
: hasClientComposition(false),
hasDeviceComposition(false),
- hwcDisplay(),
+ hwcDisplay(nullptr),
lastPresentFence(Fence::NO_FENCE),
outbufHandle(nullptr),
outbufAcquireFence(Fence::NO_FENCE),
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index 3eb968d..3640bb5 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -65,24 +65,14 @@
class HWComposer
{
public:
- class EventHandler {
- friend class HWComposer;
- virtual void onVSyncReceived(
- HWComposer* composer, int32_t disp, nsecs_t timestamp) = 0;
- virtual void onHotplugReceived(HWComposer* composer, int32_t disp, bool connected) = 0;
- virtual void onInvalidateReceived(HWComposer* composer) = 0;
- protected:
- virtual ~EventHandler() {}
- };
-
- // useVrComposer is passed to the composer HAL. When true, the composer HAL
- // will use the vr composer service, otherwise it uses the real hardware
- // composer.
- HWComposer(bool useVrComposer);
+ // Uses the named composer service. Valid choices for normal use
+ // are 'default' and 'vr'.
+ HWComposer(const std::string& serviceName);
~HWComposer();
- void setEventHandler(EventHandler* handler);
+ void registerCallback(HWC2::ComposerCallback* callback,
+ int32_t sequenceId);
bool hasCapability(HWC2::Capability capability) const;
@@ -92,7 +82,9 @@
android_pixel_format_t* format, int32_t* outId);
// Attempts to create a new layer on this display
- std::shared_ptr<HWC2::Layer> createLayer(int32_t displayId);
+ HWC2::Layer* createLayer(int32_t displayId);
+ // Destroy a previously created layer
+ void destroyLayer(int32_t displayId, HWC2::Layer* layer);
// Asks the HAL what it can do
status_t prepare(DisplayDevice& displayDevice);
@@ -127,7 +119,7 @@
// Get last release fence for the given layer
sp<Fence> getLayerReleaseFence(int32_t displayId,
- const std::shared_ptr<HWC2::Layer>& layer) const;
+ HWC2::Layer* layer) const;
// Set the output buffer and acquire fence for a virtual display.
// Returns INVALID_OPERATION if displayId is not a virtual display.
@@ -143,6 +135,12 @@
// Events handling ---------------------------------------------------------
+ // Returns true if successful, false otherwise. The
+ // DisplayDevice::DisplayType of the display is returned as an output param.
+ bool onVsync(hwc2_display_t displayId, int64_t timestamp,
+ int32_t* outDisplay);
+ void onHotplug(hwc2_display_t displayId, HWC2::Connection connection);
+
void setVsyncEnabled(int32_t displayId, HWC2::Vsync enabled);
// Query display parameters. Pass in a display index (e.g.
@@ -170,19 +168,11 @@
private:
static const int32_t VIRTUAL_DISPLAY_ID_BASE = 2;
- void loadHwcModule(bool useVrComposer);
-
bool isValidDisplay(int32_t displayId) const;
static void validateChange(HWC2::Composition from, HWC2::Composition to);
struct cb_context;
- void invalidate(const std::shared_ptr<HWC2::Display>& display);
- void vsync(const std::shared_ptr<HWC2::Display>& display,
- int64_t timestamp);
- void hotplug(const std::shared_ptr<HWC2::Display>& display,
- HWC2::Connection connected);
-
struct DisplayData {
DisplayData();
~DisplayData();
@@ -190,11 +180,10 @@
bool hasClientComposition;
bool hasDeviceComposition;
- std::shared_ptr<HWC2::Display> hwcDisplay;
+ HWC2::Display* hwcDisplay;
HWC2::DisplayRequest displayRequests;
sp<Fence> lastPresentFence; // signals when the last set op retires
- std::unordered_map<std::shared_ptr<HWC2::Layer>, sp<Fence>>
- releaseFences;
+ std::unordered_map<HWC2::Layer*, sp<Fence>> releaseFences;
buffer_handle_t outbufHandle;
sp<Fence> outbufAcquireFence;
mutable std::unordered_map<int32_t,
@@ -202,6 +191,9 @@
// protected by mVsyncLock
HWC2::Vsync vsyncEnabled;
+
+ bool validateWasSkipped;
+ HWC2::Error presentError;
};
std::unique_ptr<HWC2::Device> mHwcDevice;
@@ -212,7 +204,6 @@
mutable Mutex mDisplayLock;
cb_context* mCBContext;
- EventHandler* mEventHandler;
size_t mVSyncCounts[HWC_NUM_PHYSICAL_DISPLAY_TYPES];
uint32_t mRemainingHwcVirtualDisplays;
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
index 6e843d9..1de5e48 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
@@ -16,6 +16,9 @@
// #define LOG_NDEBUG 0
#include "VirtualDisplaySurface.h"
+
+#include <inttypes.h>
+
#include "HWComposer.h"
#include "SurfaceFlinger.h"
@@ -339,11 +342,12 @@
}
status_t VirtualDisplaySurface::dequeueBuffer(Source source,
- PixelFormat format, uint32_t usage, int* sslot, sp<Fence>* fence) {
+ PixelFormat format, uint64_t usage, int* sslot, sp<Fence>* fence) {
LOG_FATAL_IF(mDisplayId < 0, "mDisplayId=%d but should not be < 0.", mDisplayId);
- status_t result = mSource[source]->dequeueBuffer(sslot, fence,
- mSinkBufferWidth, mSinkBufferHeight, format, usage, nullptr);
+ status_t result =
+ mSource[source]->dequeueBuffer(sslot, fence, mSinkBufferWidth, mSinkBufferHeight,
+ format, usage, nullptr, nullptr);
if (result < 0)
return result;
int pslot = mapSource2ProducerSlot(source, *sslot);
@@ -372,7 +376,7 @@
mSource[source]->cancelBuffer(*sslot, *fence);
return result;
}
- VDS_LOGV("dequeueBuffer(%s): buffers[%d]=%p fmt=%d usage=%#x",
+ VDS_LOGV("dequeueBuffer(%s): buffers[%d]=%p fmt=%d usage=%#" PRIx64,
dbgSourceStr(source), pslot, mProducerBuffers[pslot].get(),
mProducerBuffers[pslot]->getPixelFormat(),
mProducerBuffers[pslot]->getUsage());
@@ -381,19 +385,20 @@
return result;
}
-status_t VirtualDisplaySurface::dequeueBuffer(int* pslot, sp<Fence>* fence,
- uint32_t w, uint32_t h, PixelFormat format, uint32_t usage,
- FrameEventHistoryDelta* outTimestamps) {
+status_t VirtualDisplaySurface::dequeueBuffer(int* pslot, sp<Fence>* fence, uint32_t w, uint32_t h,
+ PixelFormat format, uint64_t usage,
+ uint64_t* outBufferAge,
+ FrameEventHistoryDelta* outTimestamps) {
if (mDisplayId < 0) {
- return mSource[SOURCE_SINK]->dequeueBuffer(
- pslot, fence, w, h, format, usage, outTimestamps);
+ return mSource[SOURCE_SINK]->dequeueBuffer(pslot, fence, w, h, format, usage, outBufferAge,
+ outTimestamps);
}
VDS_LOGW_IF(mDbgState != DBG_STATE_PREPARED,
"Unexpected dequeueBuffer() in %s state", dbgStateStr());
mDbgState = DBG_STATE_GLES;
- VDS_LOGV("dequeueBuffer %dx%d fmt=%d usage=%#x", w, h, format, usage);
+ VDS_LOGV("dequeueBuffer %dx%d fmt=%d usage=%#" PRIx64, w, h, format, usage);
status_t result = NO_ERROR;
Source source = fbSourceForCompositionType(mCompositionType);
@@ -423,8 +428,8 @@
(w != 0 && w != mSinkBufferWidth) ||
(h != 0 && h != mSinkBufferHeight)) {
VDS_LOGV("dequeueBuffer: dequeueing new output buffer: "
- "want %dx%d fmt=%d use=%#x, "
- "have %dx%d fmt=%d use=%#x",
+ "want %dx%d fmt=%d use=%#" PRIx64 ", "
+ "have %dx%d fmt=%d use=%#" PRIx64,
w, h, format, usage,
mSinkBufferWidth, mSinkBufferHeight,
buf->getPixelFormat(), buf->getUsage());
@@ -446,6 +451,9 @@
*pslot = mapSource2ProducerSlot(source, sslot);
}
}
+ if (outBufferAge) {
+ *outBufferAge = 0;
+ }
return result;
}
@@ -575,7 +583,7 @@
}
void VirtualDisplaySurface::allocateBuffers(uint32_t /* width */,
- uint32_t /* height */, PixelFormat /* format */, uint32_t /* usage */) {
+ uint32_t /* height */, PixelFormat /* format */, uint64_t /* usage */) {
// TODO: Should we actually allocate buffers for a virtual display?
}
@@ -619,6 +627,10 @@
return INVALID_OPERATION;
}
+status_t VirtualDisplaySurface::getConsumerUsage(uint64_t* outUsage) const {
+ return mSource[SOURCE_SINK]->getConsumerUsage(outUsage);
+}
+
void VirtualDisplaySurface::updateQueueBufferOutput(
QueueBufferOutput&& qbo) {
mQueueBufferOutput = std::move(qbo);
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
index 5c0e084..1671aba 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
@@ -104,9 +104,9 @@
virtual status_t requestBuffer(int pslot, sp<GraphicBuffer>* outBuf);
virtual status_t setMaxDequeuedBufferCount(int maxDequeuedBuffers);
virtual status_t setAsyncMode(bool async);
- virtual status_t dequeueBuffer(int* pslot, sp<Fence>* fence, uint32_t w,
- uint32_t h, PixelFormat format, uint32_t usage,
- FrameEventHistoryDelta *outTimestamps);
+ virtual status_t dequeueBuffer(int* pslot, sp<Fence>* fence, uint32_t w, uint32_t h,
+ PixelFormat format, uint64_t usage, uint64_t* outBufferAge,
+ FrameEventHistoryDelta* outTimestamps);
virtual status_t detachBuffer(int slot);
virtual status_t detachNextBuffer(sp<GraphicBuffer>* outBuffer,
sp<Fence>* outFence);
@@ -120,7 +120,7 @@
virtual status_t disconnect(int api, DisconnectMode mode);
virtual status_t setSidebandStream(const sp<NativeHandle>& stream);
virtual void allocateBuffers(uint32_t width, uint32_t height,
- PixelFormat format, uint32_t usage);
+ PixelFormat format, uint64_t usage);
virtual status_t allowAllocation(bool allow);
virtual status_t setGenerationNumber(uint32_t generationNumber);
virtual String8 getConsumerName() const override;
@@ -130,12 +130,13 @@
virtual status_t getLastQueuedBuffer(sp<GraphicBuffer>* outBuffer,
sp<Fence>* outFence, float outTransformMatrix[16]) override;
virtual status_t getUniqueId(uint64_t* outId) const override;
+ virtual status_t getConsumerUsage(uint64_t* outUsage) const override;
//
// Utility methods
//
static Source fbSourceForCompositionType(CompositionType type);
- status_t dequeueBuffer(Source source, PixelFormat format, uint32_t usage,
+ status_t dequeueBuffer(Source source, PixelFormat format, uint64_t usage,
int* sslot, sp<Fence>* fence);
void updateQueueBufferOutput(QueueBufferOutput&& qbo);
void resetPerFrameState();
@@ -168,7 +169,7 @@
// the composition type changes or the GLES driver starts requesting
// different usage/format, we'll get a new buffer.
uint32_t mOutputFormat;
- uint32_t mOutputUsage;
+ uint64_t mOutputUsage;
// Since we present a single producer interface to the GLES driver, but
// are internally muxing between the sink and scratch producers, we have
diff --git a/services/surfaceflinger/EventControlThread.cpp b/services/surfaceflinger/EventControlThread.cpp
index ee6e886..052a959 100644
--- a/services/surfaceflinger/EventControlThread.cpp
+++ b/services/surfaceflinger/EventControlThread.cpp
@@ -31,34 +31,35 @@
}
bool EventControlThread::threadLoop() {
- Mutex::Autolock lock(mMutex);
-
- bool vsyncEnabled = mVsyncEnabled;
-
-#ifdef USE_HWC2
- mFlinger->setVsyncEnabled(HWC_DISPLAY_PRIMARY, mVsyncEnabled);
-#else
- mFlinger->eventControl(HWC_DISPLAY_PRIMARY, SurfaceFlinger::EVENT_VSYNC,
- mVsyncEnabled);
-#endif
+ enum class VsyncState {Unset, On, Off};
+ auto currentVsyncState = VsyncState::Unset;
while (true) {
- status_t err = mCond.wait(mMutex);
- if (err != NO_ERROR) {
- ALOGE("error waiting for new events: %s (%d)",
- strerror(-err), err);
- return false;
+ auto requestedVsyncState = VsyncState::On;
+ {
+ Mutex::Autolock lock(mMutex);
+ requestedVsyncState =
+ mVsyncEnabled ? VsyncState::On : VsyncState::Off;
+ while (currentVsyncState == requestedVsyncState) {
+ status_t err = mCond.wait(mMutex);
+ if (err != NO_ERROR) {
+ ALOGE("error waiting for new events: %s (%d)",
+ strerror(-err), err);
+ return false;
+ }
+ requestedVsyncState =
+ mVsyncEnabled ? VsyncState::On : VsyncState::Off;
+ }
}
- if (vsyncEnabled != mVsyncEnabled) {
+ bool enable = requestedVsyncState == VsyncState::On;
#ifdef USE_HWC2
- mFlinger->setVsyncEnabled(HWC_DISPLAY_PRIMARY, mVsyncEnabled);
+ mFlinger->setVsyncEnabled(HWC_DISPLAY_PRIMARY, enable);
#else
- mFlinger->eventControl(HWC_DISPLAY_PRIMARY,
- SurfaceFlinger::EVENT_VSYNC, mVsyncEnabled);
+ mFlinger->eventControl(HWC_DISPLAY_PRIMARY,
+ SurfaceFlinger::EVENT_VSYNC, enable);
#endif
- vsyncEnabled = mVsyncEnabled;
- }
+ currentVsyncState = requestedVsyncState;
}
return false;
diff --git a/services/surfaceflinger/EventThread.cpp b/services/surfaceflinger/EventThread.cpp
index a9bb2ba..f647742 100644
--- a/services/surfaceflinger/EventThread.cpp
+++ b/services/surfaceflinger/EventThread.cpp
@@ -248,7 +248,7 @@
// find out connections waiting for events
size_t count = mDisplayEventConnections.size();
- for (size_t i=0 ; i<count ; i++) {
+ for (size_t i=0 ; i<count ; ) {
sp<Connection> connection(mDisplayEventConnections[i].promote());
if (connection != NULL) {
bool added = false;
@@ -279,11 +279,12 @@
// messages.
signalConnections.add(connection);
}
+ ++i;
} else {
// we couldn't promote this reference, the connection has
// died, so clean-up!
mDisplayEventConnections.removeAt(i);
- --i; --count;
+ --count;
}
}
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
old mode 100755
new mode 100644
index d19f964..80987a4
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -19,10 +19,10 @@
#define LOG_TAG "Layer"
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
-#include <stdlib.h>
-#include <stdint.h>
-#include <sys/types.h>
#include <math.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <sys/types.h>
#include <cutils/compiler.h>
#include <cutils/native_handle.h>
@@ -40,39 +40,37 @@
#include <gui/BufferItem.h>
#include <gui/BufferQueue.h>
+#include <gui/LayerDebugInfo.h>
#include <gui/Surface.h>
-#include "clz.h"
#include "Colorizer.h"
#include "DisplayDevice.h"
#include "Layer.h"
#include "LayerRejecter.h"
#include "MonitoredProducer.h"
#include "SurfaceFlinger.h"
+#include "clz.h"
#include "DisplayHardware/HWComposer.h"
#include "RenderEngine/RenderEngine.h"
#include <mutex>
+#include "LayerProtoHelper.h"
-#define DEBUG_RESIZE 0
+#define DEBUG_RESIZE 0
namespace android {
-// ---------------------------------------------------------------------------
-
int32_t Layer::sSequence = 1;
-Layer::Layer(SurfaceFlinger* flinger, const sp<Client>& client,
- const String8& name, uint32_t w, uint32_t h, uint32_t flags)
- : contentDirty(false),
+Layer::Layer(SurfaceFlinger* flinger, const sp<Client>& client, const String8& name, uint32_t w,
+ uint32_t h, uint32_t flags)
+ : contentDirty(false),
sequence(uint32_t(android_atomic_inc(&sSequence))),
mFlinger(flinger),
- mTextureName(-1U),
mPremultipliedAlpha(true),
- mName("unnamed"),
- mFormat(PIXEL_FORMAT_NONE),
+ mName(name),
mTransactionFlags(0),
mPendingStateMutex(),
mPendingStates(),
@@ -80,13 +78,9 @@
mSidebandStreamChanged(false),
mActiveBufferSlot(BufferQueue::INVALID_BUFFER_SLOT),
mCurrentTransform(0),
- mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
mOverrideScalingMode(-1),
mCurrentOpacity(true),
- mBufferLatched(false),
mCurrentFrameNumber(0),
- mPreviousFrameNumber(0),
- mRefreshPending(false),
mFrameLatencyNeeded(false),
mFiltering(false),
mNeedsFiltering(false),
@@ -95,54 +89,36 @@
mIsGlesComposition(false),
#endif
mProtectedByApp(false),
- mHasSurface(false),
mClientRef(client),
mPotentialCursor(false),
mQueueItemLock(),
mQueueItemCondition(),
mQueueItems(),
mLastFrameNumberReceived(0),
- mUpdateTexImageFailed(false),
mAutoRefresh(false),
- mFreezeGeometryUpdates(false)
-{
-#ifdef USE_HWC2
- ALOGV("Creating Layer %s", name.string());
-#endif
+ mFreezeGeometryUpdates(false) {
mCurrentCrop.makeInvalid();
- mFlinger->getRenderEngine().genTextures(1, &mTextureName);
- mTexture.init(Texture::TEXTURE_EXTERNAL, mTextureName);
uint32_t layerFlags = 0;
- if (flags & ISurfaceComposerClient::eHidden)
- layerFlags |= layer_state_t::eLayerHidden;
- if (flags & ISurfaceComposerClient::eOpaque)
- layerFlags |= layer_state_t::eLayerOpaque;
- if (flags & ISurfaceComposerClient::eSecure)
- layerFlags |= layer_state_t::eLayerSecure;
-
- if (flags & ISurfaceComposerClient::eNonPremultiplied)
- mPremultipliedAlpha = false;
+ if (flags & ISurfaceComposerClient::eHidden) layerFlags |= layer_state_t::eLayerHidden;
+ if (flags & ISurfaceComposerClient::eOpaque) layerFlags |= layer_state_t::eLayerOpaque;
+ if (flags & ISurfaceComposerClient::eSecure) layerFlags |= layer_state_t::eLayerSecure;
mName = name;
mTransactionName = String8("TX - ") + mName;
mCurrentState.active.w = w;
mCurrentState.active.h = h;
+ mCurrentState.flags = layerFlags;
mCurrentState.active.transform.set(0, 0);
mCurrentState.crop.makeInvalid();
mCurrentState.finalCrop.makeInvalid();
mCurrentState.requestedFinalCrop = mCurrentState.finalCrop;
mCurrentState.requestedCrop = mCurrentState.crop;
mCurrentState.z = 0;
-#ifdef USE_HWC2
- mCurrentState.alpha = 1.0f;
-#else
- mCurrentState.alpha = 0xFF;
-#endif
+ mCurrentState.color.a = 1.0f;
mCurrentState.layerStack = 0;
- mCurrentState.flags = layerFlags;
mCurrentState.sequence = 0;
mCurrentState.requested = mCurrentState.active;
mCurrentState.dataSpace = HAL_DATASPACE_UNKNOWN;
@@ -157,8 +133,7 @@
const auto& activeConfig = hwc.getActiveConfig(HWC_DISPLAY_PRIMARY);
nsecs_t displayPeriod = activeConfig->getVsyncPeriod();
#else
- nsecs_t displayPeriod =
- flinger->getHwComposer().getRefreshPeriod(HWC_DISPLAY_PRIMARY);
+ nsecs_t displayPeriod = flinger->getHwComposer().getRefreshPeriod(HWC_DISPLAY_PRIMARY);
#endif
mFrameTracker.setDisplayRefreshPeriod(displayPeriod);
@@ -167,38 +142,9 @@
mFrameEventHistory.initializeCompositorTiming(compositorTiming);
}
-void Layer::onFirstRef() {
- // Creates a custom BufferQueue for SurfaceFlingerConsumer to use
- sp<IGraphicBufferProducer> producer;
- sp<IGraphicBufferConsumer> consumer;
- BufferQueue::createBufferQueue(&producer, &consumer, true);
- mProducer = new MonitoredProducer(producer, mFlinger, this);
- mSurfaceFlingerConsumer = new SurfaceFlingerConsumer(consumer, mTextureName, this);
- mSurfaceFlingerConsumer->setConsumerUsageBits(getEffectiveUsage(0));
- mSurfaceFlingerConsumer->setContentsChangedListener(this);
- mSurfaceFlingerConsumer->setName(mName);
-
- if (mFlinger->isLayerTripleBufferingDisabled()) {
- mProducer->setMaxDequeuedBufferCount(2);
- }
-
- const sp<const DisplayDevice> hw(mFlinger->getDefaultDisplayDevice());
- updateTransformHint(hw);
-}
+void Layer::onFirstRef() {}
Layer::~Layer() {
- sp<Client> c(mClientRef.promote());
- if (c != 0) {
- c->detachLayer(this);
- }
-
- for (auto& point : mRemoteSyncPoints) {
- point->setTransactionApplied();
- }
- for (auto& point : mLocalSyncPoints) {
- point->setFrameAvailable();
- }
- mFlinger->deleteTextureAsync(mTextureName);
mFrameTracker.logAndResetStats(mName);
}
@@ -206,103 +152,43 @@
// callbacks
// ---------------------------------------------------------------------------
+/*
+ * onLayerDisplayed is only meaningful for BufferLayer, but, is called through
+ * Layer. So, the implementation is done in BufferLayer. When called on a
+ * ColorLayer object, it's essentially a NOP.
+ */
#ifdef USE_HWC2
-void Layer::onLayerDisplayed(const sp<Fence>& releaseFence) {
- if (mHwcLayers.empty()) {
- return;
- }
- mSurfaceFlingerConsumer->setReleaseFence(releaseFence);
-}
+void Layer::onLayerDisplayed(const sp<Fence>& /*releaseFence*/) {}
#else
void Layer::onLayerDisplayed(const sp<const DisplayDevice>& /* hw */,
- HWComposer::HWCLayerInterface* layer) {
- if (layer) {
- layer->onDisplayed();
- mSurfaceFlingerConsumer->setReleaseFence(layer->getAndResetReleaseFence());
- }
-}
+ HWComposer::HWCLayerInterface* /*layer*/) {}
#endif
-void Layer::onFrameAvailable(const BufferItem& item) {
- // Add this buffer from our internal queue tracker
- { // Autolock scope
- Mutex::Autolock lock(mQueueItemLock);
- mFlinger->mInterceptor.saveBufferUpdate(this, item.mGraphicBuffer->getWidth(),
- item.mGraphicBuffer->getHeight(), item.mFrameNumber);
- // Reset the frame number tracker when we receive the first buffer after
- // a frame number reset
- if (item.mFrameNumber == 1) {
- mLastFrameNumberReceived = 0;
- }
+void Layer::onRemovedFromCurrentState() {
+ // the layer is removed from SF mCurrentState to mLayersPendingRemoval
- // Ensure that callbacks are handled in order
- while (item.mFrameNumber != mLastFrameNumberReceived + 1) {
- status_t result = mQueueItemCondition.waitRelative(mQueueItemLock,
- ms2ns(500));
- if (result != NO_ERROR) {
- ALOGE("[%s] Timed out waiting on callback", mName.string());
- }
- }
+ mPendingRemoval = true;
- mQueueItems.push_back(item);
- android_atomic_inc(&mQueuedFrames);
-
- // Wake up any pending callbacks
- mLastFrameNumberReceived = item.mFrameNumber;
- mQueueItemCondition.broadcast();
- }
-
- mFlinger->signalLayerUpdate();
-}
-
-void Layer::onFrameReplaced(const BufferItem& item) {
- { // Autolock scope
- Mutex::Autolock lock(mQueueItemLock);
-
- // Ensure that callbacks are handled in order
- while (item.mFrameNumber != mLastFrameNumberReceived + 1) {
- status_t result = mQueueItemCondition.waitRelative(mQueueItemLock,
- ms2ns(500));
- if (result != NO_ERROR) {
- ALOGE("[%s] Timed out waiting on callback", mName.string());
- }
- }
-
- if (mQueueItems.empty()) {
- ALOGE("Can't replace a frame on an empty queue");
- return;
- }
- mQueueItems.editItemAt(mQueueItems.size() - 1) = item;
-
- // Wake up any pending callbacks
- mLastFrameNumberReceived = item.mFrameNumber;
- mQueueItemCondition.broadcast();
- }
-}
-
-void Layer::onSidebandStreamChanged() {
- if (android_atomic_release_cas(false, true, &mSidebandStreamChanged) == 0) {
- // mSidebandStreamChanged was false
- mFlinger->signalLayerUpdate();
- }
-}
-
-// called with SurfaceFlinger::mStateLock from the drawing thread after
-// the layer has been remove from the current state list (and just before
-// it's removed from the drawing state list)
-void Layer::onRemoved() {
if (mCurrentState.zOrderRelativeOf != nullptr) {
sp<Layer> strongRelative = mCurrentState.zOrderRelativeOf.promote();
if (strongRelative != nullptr) {
strongRelative->removeZOrderRelative(this);
+ mFlinger->setTransactionFlags(eTraversalNeeded);
}
mCurrentState.zOrderRelativeOf = nullptr;
}
- mSurfaceFlingerConsumer->abandon();
+ for (const auto& child : mCurrentChildren) {
+ child->onRemovedFromCurrentState();
+ }
+}
+
+void Layer::onRemoved() {
+ // the layer is removed from SF mLayersPendingRemoval
+ abandon();
#ifdef USE_HWC2
- clearHwcLayers();
+ destroyAllHwcLayers();
#endif
for (const auto& child : mCurrentChildren) {
@@ -318,51 +204,58 @@
return mName;
}
-status_t Layer::setBuffers( uint32_t w, uint32_t h,
- PixelFormat format, uint32_t flags)
-{
- uint32_t const maxSurfaceDims = min(
- mFlinger->getMaxTextureSize(), mFlinger->getMaxViewportDims());
-
- // never allow a surface larger than what our underlying GL implementation
- // can handle.
- if ((uint32_t(w)>maxSurfaceDims) || (uint32_t(h)>maxSurfaceDims)) {
- ALOGE("dimensions too large %u x %u", uint32_t(w), uint32_t(h));
- return BAD_VALUE;
- }
-
- mFormat = format;
-
- mPotentialCursor = (flags & ISurfaceComposerClient::eCursorWindow) ? true : false;
- mProtectedByApp = (flags & ISurfaceComposerClient::eProtectedByApp) ? true : false;
- mCurrentOpacity = getOpacityForFormat(format);
-
- mSurfaceFlingerConsumer->setDefaultBufferSize(w, h);
- mSurfaceFlingerConsumer->setDefaultBufferFormat(format);
- mSurfaceFlingerConsumer->setConsumerUsageBits(getEffectiveUsage(0));
-
- return NO_ERROR;
+bool Layer::getPremultipledAlpha() const {
+ return mPremultipliedAlpha;
}
sp<IBinder> Layer::getHandle() {
Mutex::Autolock _l(mLock);
-
- LOG_ALWAYS_FATAL_IF(mHasSurface,
- "Layer::getHandle() has already been called");
-
- mHasSurface = true;
-
return new Handle(mFlinger, this);
}
-sp<IGraphicBufferProducer> Layer::getProducer() const {
- return mProducer;
-}
-
// ---------------------------------------------------------------------------
// h/w composer set-up
// ---------------------------------------------------------------------------
+#ifdef USE_HWC2
+bool Layer::createHwcLayer(HWComposer* hwc, int32_t hwcId) {
+ LOG_ALWAYS_FATAL_IF(mHwcLayers.count(hwcId) != 0, "Already have a layer for hwcId %d", hwcId);
+ HWC2::Layer* layer = hwc->createLayer(hwcId);
+ if (!layer) {
+ return false;
+ }
+ HWCInfo& hwcInfo = mHwcLayers[hwcId];
+ hwcInfo.hwc = hwc;
+ hwcInfo.layer = layer;
+ layer->setLayerDestroyedListener(
+ [this, hwcId](HWC2::Layer* /*layer*/) { mHwcLayers.erase(hwcId); });
+ return true;
+}
+
+void Layer::destroyHwcLayer(int32_t hwcId) {
+ if (mHwcLayers.count(hwcId) == 0) {
+ return;
+ }
+ auto& hwcInfo = mHwcLayers[hwcId];
+ LOG_ALWAYS_FATAL_IF(hwcInfo.layer == nullptr, "Attempt to destroy null layer");
+ LOG_ALWAYS_FATAL_IF(hwcInfo.hwc == nullptr, "Missing HWComposer");
+ hwcInfo.hwc->destroyLayer(hwcId, hwcInfo.layer);
+ // The layer destroyed listener should have cleared the entry from
+ // mHwcLayers. Verify that.
+ LOG_ALWAYS_FATAL_IF(mHwcLayers.count(hwcId) != 0, "Stale layer entry in mHwcLayers");
+}
+
+void Layer::destroyAllHwcLayers() {
+ size_t numLayers = mHwcLayers.size();
+ for (size_t i = 0; i < numLayers; ++i) {
+ LOG_ALWAYS_FATAL_IF(mHwcLayers.empty(), "destroyAllHwcLayers failed");
+ destroyHwcLayer(mHwcLayers.begin()->first);
+ }
+ LOG_ALWAYS_FATAL_IF(!mHwcLayers.empty(),
+ "All hardware composer layers should have been destroyed");
+}
+#endif
+
Rect Layer::getContentCrop() const {
// this is the crop rectangle that applies to the buffer
// itself (as opposed to the window)
@@ -401,7 +294,11 @@
Transform t = getTransform();
win = t.transform(win);
- const sp<Layer>& p = getParent();
+ if (!s.finalCrop.isEmpty()) {
+ win.intersect(s.finalCrop, &win);
+ }
+
+ const sp<Layer>& p = mDrawingParent.promote();
// Now we need to calculate the parent bounds, so we can clip ourselves to those.
// When calculating the parent bounds for purposes of clipping,
// we don't need to constrain the parent to its transparent region.
@@ -438,7 +335,7 @@
}
Rect bounds = win;
- const auto& p = getParent();
+ const auto& p = mDrawingParent.promote();
if (p != nullptr) {
// Look in computeScreenBounds recursive call for explanation of
// why we pass false here.
@@ -470,7 +367,7 @@
Rect activeCrop(s.active.w, s.active.h);
if (!s.crop.isEmpty()) {
- activeCrop = s.crop;
+ activeCrop.intersect(s.crop, &activeCrop);
}
Transform t = getTransform();
@@ -479,10 +376,17 @@
activeCrop.clear();
}
if (!s.finalCrop.isEmpty()) {
- if(!activeCrop.intersect(s.finalCrop, &activeCrop)) {
+ if (!activeCrop.intersect(s.finalCrop, &activeCrop)) {
activeCrop.clear();
}
}
+
+ const auto& p = mDrawingParent.promote();
+ if (p != nullptr) {
+ auto parentCrop = p->computeInitialCrop(hw);
+ activeCrop.intersect(parentCrop, &activeCrop);
+ }
+
return activeCrop;
}
@@ -496,11 +400,6 @@
// Screen space to make reduction to parent crop clearer.
Rect activeCrop = computeInitialCrop(hw);
- const auto& p = getParent();
- if (p != nullptr) {
- auto parentCrop = p->computeInitialCrop(hw);
- activeCrop.intersect(parentCrop, &activeCrop);
- }
Transform t = getTransform();
// Back to layer space to work with the content crop.
activeCrop = t.inverse().transform(activeCrop);
@@ -527,16 +426,13 @@
* the code below applies the primary display's inverse transform to the
* buffer
*/
- uint32_t invTransformOrient =
- DisplayDevice::getPrimaryDisplayOrientationTransform();
+ uint32_t invTransformOrient = DisplayDevice::getPrimaryDisplayOrientationTransform();
// calculate the inverse transform
if (invTransformOrient & NATIVE_WINDOW_TRANSFORM_ROT_90) {
- invTransformOrient ^= NATIVE_WINDOW_TRANSFORM_FLIP_V |
- NATIVE_WINDOW_TRANSFORM_FLIP_H;
+ invTransformOrient ^= NATIVE_WINDOW_TRANSFORM_FLIP_V | NATIVE_WINDOW_TRANSFORM_FLIP_H;
}
// and apply to the current transform
- invTransform = (Transform(invTransformOrient) * Transform(invTransform))
- .getOrientation();
+ invTransform = (Transform(invTransformOrient) * Transform(invTransform)).getOrientation();
}
int winWidth = s.active.w;
@@ -550,27 +446,25 @@
bool is_h_flipped = (invTransform & NATIVE_WINDOW_TRANSFORM_FLIP_H) != 0;
bool is_v_flipped = (invTransform & NATIVE_WINDOW_TRANSFORM_FLIP_V) != 0;
if (is_h_flipped == is_v_flipped) {
- invTransform ^= NATIVE_WINDOW_TRANSFORM_FLIP_V |
- NATIVE_WINDOW_TRANSFORM_FLIP_H;
+ invTransform ^= NATIVE_WINDOW_TRANSFORM_FLIP_V | NATIVE_WINDOW_TRANSFORM_FLIP_H;
}
winWidth = s.active.h;
winHeight = s.active.w;
}
- const Rect winCrop = activeCrop.transform(
- invTransform, s.active.w, s.active.h);
+ const Rect winCrop = activeCrop.transform(invTransform, s.active.w, s.active.h);
// below, crop is intersected with winCrop expressed in crop's coordinate space
- float xScale = crop.getWidth() / float(winWidth);
+ float xScale = crop.getWidth() / float(winWidth);
float yScale = crop.getHeight() / float(winHeight);
- float insetL = winCrop.left * xScale;
- float insetT = winCrop.top * yScale;
- float insetR = (winWidth - winCrop.right ) * xScale;
+ float insetL = winCrop.left * xScale;
+ float insetT = winCrop.top * yScale;
+ float insetR = (winWidth - winCrop.right) * xScale;
float insetB = (winHeight - winCrop.bottom) * yScale;
- crop.left += insetL;
- crop.top += insetT;
- crop.right -= insetR;
+ crop.left += insetL;
+ crop.top += insetT;
+ crop.right -= insetR;
crop.bottom -= insetB;
return crop;
@@ -579,9 +473,7 @@
#ifdef USE_HWC2
void Layer::setGeometry(const sp<const DisplayDevice>& displayDevice, uint32_t z)
#else
-void Layer::setGeometry(
- const sp<const DisplayDevice>& hw,
- HWComposer::HWCLayerInterface& layer)
+void Layer::setGeometry(const sp<const DisplayDevice>& hw, HWComposer::HWCLayerInterface& layer)
#endif
{
#ifdef USE_HWC2
@@ -613,18 +505,18 @@
#ifdef USE_HWC2
auto blendMode = HWC2::BlendMode::None;
if (!isOpaque(s) || getAlpha() != 1.0f) {
- blendMode = mPremultipliedAlpha ?
- HWC2::BlendMode::Premultiplied : HWC2::BlendMode::Coverage;
+ blendMode =
+ mPremultipliedAlpha ? HWC2::BlendMode::Premultiplied : HWC2::BlendMode::Coverage;
}
auto error = hwcLayer->setBlendMode(blendMode);
- ALOGE_IF(error != HWC2::Error::None, "[%s] Failed to set blend mode %s:"
- " %s (%d)", mName.string(), to_string(blendMode).c_str(),
- to_string(error).c_str(), static_cast<int32_t>(error));
+ ALOGE_IF(error != HWC2::Error::None,
+ "[%s] Failed to set blend mode %s:"
+ " %s (%d)",
+ mName.string(), to_string(blendMode).c_str(), to_string(error).c_str(),
+ static_cast<int32_t>(error));
#else
- if (!isOpaque(s) || getAlpha() != 0xFF) {
- layer.setBlending(mPremultipliedAlpha ?
- HWC_BLENDING_PREMULT :
- HWC_BLENDING_COVERAGE);
+ if (!isOpaque(s) || getAlpha() != 1.0f) {
+ layer.setBlending(mPremultipliedAlpha ? HWC_BLENDING_PREMULT : HWC_BLENDING_COVERAGE);
}
#endif
@@ -636,9 +528,9 @@
Rect activeCrop(s.crop);
activeCrop = t.transform(activeCrop);
#ifdef USE_HWC2
- if(!activeCrop.intersect(displayDevice->getViewport(), &activeCrop)) {
+ if (!activeCrop.intersect(displayDevice->getViewport(), &activeCrop)) {
#else
- if(!activeCrop.intersect(hw->getViewport(), &activeCrop)) {
+ if (!activeCrop.intersect(hw->getViewport(), &activeCrop)) {
#endif
activeCrop.clear();
}
@@ -649,22 +541,20 @@
// transform.inverse().transform(transform.transform(Rect)) != Rect
// in which case we need to make sure the final rect is clipped to the
// display bounds.
- if(!activeCrop.intersect(Rect(s.active.w, s.active.h), &activeCrop)) {
+ if (!activeCrop.intersect(Rect(s.active.w, s.active.h), &activeCrop)) {
activeCrop.clear();
}
// mark regions outside the crop as transparent
activeTransparentRegion.orSelf(Rect(0, 0, s.active.w, activeCrop.top));
- activeTransparentRegion.orSelf(Rect(0, activeCrop.bottom,
- s.active.w, s.active.h));
- activeTransparentRegion.orSelf(Rect(0, activeCrop.top,
- activeCrop.left, activeCrop.bottom));
- activeTransparentRegion.orSelf(Rect(activeCrop.right, activeCrop.top,
- s.active.w, activeCrop.bottom));
+ activeTransparentRegion.orSelf(Rect(0, activeCrop.bottom, s.active.w, s.active.h));
+ activeTransparentRegion.orSelf(Rect(0, activeCrop.top, activeCrop.left, activeCrop.bottom));
+ activeTransparentRegion.orSelf(
+ Rect(activeCrop.right, activeCrop.top, s.active.w, activeCrop.bottom));
}
Rect frame(t.transform(computeBounds(activeTransparentRegion)));
if (!s.finalCrop.isEmpty()) {
- if(!frame.intersect(s.finalCrop, &frame)) {
+ if (!frame.intersect(s.finalCrop, &frame)) {
frame.clear();
}
}
@@ -676,10 +566,9 @@
Rect transformedFrame = tr.transform(frame);
error = hwcLayer->setDisplayFrame(transformedFrame);
if (error != HWC2::Error::None) {
- ALOGE("[%s] Failed to set display frame [%d, %d, %d, %d]: %s (%d)",
- mName.string(), transformedFrame.left, transformedFrame.top,
- transformedFrame.right, transformedFrame.bottom,
- to_string(error).c_str(), static_cast<int32_t>(error));
+ ALOGE("[%s] Failed to set display frame [%d, %d, %d, %d]: %s (%d)", mName.string(),
+ transformedFrame.left, transformedFrame.top, transformedFrame.right,
+ transformedFrame.bottom, to_string(error).c_str(), static_cast<int32_t>(error));
} else {
hwcInfo.displayFrame = transformedFrame;
}
@@ -688,27 +577,27 @@
error = hwcLayer->setSourceCrop(sourceCrop);
if (error != HWC2::Error::None) {
ALOGE("[%s] Failed to set source crop [%.3f, %.3f, %.3f, %.3f]: "
- "%s (%d)", mName.string(), sourceCrop.left, sourceCrop.top,
- sourceCrop.right, sourceCrop.bottom, to_string(error).c_str(),
- static_cast<int32_t>(error));
+ "%s (%d)",
+ mName.string(), sourceCrop.left, sourceCrop.top, sourceCrop.right, sourceCrop.bottom,
+ to_string(error).c_str(), static_cast<int32_t>(error));
} else {
hwcInfo.sourceCrop = sourceCrop;
}
- float alpha = getAlpha();
+ float alpha = static_cast<float>(getAlpha());
error = hwcLayer->setPlaneAlpha(alpha);
- ALOGE_IF(error != HWC2::Error::None, "[%s] Failed to set plane alpha %.3f: "
- "%s (%d)", mName.string(), alpha, to_string(error).c_str(),
- static_cast<int32_t>(error));
+ ALOGE_IF(error != HWC2::Error::None,
+ "[%s] Failed to set plane alpha %.3f: "
+ "%s (%d)",
+ mName.string(), alpha, to_string(error).c_str(), static_cast<int32_t>(error));
error = hwcLayer->setZOrder(z);
- ALOGE_IF(error != HWC2::Error::None, "[%s] Failed to set Z %u: %s (%d)",
- mName.string(), z, to_string(error).c_str(),
- static_cast<int32_t>(error));
+ ALOGE_IF(error != HWC2::Error::None, "[%s] Failed to set Z %u: %s (%d)", mName.string(), z,
+ to_string(error).c_str(), static_cast<int32_t>(error));
int type = s.type;
int appId = s.appId;
- sp<Layer> parent = mParent.promote();
+ sp<Layer> parent = mDrawingParent.promote();
if (parent.get()) {
auto& parentState = parent->getDrawingState();
type = parentState.type;
@@ -716,8 +605,8 @@
}
error = hwcLayer->setInfo(type, appId);
- ALOGE_IF(error != HWC2::Error::None, "[%s] Failed to set info (%d)",
- mName.string(), static_cast<int32_t>(error));
+ ALOGE_IF(error != HWC2::Error::None, "[%s] Failed to set info (%d)", mName.string(),
+ static_cast<int32_t>(error));
#else
if (!frame.intersect(hw->getViewport(), &frame)) {
frame.clear();
@@ -725,7 +614,7 @@
const Transform& tr(hw->getTransform());
layer.setFrame(tr.transform(frame));
layer.setCrop(computeCrop(hw));
- layer.setPlaneAlpha(getAlpha());
+ layer.setPlaneAlpha(static_cast<uint8_t>(std::round(255.0f * getAlpha())));
#endif
/*
@@ -744,12 +633,10 @@
* the code below applies the primary display's inverse transform to the
* buffer
*/
- uint32_t invTransform =
- DisplayDevice::getPrimaryDisplayOrientationTransform();
+ uint32_t invTransform = DisplayDevice::getPrimaryDisplayOrientationTransform();
// calculate the inverse transform
if (invTransform & NATIVE_WINDOW_TRANSFORM_ROT_90) {
- invTransform ^= NATIVE_WINDOW_TRANSFORM_FLIP_V |
- NATIVE_WINDOW_TRANSFORM_FLIP_H;
+ invTransform ^= NATIVE_WINDOW_TRANSFORM_FLIP_V | NATIVE_WINDOW_TRANSFORM_FLIP_H;
}
/*
@@ -770,9 +657,11 @@
} else {
auto transform = static_cast<HWC2::Transform>(orientation);
auto error = hwcLayer->setTransform(transform);
- ALOGE_IF(error != HWC2::Error::None, "[%s] Failed to set transform %s: "
- "%s (%d)", mName.string(), to_string(transform).c_str(),
- to_string(error).c_str(), static_cast<int32_t>(error));
+ ALOGE_IF(error != HWC2::Error::None,
+ "[%s] Failed to set transform %s: "
+ "%s (%d)",
+ mName.string(), to_string(transform).c_str(), to_string(error).c_str(),
+ static_cast<int32_t>(error));
}
#else
if (orientation & Transform::ROT_INVALID) {
@@ -793,107 +682,9 @@
mHwcLayers[hwcId].forceClientComposition = true;
}
-
-void Layer::setPerFrameData(const sp<const DisplayDevice>& displayDevice) {
- // Apply this display's projection's viewport to the visible region
- // before giving it to the HWC HAL.
- const Transform& tr = displayDevice->getTransform();
- const auto& viewport = displayDevice->getViewport();
- Region visible = tr.transform(visibleRegion.intersect(viewport));
- auto hwcId = displayDevice->getHwcDisplayId();
- auto& hwcInfo = mHwcLayers[hwcId];
- auto& hwcLayer = hwcInfo.layer;
- auto error = hwcLayer->setVisibleRegion(visible);
- if (error != HWC2::Error::None) {
- ALOGE("[%s] Failed to set visible region: %s (%d)", mName.string(),
- to_string(error).c_str(), static_cast<int32_t>(error));
- visible.dump(LOG_TAG);
- }
-
- error = hwcLayer->setSurfaceDamage(surfaceDamageRegion);
- if (error != HWC2::Error::None) {
- ALOGE("[%s] Failed to set surface damage: %s (%d)", mName.string(),
- to_string(error).c_str(), static_cast<int32_t>(error));
- surfaceDamageRegion.dump(LOG_TAG);
- }
-
- // Sideband layers
- if (mSidebandStream.get()) {
- setCompositionType(hwcId, HWC2::Composition::Sideband);
- ALOGV("[%s] Requesting Sideband composition", mName.string());
- error = hwcLayer->setSidebandStream(mSidebandStream->handle());
- if (error != HWC2::Error::None) {
- ALOGE("[%s] Failed to set sideband stream %p: %s (%d)",
- mName.string(), mSidebandStream->handle(),
- to_string(error).c_str(), static_cast<int32_t>(error));
- }
- return;
- }
-
- // Client layers
- if (hwcInfo.forceClientComposition ||
- (mActiveBuffer != nullptr && mActiveBuffer->handle == nullptr)) {
- ALOGV("[%s] Requesting Client composition", mName.string());
- setCompositionType(hwcId, HWC2::Composition::Client);
- return;
- }
-
- // SolidColor layers
- if (mActiveBuffer == nullptr) {
- setCompositionType(hwcId, HWC2::Composition::SolidColor);
-
- // For now, we only support black for DimLayer
- error = hwcLayer->setColor({0, 0, 0, 255});
- if (error != HWC2::Error::None) {
- ALOGE("[%s] Failed to set color: %s (%d)", mName.string(),
- to_string(error).c_str(), static_cast<int32_t>(error));
- }
-
- // Clear out the transform, because it doesn't make sense absent a
- // source buffer
- error = hwcLayer->setTransform(HWC2::Transform::None);
- if (error != HWC2::Error::None) {
- ALOGE("[%s] Failed to clear transform: %s (%d)", mName.string(),
- to_string(error).c_str(), static_cast<int32_t>(error));
- }
-
- return;
- }
-
- // Device or Cursor layers
- if (mPotentialCursor) {
- ALOGV("[%s] Requesting Cursor composition", mName.string());
- setCompositionType(hwcId, HWC2::Composition::Cursor);
- } else {
- ALOGV("[%s] Requesting Device composition", mName.string());
- setCompositionType(hwcId, HWC2::Composition::Device);
- }
-
- ALOGV("setPerFrameData: dataspace = %d", mCurrentState.dataSpace);
- error = hwcLayer->setDataspace(mCurrentState.dataSpace);
- if (error != HWC2::Error::None) {
- ALOGE("[%s] Failed to set dataspace %d: %s (%d)", mName.string(),
- mCurrentState.dataSpace, to_string(error).c_str(),
- static_cast<int32_t>(error));
- }
-
- uint32_t hwcSlot = 0;
- sp<GraphicBuffer> hwcBuffer;
- hwcInfo.bufferCache.getHwcBuffer(mActiveBufferSlot, mActiveBuffer,
- &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(),
- static_cast<int32_t>(error));
- }
-}
-
#else
void Layer::setPerFrameData(const sp<const DisplayDevice>& hw,
- HWComposer::HWCLayerInterface& layer) {
+ HWComposer::HWCLayerInterface& layer) {
// we have to set the visible region on every frame because
// we currently free it during onLayerDisplayed(), which is called
// after HWComposer::commit() -- every frame.
@@ -915,11 +706,11 @@
}
#endif
+
#ifdef USE_HWC2
void Layer::updateCursorPosition(const sp<const DisplayDevice>& displayDevice) {
auto hwcId = displayDevice->getHwcDisplayId();
- if (mHwcLayers.count(hwcId) == 0 ||
- getCompositionType(hwcId) != HWC2::Composition::Cursor) {
+ if (mHwcLayers.count(hwcId) == 0 || getCompositionType(hwcId) != HWC2::Composition::Cursor) {
return;
}
@@ -942,36 +733,15 @@
auto& displayTransform(displayDevice->getTransform());
auto position = displayTransform.transform(frame);
- auto error = mHwcLayers[hwcId].layer->setCursorPosition(position.left,
- position.top);
- ALOGE_IF(error != HWC2::Error::None, "[%s] Failed to set cursor position "
- "to (%d, %d): %s (%d)", mName.string(), position.left,
- position.top, to_string(error).c_str(),
- static_cast<int32_t>(error));
+ auto error = mHwcLayers[hwcId].layer->setCursorPosition(position.left, position.top);
+ ALOGE_IF(error != HWC2::Error::None,
+ "[%s] Failed to set cursor position "
+ "to (%d, %d): %s (%d)",
+ mName.string(), position.left, position.top, to_string(error).c_str(),
+ static_cast<int32_t>(error));
}
#else
-void Layer::setAcquireFence(const sp<const DisplayDevice>& /* hw */,
- HWComposer::HWCLayerInterface& layer) {
- int fenceFd = -1;
-
- // TODO: there is a possible optimization here: we only need to set the
- // acquire fence the first time a new buffer is acquired on EACH display.
-
- if (layer.getCompositionType() == HWC_OVERLAY || layer.getCompositionType() == HWC_CURSOR_OVERLAY) {
- sp<Fence> fence = mSurfaceFlingerConsumer->getCurrentFence();
- if (fence->isValid()) {
- fenceFd = fence->dup();
- if (fenceFd == -1) {
- ALOGW("failed to dup layer fence, skipping sync: %d", errno);
- }
- }
- }
- layer.setAcquireFenceFd(fenceFd);
-}
-
-Rect Layer::getPosition(
- const sp<const DisplayDevice>& hw)
-{
+Rect Layer::getPosition(const sp<const DisplayDevice>& hw) {
// this gives us only the "orientation" component of the transform
const State& s(getCurrentState());
@@ -997,228 +767,50 @@
// drawing...
// ---------------------------------------------------------------------------
-void Layer::draw(const sp<const DisplayDevice>& hw, const Region& clip) const {
- onDraw(hw, clip, false);
+void Layer::draw(const RenderArea& renderArea, const Region& clip) const {
+ onDraw(renderArea, clip, false);
}
-void Layer::draw(const sp<const DisplayDevice>& hw,
- bool useIdentityTransform) const {
- onDraw(hw, Region(hw->bounds()), useIdentityTransform);
+void Layer::draw(const RenderArea& renderArea, bool useIdentityTransform) const {
+ onDraw(renderArea, Region(renderArea.getBounds()), useIdentityTransform);
}
-void Layer::draw(const sp<const DisplayDevice>& hw) const {
- onDraw(hw, Region(hw->bounds()), false);
+void Layer::draw(const RenderArea& renderArea) const {
+ onDraw(renderArea, Region(renderArea.getBounds()), false);
}
-static constexpr mat4 inverseOrientation(uint32_t transform) {
- const mat4 flipH(-1,0,0,0, 0,1,0,0, 0,0,1,0, 1,0,0,1);
- const mat4 flipV( 1,0,0,0, 0,-1,0,0, 0,0,1,0, 0,1,0,1);
- const mat4 rot90( 0,1,0,0, -1,0,0,0, 0,0,1,0, 1,0,0,1);
- mat4 tr;
-
- if (transform & NATIVE_WINDOW_TRANSFORM_ROT_90) {
- tr = tr * rot90;
- }
- if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_H) {
- tr = tr * flipH;
- }
- if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_V) {
- tr = tr * flipV;
- }
- return inverse(tr);
-}
-
-/*
- * onDraw will draw the current layer onto the presentable buffer
- */
-void Layer::onDraw(const sp<const DisplayDevice>& hw, const Region& clip,
- bool useIdentityTransform) const
-{
- ATRACE_CALL();
-
- if (CC_UNLIKELY(mActiveBuffer == 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
- // has drawn the first time.
-
- // If there is nothing under us, we paint the screen in black, otherwise
- // we just skip this update.
-
- // figure out if there is something below us
- Region under;
- bool finished = false;
- mFlinger->mDrawingState.traverseInZOrder([&](Layer* layer) {
- if (finished || layer == static_cast<Layer const*>(this)) {
- finished = true;
- return;
- }
- under.orSelf( hw->getTransform().transform(layer->visibleRegion) );
- });
- // if not everything below us is covered, we plug the holes!
- Region holes(clip.subtract(under));
- if (!holes.isEmpty()) {
- clearWithOpenGL(hw, 0, 0, 0, 1);
- }
- return;
- }
-
- // Bind the current buffer to the GL texture, and wait for it to be
- // ready for us to draw into.
- status_t err = mSurfaceFlingerConsumer->bindTextureImage();
- if (err != NO_ERROR) {
- ALOGW("onDraw: bindTextureImage failed (err=%d)", err);
- // Go ahead and draw the buffer anyway; no matter what we do the screen
- // is probably going to have something visibly wrong.
- }
-
- bool blackOutLayer = isProtected() || (isSecure() && !hw->isSecure());
-
+void Layer::clearWithOpenGL(const RenderArea& renderArea, float red, float green, float blue,
+ float alpha) const {
RenderEngine& engine(mFlinger->getRenderEngine());
-
- if (!blackOutLayer) {
- // TODO: we could be more subtle with isFixedSize()
- const bool useFiltering = getFiltering() || needsFiltering(hw) || isFixedSize();
-
- // Query the texture matrix given our current filtering mode.
- float textureMatrix[16];
- mSurfaceFlingerConsumer->setFilteringEnabled(useFiltering);
- mSurfaceFlingerConsumer->getTransformMatrix(textureMatrix);
-
- if (getTransformToDisplayInverse()) {
-
- /*
- * the code below applies the primary display's inverse transform to
- * the texture transform
- */
- uint32_t transform =
- DisplayDevice::getPrimaryDisplayOrientationTransform();
- mat4 tr = inverseOrientation(transform);
-
- /**
- * TODO(b/36727915): This is basically a hack.
- *
- * Ensure that regardless of the parent transformation,
- * this buffer is always transformed from native display
- * orientation to display orientation. For example, in the case
- * of a camera where the buffer remains in native orientation,
- * we want the pixels to always be upright.
- */
- if (getParent() != nullptr) {
- const auto parentTransform = getParent()->getTransform();
- tr = tr * inverseOrientation(parentTransform.getOrientation());
- }
-
- // and finally apply it to the original texture matrix
- const mat4 texTransform(mat4(static_cast<const float*>(textureMatrix)) * tr);
- memcpy(textureMatrix, texTransform.asArray(), sizeof(textureMatrix));
- }
-
- // Set things up for texturing.
- mTexture.setDimensions(mActiveBuffer->getWidth(), mActiveBuffer->getHeight());
- mTexture.setFiltering(useFiltering);
- mTexture.setMatrix(textureMatrix);
-
- engine.setupLayerTexturing(mTexture);
- } else {
- engine.setupLayerBlackedOut();
- }
- drawWithOpenGL(hw, useIdentityTransform);
- engine.disableTexturing();
-}
-
-
-void Layer::clearWithOpenGL(const sp<const DisplayDevice>& hw,
- float red, float green, float blue,
- float alpha) const
-{
- RenderEngine& engine(mFlinger->getRenderEngine());
- computeGeometry(hw, mMesh, false);
+ computeGeometry(renderArea, mMesh, false);
engine.setupFillWithColor(red, green, blue, alpha);
engine.drawMesh(mMesh);
}
-void Layer::clearWithOpenGL(
- const sp<const DisplayDevice>& hw) const {
- clearWithOpenGL(hw, 0,0,0,0);
-}
-
-void Layer::drawWithOpenGL(const sp<const DisplayDevice>& hw,
- bool useIdentityTransform) const {
- const State& s(getDrawingState());
-
- computeGeometry(hw, mMesh, useIdentityTransform);
-
- /*
- * NOTE: the way we compute the texture coordinates here produces
- * different results than when we take the HWC path -- in the later case
- * the "source crop" is rounded to texel boundaries.
- * This can produce significantly different results when the texture
- * is scaled by a large amount.
- *
- * The GL code below is more logical (imho), and the difference with
- * HWC is due to a limitation of the HWC API to integers -- a question
- * is suspend is whether we should ignore this problem or revert to
- * GL composition when a buffer scaling is applied (maybe with some
- * minimal value)? Or, we could make GL behave like HWC -- but this feel
- * like more of a hack.
- */
- Rect win(computeBounds());
-
- Transform t = getTransform();
- if (!s.finalCrop.isEmpty()) {
- win = t.transform(win);
- if (!win.intersect(s.finalCrop, &win)) {
- win.clear();
- }
- win = t.inverse().transform(win);
- if (!win.intersect(computeBounds(), &win)) {
- win.clear();
- }
- }
-
- float left = float(win.left) / float(s.active.w);
- float top = float(win.top) / float(s.active.h);
- float right = float(win.right) / float(s.active.w);
- float bottom = float(win.bottom) / float(s.active.h);
-
- // TODO: we probably want to generate the texture coords with the mesh
- // here we assume that we only have 4 vertices
- Mesh::VertexArray<vec2> texCoords(mMesh.getTexCoordArray<vec2>());
- texCoords[0] = vec2(left, 1.0f - top);
- texCoords[1] = vec2(left, 1.0f - bottom);
- texCoords[2] = vec2(right, 1.0f - bottom);
- texCoords[3] = vec2(right, 1.0f - top);
-
- RenderEngine& engine(mFlinger->getRenderEngine());
- engine.setupLayerBlending(mPremultipliedAlpha, isOpaque(s), getAlpha());
-#ifdef USE_HWC2
- engine.setSourceDataSpace(mCurrentState.dataSpace);
-#endif
- engine.drawMesh(mMesh);
- engine.disableBlending();
+void Layer::clearWithOpenGL(const RenderArea& renderArea) const {
+ clearWithOpenGL(renderArea, 0, 0, 0, 0);
}
#ifdef USE_HWC2
-void Layer::setCompositionType(int32_t hwcId, HWC2::Composition type,
- bool callIntoHwc) {
+void Layer::setCompositionType(int32_t hwcId, HWC2::Composition type, bool callIntoHwc) {
if (mHwcLayers.count(hwcId) == 0) {
ALOGE("setCompositionType called without a valid HWC layer");
return;
}
auto& hwcInfo = mHwcLayers[hwcId];
auto& hwcLayer = hwcInfo.layer;
- ALOGV("setCompositionType(%" PRIx64 ", %s, %d)", hwcLayer->getId(),
- to_string(type).c_str(), static_cast<int>(callIntoHwc));
+ ALOGV("setCompositionType(%" PRIx64 ", %s, %d)", hwcLayer->getId(), to_string(type).c_str(),
+ static_cast<int>(callIntoHwc));
if (hwcInfo.compositionType != type) {
ALOGV(" actually setting");
hwcInfo.compositionType = type;
if (callIntoHwc) {
auto error = hwcLayer->setCompositionType(type);
- ALOGE_IF(error != HWC2::Error::None, "[%s] Failed to set "
- "composition type %s: %s (%d)", mName.string(),
- to_string(type).c_str(), to_string(error).c_str(),
- static_cast<int32_t>(error));
+ ALOGE_IF(error != HWC2::Error::None,
+ "[%s] Failed to set "
+ "composition type %s: %s (%d)",
+ mName.string(), to_string(type).c_str(), to_string(error).c_str(),
+ static_cast<int32_t>(error));
}
}
}
@@ -1253,63 +845,6 @@
}
#endif
-uint32_t Layer::getProducerStickyTransform() const {
- int producerStickyTransform = 0;
- int ret = mProducer->query(NATIVE_WINDOW_STICKY_TRANSFORM, &producerStickyTransform);
- if (ret != OK) {
- ALOGW("%s: Error %s (%d) while querying window sticky transform.", __FUNCTION__,
- strerror(-ret), ret);
- return 0;
- }
- return static_cast<uint32_t>(producerStickyTransform);
-}
-
-bool Layer::latchUnsignaledBuffers() {
- static bool propertyLoaded = false;
- static bool latch = false;
- static std::mutex mutex;
- std::lock_guard<std::mutex> lock(mutex);
- if (!propertyLoaded) {
- char value[PROPERTY_VALUE_MAX] = {};
- property_get("debug.sf.latch_unsignaled", value, "0");
- latch = atoi(value);
- propertyLoaded = true;
- }
- return latch;
-}
-
-uint64_t Layer::getHeadFrameNumber() const {
- Mutex::Autolock lock(mQueueItemLock);
- if (!mQueueItems.empty()) {
- return mQueueItems[0].mFrameNumber;
- } else {
- return mCurrentFrameNumber;
- }
-}
-
-bool Layer::headFenceHasSignaled() const {
-#ifdef USE_HWC2
- if (latchUnsignaledBuffers()) {
- return true;
- }
-
- Mutex::Autolock lock(mQueueItemLock);
- if (mQueueItems.empty()) {
- return true;
- }
- if (mQueueItems[0].mIsDroppable) {
- // Even though this buffer's fence may not have signaled yet, it could
- // be replaced by another buffer before it has a chance to, which means
- // that it's possible to get into a situation where a buffer is never
- // able to be latched. To avoid this, grab this buffer anyway.
- return true;
- }
- return mQueueItems[0].mFence->getSignalTime() != INT64_MAX;
-#else
- return true;
-#endif
-}
-
bool Layer::addSyncPoint(const std::shared_ptr<SyncPoint>& point) {
if (point->getFrameNumber() <= mCurrentFrameNumber) {
// Don't bother with a SyncPoint, since we've already latched the
@@ -1330,28 +865,6 @@
return mFiltering;
}
-// As documented in libhardware header, formats in the range
-// 0x100 - 0x1FF are specific to the HAL implementation, and
-// are known to have no alpha channel
-// TODO: move definition for device-specific range into
-// hardware.h, instead of using hard-coded values here.
-#define HARDWARE_IS_DEVICE_FORMAT(f) ((f) >= 0x100 && (f) <= 0x1FF)
-
-bool Layer::getOpacityForFormat(uint32_t format) {
- if (HARDWARE_IS_DEVICE_FORMAT(format)) {
- return true;
- }
- switch (format) {
- case HAL_PIXEL_FORMAT_RGBA_8888:
- case HAL_PIXEL_FORMAT_BGRA_8888:
- case HAL_PIXEL_FORMAT_RGBA_FP16:
- case HAL_PIXEL_FORMAT_RGBA_1010102:
- return false;
- }
- // in all other case, we have no blending (also for unknown formats)
- return true;
-}
-
// ----------------------------------------------------------------------------
// local state
// ----------------------------------------------------------------------------
@@ -1371,12 +884,11 @@
}
}
-void Layer::computeGeometry(const sp<const DisplayDevice>& hw, Mesh& mesh,
- bool useIdentityTransform) const
-{
+void Layer::computeGeometry(const RenderArea& renderArea, Mesh& mesh,
+ bool useIdentityTransform) const {
const Layer::State& s(getDrawingState());
- const Transform hwTransform(hw->getTransform());
- const uint32_t hw_h = hw->getHeight();
+ const Transform renderAreaTransform(renderArea.getTransform());
+ const uint32_t height = renderArea.getHeight();
Rect win = computeBounds();
vec2 lt = vec2(win.left, win.top);
@@ -1400,53 +912,20 @@
}
Mesh::VertexArray<vec2> position(mesh.getPositionArray<vec2>());
- position[0] = hwTransform.transform(lt);
- position[1] = hwTransform.transform(lb);
- position[2] = hwTransform.transform(rb);
- position[3] = hwTransform.transform(rt);
- for (size_t i=0 ; i<4 ; i++) {
- position[i].y = hw_h - position[i].y;
+ position[0] = renderAreaTransform.transform(lt);
+ position[1] = renderAreaTransform.transform(lb);
+ position[2] = renderAreaTransform.transform(rb);
+ position[3] = renderAreaTransform.transform(rt);
+ for (size_t i = 0; i < 4; i++) {
+ position[i].y = height - position[i].y;
}
}
-bool Layer::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 ((mSidebandStream == nullptr) && (mActiveBuffer == nullptr)) {
- return false;
- }
-
- // if the layer has the opaque flag, then we're always opaque,
- // otherwise we use the current buffer's format.
- return ((s.flags & layer_state_t::eLayerOpaque) != 0) || mCurrentOpacity;
-}
-
-bool Layer::isSecure() const
-{
+bool Layer::isSecure() const {
const Layer::State& s(mDrawingState);
return (s.flags & layer_state_t::eLayerSecure);
}
-bool Layer::isProtected() const
-{
- const sp<GraphicBuffer>& activeBuffer(mActiveBuffer);
- return (activeBuffer != 0) &&
- (activeBuffer->getUsage() & GRALLOC_USAGE_PROTECTED);
-}
-
-bool Layer::isFixedSize() const {
- return getEffectiveScalingMode() != NATIVE_WINDOW_SCALING_MODE_FREEZE;
-}
-
-bool Layer::isCropped() const {
- return !mCurrentCrop.isEmpty();
-}
-
-bool Layer::needsFiltering(const sp<const DisplayDevice>& hw) const {
- return mNeedsFiltering || hw->needsFiltering();
-}
-
void Layer::setVisibleRegion(const Region& visibleRegion) {
// always called from main thread
this->visibleRegion = visibleRegion;
@@ -1457,8 +936,7 @@
this->coveredRegion = coveredRegion;
}
-void Layer::setVisibleNonTransparentRegion(const Region&
- setVisibleNonTransparentRegion) {
+void Layer::setVisibleNonTransparentRegion(const Region& setVisibleNonTransparentRegion) {
// always called from main thread
this->visibleNonTransparentRegion = setVisibleNonTransparentRegion;
}
@@ -1483,8 +961,7 @@
// to be applied as per normal (no synchronization).
mCurrentState.barrierLayer = nullptr;
} else {
- auto syncPoint = std::make_shared<SyncPoint>(
- mCurrentState.frameNumber);
+ auto syncPoint = std::make_shared<SyncPoint>(mCurrentState.frameNumber);
if (barrierLayer->addSyncPoint(syncPoint)) {
mRemoteSyncPoints.push_back(std::move(syncPoint));
} else {
@@ -1505,8 +982,8 @@
void Layer::popPendingState(State* stateToCommit) {
auto oldFlags = stateToCommit->flags;
*stateToCommit = mPendingStates[0];
- stateToCommit->flags = (oldFlags & ~stateToCommit->mask) |
- (stateToCommit->flags & stateToCommit->mask);
+ stateToCommit->flags =
+ (oldFlags & ~stateToCommit->mask) | (stateToCommit->flags & stateToCommit->mask);
mPendingStates.removeAt(0);
ATRACE_INT(mTransactionName.string(), mPendingStates.size());
@@ -1526,10 +1003,8 @@
continue;
}
- if (mRemoteSyncPoints.front()->getFrameNumber() !=
- mPendingStates[0].frameNumber) {
- ALOGE("[%s] Unexpected sync point frame number found",
- mName.string());
+ if (mRemoteSyncPoints.front()->getFrameNumber() != mPendingStates[0].frameNumber) {
+ ALOGE("[%s] Unexpected sync point frame number found", mName.string());
// Signal our end of the sync point and then dispose of it
mRemoteSyncPoints.front()->setTransactionApplied();
@@ -1565,17 +1040,6 @@
return stateUpdateAvailable;
}
-void Layer::notifyAvailableFrames() {
- auto headFrameNumber = getHeadFrameNumber();
- bool headFenceSignaled = headFenceHasSignaled();
- Mutex::Autolock lock(mLocalSyncPointMutex);
- for (auto& point : mLocalSyncPoints) {
- if (headFrameNumber >= point->getFrameNumber() && headFenceSignaled) {
- point->setFrameAvailable();
- }
- }
-}
-
uint32_t Layer::doTransaction(uint32_t flags) {
ATRACE_CALL();
@@ -1587,59 +1051,49 @@
const Layer::State& s(getDrawingState());
- const bool sizeChanged = (c.requested.w != s.requested.w) ||
- (c.requested.h != s.requested.h);
+ const bool sizeChanged = (c.requested.w != s.requested.w) || (c.requested.h != s.requested.h);
if (sizeChanged) {
// the size changed, we need to ask our client to request a new buffer
ALOGD_IF(DEBUG_RESIZE,
- "doTransaction: geometry (layer=%p '%s'), tr=%02x, scalingMode=%d\n"
- " current={ active ={ wh={%4u,%4u} crop={%4d,%4d,%4d,%4d} (%4d,%4d) }\n"
- " requested={ wh={%4u,%4u} }}\n"
- " drawing={ active ={ wh={%4u,%4u} crop={%4d,%4d,%4d,%4d} (%4d,%4d) }\n"
- " requested={ wh={%4u,%4u} }}\n",
- this, getName().string(), mCurrentTransform,
- getEffectiveScalingMode(),
- c.active.w, c.active.h,
- c.crop.left,
- c.crop.top,
- c.crop.right,
- c.crop.bottom,
- c.crop.getWidth(),
- c.crop.getHeight(),
- c.requested.w, c.requested.h,
- s.active.w, s.active.h,
- s.crop.left,
- s.crop.top,
- s.crop.right,
- s.crop.bottom,
- s.crop.getWidth(),
- s.crop.getHeight(),
- s.requested.w, s.requested.h);
+ "doTransaction: geometry (layer=%p '%s'), tr=%02x, scalingMode=%d\n"
+ " current={ active ={ wh={%4u,%4u} crop={%4d,%4d,%4d,%4d} (%4d,%4d) }\n"
+ " requested={ wh={%4u,%4u} }}\n"
+ " drawing={ active ={ wh={%4u,%4u} crop={%4d,%4d,%4d,%4d} (%4d,%4d) }\n"
+ " requested={ wh={%4u,%4u} }}\n",
+ this, getName().string(), mCurrentTransform, getEffectiveScalingMode(), c.active.w,
+ c.active.h, c.crop.left, c.crop.top, c.crop.right, c.crop.bottom,
+ c.crop.getWidth(), c.crop.getHeight(), c.requested.w, c.requested.h, s.active.w,
+ s.active.h, s.crop.left, s.crop.top, s.crop.right, s.crop.bottom,
+ s.crop.getWidth(), s.crop.getHeight(), s.requested.w, s.requested.h);
// record the new size, form this point on, when the client request
// a buffer, it'll get the new size.
- mSurfaceFlingerConsumer->setDefaultBufferSize(
- c.requested.w, c.requested.h);
+ setDefaultBufferSize(c.requested.w, c.requested.h);
}
- const bool resizePending = (c.requested.w != c.active.w) ||
- (c.requested.h != c.active.h);
+ // Don't let Layer::doTransaction update the drawing state
+ // if we have a pending resize, unless we are in fixed-size mode.
+ // the drawing state will be updated only once we receive a buffer
+ // with the correct size.
+ //
+ // In particular, we want to make sure the clip (which is part
+ // of the geometry state) is latched together with the size but is
+ // latched immediately when no resizing is involved.
+ //
+ // If a sideband stream is attached, however, we want to skip this
+ // optimization so that transactions aren't missed when a buffer
+ // never arrives
+ //
+ // In the case that we don't have a buffer we ignore other factors
+ // and avoid entering the resizePending state. At a high level the
+ // resizePending state is to avoid applying the state of the new buffer
+ // 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);
if (!isFixedSize()) {
if (resizePending && mSidebandStream == NULL) {
- // don't let Layer::doTransaction update the drawing state
- // if we have a pending resize, unless we are in fixed-size mode.
- // the drawing state will be updated only once we receive a buffer
- // with the correct size.
- //
- // in particular, we want to make sure the clip (which is part
- // of the geometry state) is latched together with the size but is
- // latched immediately when no resizing is involved.
- //
- // If a sideband stream is attached, however, we want to skip this
- // optimization so that transactions aren't missed when a buffer
- // never arrives
-
flags |= eDontUpdateGeometryState;
}
}
@@ -1686,8 +1140,7 @@
// we may use linear filtering, if the matrix scales us
const uint8_t type = c.active.transform.getType();
- mNeedsFiltering = (!c.active.transform.preserveRects() ||
- (type >= Transform::SCALE));
+ mNeedsFiltering = (!c.active.transform.preserveRects() || (type >= Transform::SCALE));
}
// If the layer is hidden, signal and clear out all local sync points so
@@ -1750,8 +1203,7 @@
}
bool Layer::setLayer(int32_t z) {
- if (mCurrentState.z == z)
- return false;
+ if (mCurrentState.z == z) return false;
mCurrentState.sequence++;
mCurrentState.z = z;
mCurrentState.modified = true;
@@ -1796,6 +1248,10 @@
mCurrentState.modified = true;
mCurrentState.z = z;
+ auto oldZOrderRelativeOf = mCurrentState.zOrderRelativeOf.promote();
+ if (oldZOrderRelativeOf != nullptr) {
+ oldZOrderRelativeOf->removeZOrderRelative(this);
+ }
mCurrentState.zOrderRelativeOf = relative;
relative->addZOrderRelative(this);
@@ -1805,31 +1261,39 @@
}
bool Layer::setSize(uint32_t w, uint32_t h) {
- if (mCurrentState.requested.w == w && mCurrentState.requested.h == h)
- return false;
+ if (mCurrentState.requested.w == w && mCurrentState.requested.h == h) return false;
mCurrentState.requested.w = w;
mCurrentState.requested.h = h;
mCurrentState.modified = true;
setTransactionFlags(eTransactionNeeded);
return true;
}
-#ifdef USE_HWC2
bool Layer::setAlpha(float alpha) {
-#else
-bool Layer::setAlpha(uint8_t alpha) {
-#endif
- if (mCurrentState.alpha == alpha)
- return false;
+ if (mCurrentState.color.a == alpha) return false;
mCurrentState.sequence++;
- mCurrentState.alpha = alpha;
+ mCurrentState.color.a = alpha;
mCurrentState.modified = true;
setTransactionFlags(eTransactionNeeded);
return true;
}
+
+bool Layer::setColor(const half3& color) {
+ if (color.r == mCurrentState.color.r && color.g == mCurrentState.color.g &&
+ color.b == mCurrentState.color.b)
+ return false;
+
+ mCurrentState.sequence++;
+ mCurrentState.color.r = color.r;
+ mCurrentState.color.g = color.g;
+ mCurrentState.color.b = color.b;
+ mCurrentState.modified = true;
+ setTransactionFlags(eTransactionNeeded);
+ return true;
+}
+
bool Layer::setMatrix(const layer_state_t::matrix22_t& matrix) {
mCurrentState.sequence++;
- mCurrentState.requested.transform.set(
- matrix.dsdx, matrix.dtdy, matrix.dtdx, matrix.dsdy);
+ mCurrentState.requested.transform.set(matrix.dsdx, matrix.dtdy, matrix.dtdx, matrix.dsdy);
mCurrentState.modified = true;
setTransactionFlags(eTransactionNeeded);
return true;
@@ -1842,8 +1306,7 @@
}
bool Layer::setFlags(uint8_t flags, uint8_t mask) {
const uint32_t newFlags = (mCurrentState.flags & ~mask) | (flags & mask);
- if (mCurrentState.flags == newFlags)
- return false;
+ if (mCurrentState.flags == newFlags) return false;
mCurrentState.sequence++;
mCurrentState.flags = newFlags;
mCurrentState.mask = mask;
@@ -1853,8 +1316,7 @@
}
bool Layer::setCrop(const Rect& crop, bool immediate) {
- if (mCurrentState.requestedCrop == crop)
- return false;
+ if (mCurrentState.requestedCrop == crop) return false;
mCurrentState.sequence++;
mCurrentState.requestedCrop = crop;
if (immediate && !mFreezeGeometryUpdates) {
@@ -1868,8 +1330,7 @@
}
bool Layer::setFinalCrop(const Rect& crop, bool immediate) {
- if (mCurrentState.requestedFinalCrop == crop)
- return false;
+ if (mCurrentState.requestedFinalCrop == crop) return false;
mCurrentState.sequence++;
mCurrentState.requestedFinalCrop = crop;
if (immediate && !mFreezeGeometryUpdates) {
@@ -1883,30 +1344,21 @@
}
bool Layer::setOverrideScalingMode(int32_t scalingMode) {
- if (scalingMode == mOverrideScalingMode)
- return false;
+ if (scalingMode == mOverrideScalingMode) return false;
mOverrideScalingMode = scalingMode;
setTransactionFlags(eTransactionNeeded);
return true;
}
void Layer::setInfo(uint32_t type, uint32_t appId) {
- mCurrentState.appId = appId;
- mCurrentState.type = type;
- mCurrentState.modified = true;
- setTransactionFlags(eTransactionNeeded);
-}
-
-uint32_t Layer::getEffectiveScalingMode() const {
- if (mOverrideScalingMode >= 0) {
- return mOverrideScalingMode;
- }
- return mCurrentScalingMode;
+ mCurrentState.appId = appId;
+ mCurrentState.type = type;
+ mCurrentState.modified = true;
+ setTransactionFlags(eTransactionNeeded);
}
bool Layer::setLayerStack(uint32_t layerStack) {
- if (mCurrentState.layerStack == layerStack)
- return false;
+ if (mCurrentState.layerStack == layerStack) return false;
mCurrentState.sequence++;
mCurrentState.layerStack = layerStack;
mCurrentState.modified = true;
@@ -1915,8 +1367,7 @@
}
bool Layer::setDataSpace(android_dataspace dataSpace) {
- if (mCurrentState.dataSpace == dataSpace)
- return false;
+ if (mCurrentState.dataSpace == dataSpace) return false;
mCurrentState.sequence++;
mCurrentState.dataSpace = dataSpace;
mCurrentState.modified = true;
@@ -1929,15 +1380,14 @@
}
uint32_t Layer::getLayerStack() const {
- auto p = getParent();
+ auto p = mDrawingParent.promote();
if (p == nullptr) {
return getDrawingState().layerStack;
}
return p->getLayerStack();
}
-void Layer::deferTransactionUntil(const sp<Layer>& barrierLayer,
- uint64_t frameNumber) {
+void Layer::deferTransactionUntil(const sp<Layer>& barrierLayer, uint64_t frameNumber) {
mCurrentState.barrierLayer = barrierLayer;
mCurrentState.frameNumber = frameNumber;
// We don't set eTransactionNeeded, because just receiving a deferral
@@ -1947,387 +1397,28 @@
mCurrentState.barrierLayer = nullptr;
mCurrentState.frameNumber = 0;
mCurrentState.modified = false;
- ALOGE("Deferred transaction");
}
-void Layer::deferTransactionUntil(const sp<IBinder>& barrierHandle,
- uint64_t frameNumber) {
+void Layer::deferTransactionUntil(const sp<IBinder>& barrierHandle, uint64_t frameNumber) {
sp<Handle> handle = static_cast<Handle*>(barrierHandle.get());
deferTransactionUntil(handle->owner.promote(), frameNumber);
}
-void Layer::useSurfaceDamage() {
- if (mFlinger->mForceFullDamage) {
- surfaceDamageRegion = Region::INVALID_REGION;
- } else {
- surfaceDamageRegion = mSurfaceFlingerConsumer->getSurfaceDamage();
- }
-}
-
-void Layer::useEmptyDamage() {
- surfaceDamageRegion.clear();
-}
// ----------------------------------------------------------------------------
// pageflip handling...
// ----------------------------------------------------------------------------
-bool Layer::shouldPresentNow(const DispSync& dispSync) const {
- if (mSidebandStreamChanged || mAutoRefresh) {
- return true;
- }
-
- Mutex::Autolock lock(mQueueItemLock);
- if (mQueueItems.empty()) {
- return false;
- }
- auto timestamp = mQueueItems[0].mTimestamp;
- nsecs_t expectedPresent =
- mSurfaceFlingerConsumer->computeExpectedPresent(dispSync);
-
- // Ignore timestamps more than a second in the future
- bool isPlausible = timestamp < (expectedPresent + s2ns(1));
- ALOGW_IF(!isPlausible, "[%s] Timestamp %" PRId64 " seems implausible "
- "relative to expectedPresent %" PRId64, mName.string(), timestamp,
- expectedPresent);
-
- bool isDue = timestamp < expectedPresent;
- return isDue || !isPlausible;
-}
-
-bool Layer::onPreComposition(nsecs_t refreshStartTime) {
- if (mBufferLatched) {
- Mutex::Autolock lock(mFrameEventHistoryMutex);
- mFrameEventHistory.addPreComposition(mCurrentFrameNumber, refreshStartTime);
- }
- mRefreshPending = false;
- return mQueuedFrames > 0 || mSidebandStreamChanged || mAutoRefresh;
-}
-
-bool Layer::onPostComposition(const std::shared_ptr<FenceTime>& glDoneFence,
- const std::shared_ptr<FenceTime>& presentFence,
- const CompositorTiming& compositorTiming) {
- mAcquireTimeline.updateSignalTimes();
- mReleaseTimeline.updateSignalTimes();
-
- // mFrameLatencyNeeded is true when a new frame was latched for the
- // composition.
- if (!mFrameLatencyNeeded)
- return false;
-
- // Update mFrameEventHistory.
- {
- Mutex::Autolock lock(mFrameEventHistoryMutex);
- mFrameEventHistory.addPostComposition(mCurrentFrameNumber,
- glDoneFence, presentFence, compositorTiming);
- }
-
- // Update mFrameTracker.
- nsecs_t desiredPresentTime = mSurfaceFlingerConsumer->getTimestamp();
- mFrameTracker.setDesiredPresentTime(desiredPresentTime);
-
- std::shared_ptr<FenceTime> frameReadyFence =
- mSurfaceFlingerConsumer->getCurrentFenceTime();
- if (frameReadyFence->isValid()) {
- mFrameTracker.setFrameReadyFence(std::move(frameReadyFence));
- } else {
- // There was no fence for this frame, so assume that it was ready
- // to be presented at the desired present time.
- mFrameTracker.setFrameReadyTime(desiredPresentTime);
- }
-
- if (presentFence->isValid()) {
- mFrameTracker.setActualPresentFence(
- std::shared_ptr<FenceTime>(presentFence));
- } else {
- // The HWC doesn't support present fences, so use the refresh
- // timestamp instead.
- mFrameTracker.setActualPresentTime(
- mFlinger->getHwComposer().getRefreshTimestamp(
- HWC_DISPLAY_PRIMARY));
- }
-
- mFrameTracker.advanceFrame();
- mFrameLatencyNeeded = false;
- return true;
-}
-
-#ifdef USE_HWC2
-void Layer::releasePendingBuffer(nsecs_t dequeueReadyTime) {
- if (!mSurfaceFlingerConsumer->releasePendingBuffer()) {
- return;
- }
-
- auto releaseFenceTime = std::make_shared<FenceTime>(
- mSurfaceFlingerConsumer->getPrevFinalReleaseFence());
- mReleaseTimeline.push(releaseFenceTime);
-
- Mutex::Autolock lock(mFrameEventHistoryMutex);
- if (mPreviousFrameNumber != 0) {
- mFrameEventHistory.addRelease(mPreviousFrameNumber,
- dequeueReadyTime, std::move(releaseFenceTime));
- }
-}
-#endif
-
bool Layer::isHiddenByPolicy() const {
const Layer::State& s(mDrawingState);
- const auto& parent = getParent();
+ const auto& parent = mDrawingParent.promote();
if (parent != nullptr && parent->isHiddenByPolicy()) {
return true;
}
return s.flags & layer_state_t::eLayerHidden;
}
-bool Layer::isVisible() const {
-#ifdef USE_HWC2
- return !(isHiddenByPolicy()) && getAlpha() > 0.0f
- && (mActiveBuffer != NULL || mSidebandStream != NULL);
-#else
- return !(isHiddenByPolicy()) && getAlpha()
- && (mActiveBuffer != NULL || mSidebandStream != NULL);
-#endif
-}
-
-bool Layer::allTransactionsSignaled() {
- auto headFrameNumber = getHeadFrameNumber();
- bool matchingFramesFound = false;
- bool allTransactionsApplied = true;
- Mutex::Autolock lock(mLocalSyncPointMutex);
-
- for (auto& point : mLocalSyncPoints) {
- if (point->getFrameNumber() > headFrameNumber) {
- break;
- }
- matchingFramesFound = true;
-
- if (!point->frameIsAvailable()) {
- // We haven't notified the remote layer that the frame for
- // this point is available yet. Notify it now, and then
- // abort this attempt to latch.
- point->setFrameAvailable();
- allTransactionsApplied = false;
- break;
- }
-
- allTransactionsApplied = allTransactionsApplied && point->transactionIsApplied();
- }
- return !matchingFramesFound || allTransactionsApplied;
-}
-
-Region Layer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime)
-{
- ATRACE_CALL();
-
- if (android_atomic_acquire_cas(true, false, &mSidebandStreamChanged) == 0) {
- // mSidebandStreamChanged was true
- mSidebandStream = mSurfaceFlingerConsumer->getSidebandStream();
- if (mSidebandStream != NULL) {
- setTransactionFlags(eTransactionNeeded);
- mFlinger->setTransactionFlags(eTraversalNeeded);
- }
- recomputeVisibleRegions = true;
-
- const State& s(getDrawingState());
- return getTransform().transform(Region(Rect(s.active.w, s.active.h)));
- }
-
- Region outDirtyRegion;
- if (mQueuedFrames <= 0 && !mAutoRefresh) {
- return outDirtyRegion;
- }
-
- // if we've already called updateTexImage() without going through
- // a composition step, we have to skip this layer at this point
- // because we cannot call updateTeximage() without a corresponding
- // compositionComplete() call.
- // we'll trigger an update in onPreComposition().
- if (mRefreshPending) {
- return outDirtyRegion;
- }
-
- // If the head buffer's acquire fence hasn't signaled yet, return and
- // try again later
- if (!headFenceHasSignaled()) {
- mFlinger->signalLayerUpdate();
- return outDirtyRegion;
- }
-
- // Capture the old state of the layer for comparisons later
- const State& s(getDrawingState());
- const bool oldOpacity = isOpaque(s);
- sp<GraphicBuffer> oldActiveBuffer = mActiveBuffer;
-
- if (!allTransactionsSignaled()) {
- mFlinger->signalLayerUpdate();
- return outDirtyRegion;
- }
-
- // This boolean is used to make sure that SurfaceFlinger's shadow copy
- // of the buffer queue isn't modified when the buffer queue is returning
- // BufferItem's that weren't actually queued. This can happen in shared
- // buffer mode.
- bool queuedBuffer = false;
- LayerRejecter r(mDrawingState, getCurrentState(), recomputeVisibleRegions,
- getProducerStickyTransform() != 0, mName.string(),
- mOverrideScalingMode, mFreezeGeometryUpdates);
- status_t updateResult = mSurfaceFlingerConsumer->updateTexImage(&r,
- mFlinger->mPrimaryDispSync, &mAutoRefresh, &queuedBuffer,
- mLastFrameNumberReceived);
- if (updateResult == BufferQueue::PRESENT_LATER) {
- // Producer doesn't want buffer to be displayed yet. Signal a
- // layer update so we check again at the next opportunity.
- mFlinger->signalLayerUpdate();
- return outDirtyRegion;
- } else if (updateResult == SurfaceFlingerConsumer::BUFFER_REJECTED) {
- // If the buffer has been rejected, remove it from the shadow queue
- // and return early
- if (queuedBuffer) {
- Mutex::Autolock lock(mQueueItemLock);
- mQueueItems.removeAt(0);
- android_atomic_dec(&mQueuedFrames);
- }
- return outDirtyRegion;
- } else if (updateResult != NO_ERROR || mUpdateTexImageFailed) {
- // This can occur if something goes wrong when trying to create the
- // EGLImage for this buffer. If this happens, the buffer has already
- // been released, so we need to clean up the queue and bug out
- // early.
- if (queuedBuffer) {
- Mutex::Autolock lock(mQueueItemLock);
- mQueueItems.clear();
- android_atomic_and(0, &mQueuedFrames);
- }
-
- // Once we have hit this state, the shadow queue may no longer
- // correctly reflect the incoming BufferQueue's contents, so even if
- // updateTexImage starts working, the only safe course of action is
- // to continue to ignore updates.
- mUpdateTexImageFailed = true;
-
- return outDirtyRegion;
- }
-
- if (queuedBuffer) {
- // Autolock scope
- auto currentFrameNumber = mSurfaceFlingerConsumer->getFrameNumber();
-
- Mutex::Autolock lock(mQueueItemLock);
-
- // Remove any stale buffers that have been dropped during
- // updateTexImage
- while (mQueueItems[0].mFrameNumber != currentFrameNumber) {
- mQueueItems.removeAt(0);
- android_atomic_dec(&mQueuedFrames);
- }
-
- mQueueItems.removeAt(0);
- }
-
-
- // Decrement the queued-frames count. Signal another event if we
- // have more frames pending.
- if ((queuedBuffer && android_atomic_dec(&mQueuedFrames) > 1)
- || mAutoRefresh) {
- mFlinger->signalLayerUpdate();
- }
-
- // update the active buffer
- mActiveBuffer = mSurfaceFlingerConsumer->getCurrentBuffer(
- &mActiveBufferSlot);
- if (mActiveBuffer == NULL) {
- // this can only happen if the very first buffer was rejected.
- return outDirtyRegion;
- }
-
- mBufferLatched = true;
- mPreviousFrameNumber = mCurrentFrameNumber;
- mCurrentFrameNumber = mSurfaceFlingerConsumer->getFrameNumber();
-
- {
- Mutex::Autolock lock(mFrameEventHistoryMutex);
- mFrameEventHistory.addLatch(mCurrentFrameNumber, latchTime);
-#ifndef USE_HWC2
- auto releaseFenceTime = std::make_shared<FenceTime>(
- mSurfaceFlingerConsumer->getPrevFinalReleaseFence());
- mReleaseTimeline.push(releaseFenceTime);
- if (mPreviousFrameNumber != 0) {
- mFrameEventHistory.addRelease(mPreviousFrameNumber,
- latchTime, std::move(releaseFenceTime));
- }
-#endif
- }
-
- mRefreshPending = true;
- mFrameLatencyNeeded = true;
- if (oldActiveBuffer == NULL) {
- // the first time we receive a buffer, we need to trigger a
- // geometry invalidation.
- recomputeVisibleRegions = true;
- }
-
- setDataSpace(mSurfaceFlingerConsumer->getCurrentDataSpace());
-
- Rect crop(mSurfaceFlingerConsumer->getCurrentCrop());
- const uint32_t transform(mSurfaceFlingerConsumer->getCurrentTransform());
- const uint32_t scalingMode(mSurfaceFlingerConsumer->getCurrentScalingMode());
- if ((crop != mCurrentCrop) ||
- (transform != mCurrentTransform) ||
- (scalingMode != mCurrentScalingMode))
- {
- mCurrentCrop = crop;
- mCurrentTransform = transform;
- mCurrentScalingMode = scalingMode;
- 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)) {
- recomputeVisibleRegions = true;
- }
- }
-
- mCurrentOpacity = getOpacityForFormat(mActiveBuffer->format);
- if (oldOpacity != isOpaque(s)) {
- recomputeVisibleRegions = true;
- }
-
- // Remove any sync points corresponding to the buffer which was just
- // latched
- {
- Mutex::Autolock lock(mLocalSyncPointMutex);
- auto point = mLocalSyncPoints.begin();
- while (point != mLocalSyncPoints.end()) {
- if (!(*point)->frameIsAvailable() ||
- !(*point)->transactionIsApplied()) {
- // This sync point must have been added since we started
- // latching. Don't drop it yet.
- ++point;
- continue;
- }
-
- if ((*point)->getFrameNumber() <= mCurrentFrameNumber) {
- point = mLocalSyncPoints.erase(point);
- } else {
- ++point;
- }
- }
- }
-
- // FIXME: postedRegion should be dirty & bounds
- Region dirtyRegion(Rect(s.active.w, s.active.h));
-
- // transform the dirty region to window-manager space
- outDirtyRegion = (getTransform().transform(dirtyRegion));
-
- return outDirtyRegion;
-}
-
-uint32_t Layer::getEffectiveUsage(uint32_t usage) const
-{
+uint32_t Layer::getEffectiveUsage(uint32_t usage) const {
// TODO: should we do something special if mSecure is set?
if (mProtectedByApp) {
// need a hardware-protected path to external video sink
@@ -2352,78 +1443,59 @@
orientation = 0;
}
}
- mSurfaceFlingerConsumer->setTransformHint(orientation);
+ setTransformHint(orientation);
}
// ----------------------------------------------------------------------------
// debugging
// ----------------------------------------------------------------------------
-void Layer::dump(String8& result, Colorizer& colorizer) const
-{
- const Layer::State& s(getDrawingState());
-
- colorizer.colorize(result, Colorizer::GREEN);
- result.appendFormat(
- "+ %s %p (%s)\n",
- getTypeId(), this, getName().string());
- colorizer.reset(result);
-
- s.activeTransparentRegion.dump(result, "transparentRegion");
- visibleRegion.dump(result, "visibleRegion");
- surfaceDamageRegion.dump(result, "surfaceDamageRegion");
- sp<Client> client(mClientRef.promote());
- PixelFormat pf = PIXEL_FORMAT_UNKNOWN;
- const sp<GraphicBuffer>& buffer(getActiveBuffer());
- if (buffer != NULL) {
- pf = buffer->getPixelFormat();
+LayerDebugInfo Layer::getLayerDebugInfo() const {
+ LayerDebugInfo info;
+ const Layer::State& ds = getDrawingState();
+ info.mName = getName();
+ sp<Layer> parent = getParent();
+ info.mParentName = (parent == nullptr ? std::string("none") : parent->getName().string());
+ info.mType = String8(getTypeId());
+ info.mTransparentRegion = ds.activeTransparentRegion;
+ info.mVisibleRegion = visibleRegion;
+ info.mSurfaceDamageRegion = surfaceDamageRegion;
+ info.mLayerStack = getLayerStack();
+ info.mX = ds.active.transform.tx();
+ info.mY = ds.active.transform.ty();
+ info.mZ = ds.z;
+ info.mWidth = ds.active.w;
+ info.mHeight = ds.active.h;
+ info.mCrop = ds.crop;
+ info.mFinalCrop = ds.finalCrop;
+ info.mColor = ds.color;
+ info.mFlags = ds.flags;
+ info.mPixelFormat = getPixelFormat();
+ info.mDataSpace = getDataSpace();
+ info.mMatrix[0][0] = ds.active.transform[0][0];
+ info.mMatrix[0][1] = ds.active.transform[0][1];
+ 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;
+ } else {
+ info.mActiveBufferWidth = 0;
+ info.mActiveBufferHeight = 0;
+ info.mActiveBufferStride = 0;
+ info.mActiveBufferFormat = 0;
+ }
}
-
- result.appendFormat( " "
- "layerStack=%4d, z=%9d, pos=(%g,%g), size=(%4d,%4d), "
- "crop=(%4d,%4d,%4d,%4d), finalCrop=(%4d,%4d,%4d,%4d), "
- "isOpaque=%1d, invalidate=%1d, "
- "dataspace=%s, pixelformat=%s "
-#ifdef USE_HWC2
- "alpha=%.3f, flags=0x%08x, tr=[%.2f, %.2f][%.2f, %.2f]\n"
-#else
- "alpha=0x%02x, flags=0x%08x, tr=[%.2f, %.2f][%.2f, %.2f]\n"
-#endif
- " client=%p\n",
- getLayerStack(), s.z,
- s.active.transform.tx(), s.active.transform.ty(),
- s.active.w, s.active.h,
- s.crop.left, s.crop.top,
- s.crop.right, s.crop.bottom,
- s.finalCrop.left, s.finalCrop.top,
- s.finalCrop.right, s.finalCrop.bottom,
- isOpaque(s), contentDirty,
- dataspaceDetails(getDataSpace()).c_str(), decodePixelFormat(pf).c_str(),
- s.alpha, s.flags,
- s.active.transform[0][0], s.active.transform[0][1],
- s.active.transform[1][0], s.active.transform[1][1],
- client.get());
-
- sp<const GraphicBuffer> buf0(mActiveBuffer);
- uint32_t w0=0, h0=0, s0=0, f0=0;
- if (buf0 != 0) {
- w0 = buf0->getWidth();
- h0 = buf0->getHeight();
- s0 = buf0->getStride();
- f0 = buf0->format;
- }
- result.appendFormat(
- " "
- "format=%2d, activeBuffer=[%4ux%4u:%4u,%3X],"
- " queued-frames=%d, mRefreshPending=%d\n",
- mFormat, w0, h0, s0,f0,
- mQueuedFrames, mRefreshPending);
-
- if (mSurfaceFlingerConsumer != 0) {
- mSurfaceFlingerConsumer->dumpState(result, " ");
- }
+ info.mNumQueuedFrames = getQueuedFrameCount();
+ info.mRefreshPending = isBufferLatched();
+ info.mIsOpaque = isOpaque(ds);
+ info.mContentDirty = contentDirty;
+ return info;
}
-
#ifdef USE_HWC2
void Layer::miniDumpHeader(String8& result) {
result.append("----------------------------------------");
@@ -2457,15 +1529,12 @@
const Layer::State& layerState(getDrawingState());
const HWCInfo& hwcInfo = mHwcLayers.at(hwcId);
- result.appendFormat(" %10u | ", layerState.z);
- result.appendFormat("%10s | ",
- to_string(getCompositionType(hwcId)).c_str());
+ result.appendFormat(" %10d | ", layerState.z);
+ result.appendFormat("%10s | ", to_string(getCompositionType(hwcId)).c_str());
const Rect& frame = hwcInfo.displayFrame;
- result.appendFormat("%4d %4d %4d %4d | ", frame.left, frame.top,
- frame.right, frame.bottom);
+ result.appendFormat("%4d %4d %4d %4d | ", frame.left, frame.top, frame.right, frame.bottom);
const FloatRect& crop = hwcInfo.sourceCrop;
- result.appendFormat("%6.1f %6.1f %6.1f %6.1f\n", crop.left, crop.top,
- crop.right, crop.bottom);
+ result.appendFormat("%6.1f %6.1f %6.1f %6.1f\n", crop.left, crop.top, crop.right, crop.bottom);
result.append("- - - - - - - - - - - - - - - - - - - - ");
result.append("- - - - - - - - - - - - - - - - - - - -\n");
@@ -2489,8 +1558,7 @@
}
void Layer::dumpFrameEvents(String8& result) {
- result.appendFormat("- Layer %s (%s, %p)\n",
- getName().string(), getTypeId(), this);
+ result.appendFormat("- Layer %s (%s, %p)\n", getName().string(), getTypeId(), this);
Mutex::Autolock lock(mFrameEventHistoryMutex);
mFrameEventHistory.checkFencesForCompletion();
mFrameEventHistory.dump(result);
@@ -2502,9 +1570,15 @@
}
void Layer::addAndGetFrameTimestamps(const NewFrameEventsEntry* newTimestamps,
- FrameEventHistoryDelta *outDelta) {
+ FrameEventHistoryDelta* outDelta) {
Mutex::Autolock lock(mFrameEventHistoryMutex);
if (newTimestamps) {
+ // If there are any unsignaled fences in the aquire timeline at this
+ // point, the previously queued frame hasn't been latched yet. Go ahead
+ // and try to get the signal time here so the syscall is taken out of
+ // the main thread's critical path.
+ mAcquireTimeline.updateSignalTimes();
+ // Push the new fence after updating since it's likely still pending.
mAcquireTimeline.push(newTimestamps->acquireFence);
mFrameEventHistory.addQueue(*newTimestamps);
}
@@ -2514,21 +1588,12 @@
}
}
-std::vector<OccupancyTracker::Segment> Layer::getOccupancyHistory(
- bool forceFlush) {
- std::vector<OccupancyTracker::Segment> history;
- status_t result = mSurfaceFlingerConsumer->getOccupancyHistory(forceFlush,
- &history);
- if (result != NO_ERROR) {
- ALOGW("[%s] Failed to obtain occupancy history (%d)", mName.string(),
- result);
- return {};
+size_t Layer::getChildrenCount() const {
+ size_t count = 0;
+ for (const sp<Layer>& child : mCurrentChildren) {
+ count += 1 + child->getChildrenCount();
}
- return history;
-}
-
-bool Layer::getTransformToDisplayInverse() const {
- return mSurfaceFlingerConsumer->getTransformToDisplayInverse();
+ return count;
}
void Layer::addChild(const sp<Layer>& layer) {
@@ -2567,14 +1632,43 @@
return true;
}
+bool Layer::reparent(const sp<IBinder>& newParentHandle) {
+ if (newParentHandle == nullptr) {
+ return false;
+ }
+
+ auto handle = static_cast<Handle*>(newParentHandle.get());
+ sp<Layer> newParent = handle->owner.promote();
+ if (newParent == nullptr) {
+ ALOGE("Unable to promote Layer handle");
+ return false;
+ }
+
+ sp<Layer> parent = getParent();
+ if (parent != nullptr) {
+ parent->removeChild(this);
+ }
+ newParent->addChild(this);
+
+ sp<Client> client(mClientRef.promote());
+ sp<Client> newParentClient(newParent->mClientRef.promote());
+
+ if (client != newParentClient) {
+ client->setParentLayer(newParent);
+ }
+
+ return true;
+}
+
bool Layer::detachChildren() {
traverseInZOrder(LayerVector::StateSet::Drawing, [this](Layer* child) {
if (child == this) {
return;
}
+ sp<Client> parentClient = mClientRef.promote();
sp<Client> client(child->mClientRef.promote());
- if (client != nullptr) {
+ if (client != nullptr && parentClient != client) {
client->detachLayer(child);
}
});
@@ -2583,7 +1677,7 @@
}
void Layer::setParent(const sp<Layer>& layer) {
- mParent = layer;
+ mCurrentParent = layer;
}
void Layer::clearSyncPoints() {
@@ -2602,7 +1696,8 @@
return mDrawingState.z;
}
-LayerVector Layer::makeTraversalList(LayerVector::StateSet stateSet) {
+__attribute__((no_sanitize("unsigned-integer-overflow"))) LayerVector Layer::makeTraversalList(
+ LayerVector::StateSet stateSet) {
LOG_ALWAYS_FATAL_IF(stateSet == LayerVector::StateSet::Invalid,
"makeTraversalList received invalid stateSet");
const bool useDrawing = stateSet == LayerVector::StateSet::Drawing;
@@ -2657,7 +1752,7 @@
LayerVector list = makeTraversalList(stateSet);
int32_t i = 0;
- for (i = list.size()-1; i>=0; i--) {
+ for (i = int32_t(list.size()) - 1; i >= 0; i--) {
const auto& relative = list[i];
if (relative->getZ() < 0) {
break;
@@ -2665,15 +1760,38 @@
relative->traverseInReverseZOrder(stateSet, visitor);
}
visitor(this);
- for (; i>=0; i--) {
+ for (; i >= 0; i--) {
const auto& relative = list[i];
relative->traverseInReverseZOrder(stateSet, visitor);
}
}
+/**
+ * Traverse only children in z order, ignoring relative layers.
+ */
+void Layer::traverseChildrenInZOrder(LayerVector::StateSet stateSet,
+ const LayerVector::Visitor& visitor) {
+ const bool useDrawing = stateSet == LayerVector::StateSet::Drawing;
+ const LayerVector& children = useDrawing ? mDrawingChildren : mCurrentChildren;
+
+ size_t i = 0;
+ for (; i < children.size(); i++) {
+ const auto& relative = children[i];
+ if (relative->getZ() >= 0) {
+ break;
+ }
+ relative->traverseChildrenInZOrder(stateSet, visitor);
+ }
+ visitor(this);
+ for (; i < children.size(); i++) {
+ const auto& relative = children[i];
+ relative->traverseChildrenInZOrder(stateSet, visitor);
+ }
+}
+
Transform Layer::getTransform() const {
Transform t;
- const auto& p = getParent();
+ const auto& p = mDrawingParent.promote();
if (p != nullptr) {
t = p->getTransform();
@@ -2682,7 +1800,7 @@
// 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()) {
+ if (p->isFixedSize() && p->mActiveBuffer != nullptr) {
int bufferWidth;
int bufferHeight;
if ((p->mCurrentTransform & NATIVE_WINDOW_TRANSFORM_ROT_90) == 0) {
@@ -2692,10 +1810,8 @@
bufferHeight = p->mActiveBuffer->getWidth();
bufferWidth = p->mActiveBuffer->getHeight();
}
- float sx = p->getDrawingState().active.w /
- static_cast<float>(bufferWidth);
- float sy = p->getDrawingState().active.h /
- static_cast<float>(bufferHeight);
+ float sx = p->getDrawingState().active.w / static_cast<float>(bufferWidth);
+ float sy = p->getDrawingState().active.h / static_cast<float>(bufferHeight);
Transform extraParentScaling;
extraParentScaling.set(sx, 0, 0, sy);
t = t * extraParentScaling;
@@ -2704,23 +1820,17 @@
return t * getDrawingState().active.transform;
}
-#ifdef USE_HWC2
-float Layer::getAlpha() const {
- const auto& p = getParent();
+half Layer::getAlpha() const {
+ const auto& p = mDrawingParent.promote();
- float parentAlpha = (p != nullptr) ? p->getAlpha() : 1.0;
- return parentAlpha * getDrawingState().alpha;
+ half parentAlpha = (p != nullptr) ? p->getAlpha() : 1.0_hf;
+ return parentAlpha * getDrawingState().color.a;
}
-#else
-uint8_t Layer::getAlpha() const {
- const auto& p = getParent();
- float parentAlpha = (p != nullptr) ? (p->getAlpha() / 255.0f) : 1.0;
- float drawingAlpha = getDrawingState().alpha / 255.0f;
- drawingAlpha = drawingAlpha * parentAlpha;
- return static_cast<uint8_t>(std::round(drawingAlpha * 255));
+half4 Layer::getColor() const {
+ const half4 color(getDrawingState().color);
+ return half4(color.r, color.g, color.b, getAlpha());
}
-#endif
void Layer::commitChildList() {
for (size_t i = 0; i < mCurrentChildren.size(); i++) {
@@ -2728,6 +1838,83 @@
child->commitChildList();
}
mDrawingChildren = mCurrentChildren;
+ mDrawingParent = mCurrentParent;
+}
+
+void Layer::writeToProto(LayerProto* layerInfo, LayerVector::StateSet stateSet) {
+ const bool useDrawing = stateSet == LayerVector::StateSet::Drawing;
+ const LayerVector& children = useDrawing ? mDrawingChildren : mCurrentChildren;
+ const State& state = useDrawing ? mDrawingState : mCurrentState;
+
+ Transform requestedTransform = state.active.transform;
+ Transform transform = getTransform();
+
+ layerInfo->set_id(sequence);
+ layerInfo->set_name(getName().c_str());
+ layerInfo->set_type(String8(getTypeId()));
+
+ for (const auto& child : children) {
+ layerInfo->add_children(child->sequence);
+ }
+
+ for (const wp<Layer>& weakRelative : state.zOrderRelatives) {
+ sp<Layer> strongRelative = weakRelative.promote();
+ if (strongRelative != nullptr) {
+ layerInfo->add_relatives(strongRelative->sequence);
+ }
+ }
+
+ LayerProtoHelper::writeToProto(state.activeTransparentRegion,
+ layerInfo->mutable_transparent_region());
+ LayerProtoHelper::writeToProto(visibleRegion, layerInfo->mutable_visible_region());
+ LayerProtoHelper::writeToProto(surfaceDamageRegion, layerInfo->mutable_damage_region());
+
+ layerInfo->set_layer_stack(getLayerStack());
+ layerInfo->set_z(state.z);
+
+ PositionProto* position = layerInfo->mutable_position();
+ position->set_x(transform.tx());
+ position->set_y(transform.ty());
+
+ PositionProto* requestedPosition = layerInfo->mutable_requested_position();
+ requestedPosition->set_x(requestedTransform.tx());
+ requestedPosition->set_y(requestedTransform.ty());
+
+ SizeProto* size = layerInfo->mutable_size();
+ size->set_w(state.active.w);
+ size->set_h(state.active.h);
+
+ LayerProtoHelper::writeToProto(state.crop, layerInfo->mutable_crop());
+ LayerProtoHelper::writeToProto(state.finalCrop, layerInfo->mutable_final_crop());
+
+ layerInfo->set_is_opaque(isOpaque(state));
+ layerInfo->set_invalidate(contentDirty);
+ layerInfo->set_dataspace(dataspaceDetails(getDataSpace()));
+ layerInfo->set_pixel_format(decodePixelFormat(getPixelFormat()));
+ LayerProtoHelper::writeToProto(getColor(), layerInfo->mutable_color());
+ LayerProtoHelper::writeToProto(state.color, layerInfo->mutable_requested_color());
+ layerInfo->set_flags(state.flags);
+
+ LayerProtoHelper::writeToProto(transform, layerInfo->mutable_transform());
+ LayerProtoHelper::writeToProto(requestedTransform, layerInfo->mutable_requested_transform());
+
+ auto parent = getParent();
+ if (parent != nullptr) {
+ layerInfo->set_parent(parent->sequence);
+ }
+
+ auto zOrderRelativeOf = state.zOrderRelativeOf.promote();
+ if (zOrderRelativeOf != nullptr) {
+ layerInfo->set_z_order_relative_of(zOrderRelativeOf->sequence);
+ }
+
+ auto activeBuffer = getActiveBuffer();
+ if (activeBuffer != nullptr) {
+ LayerProtoHelper::writeToProto(activeBuffer, layerInfo->mutable_active_buffer());
+ }
+
+ layerInfo->set_queued_frames(getQueuedFrameCount());
+ layerInfo->set_refresh_pending(isBufferLatched());
}
// ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index c9ebf99..0580b9f 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -33,24 +33,28 @@
#include <ui/Region.h>
#include <gui/ISurfaceComposerClient.h>
-
-#include <private/gui/LayerState.h>
+#include <gui/LayerState.h>
#include <list>
-#include "FrameTracker.h"
#include "Client.h"
+#include "FrameTracker.h"
#include "LayerVector.h"
#include "MonitoredProducer.h"
#include "SurfaceFlinger.h"
-#include "SurfaceFlingerConsumer.h"
#include "Transform.h"
+#include <layerproto/LayerProtoHeader.h>
#include "DisplayHardware/HWComposer.h"
#include "DisplayHardware/HWComposerBufferCache.h"
+#include "RenderArea.h"
#include "RenderEngine/Mesh.h"
#include "RenderEngine/Texture.h"
+#include <math/vec4.h>
+
+using namespace android::surfaceflinger;
+
namespace android {
// ---------------------------------------------------------------------------
@@ -60,17 +64,11 @@
class DisplayDevice;
class GraphicBuffer;
class SurfaceFlinger;
+class LayerDebugInfo;
// ---------------------------------------------------------------------------
-/*
- * A new BufferQueue and a new SurfaceFlingerConsumer are created when the
- * Layer is first referenced.
- *
- * This also implements onFrameAvailable(), which notifies SurfaceFlinger
- * that new data has arrived.
- */
-class Layer : public SurfaceFlingerConsumer::ContentsChangedListener {
+class Layer : public virtual RefBase {
static int32_t sSequence;
public:
@@ -96,14 +94,11 @@
uint32_t h;
Transform transform;
- inline bool operator ==(const Geometry& rhs) const {
- return (w == rhs.w && h == rhs.h) &&
- (transform.tx() == rhs.transform.tx()) &&
+ inline bool operator==(const Geometry& rhs) const {
+ return (w == rhs.w && h == rhs.h) && (transform.tx() == rhs.transform.tx()) &&
(transform.ty() == rhs.transform.ty());
}
- inline bool operator !=(const Geometry& rhs) const {
- return !operator ==(rhs);
- }
+ inline bool operator!=(const Geometry& rhs) const { return !operator==(rhs); }
};
struct State {
@@ -118,11 +113,6 @@
// to achieve mirroring.
uint32_t layerStack;
-#ifdef USE_HWC2
- float alpha;
-#else
- uint8_t alpha;
-#endif
uint8_t flags;
uint8_t mask;
uint8_t reserved[2];
@@ -157,17 +147,15 @@
// A list of surfaces whose Z-order is interpreted relative to ours.
SortedVector<wp<Layer>> zOrderRelatives;
+
+ half4 color;
};
- // -----------------------------------------------------------------------
-
- Layer(SurfaceFlinger* flinger, const sp<Client>& client,
- const String8& name, uint32_t w, uint32_t h, uint32_t flags);
-
+ Layer(SurfaceFlinger* flinger, const sp<Client>& client, const String8& name, uint32_t w,
+ uint32_t h, uint32_t flags);
virtual ~Layer();
- // the this layer's size and format
- status_t setBuffers(uint32_t w, uint32_t h, PixelFormat format, uint32_t flags);
+ void setPrimaryDisplayOnly() { mPrimaryDisplayOnly = true; }
// ------------------------------------------------------------------------
// Geometry setting functions.
@@ -222,11 +210,8 @@
bool setLayer(int32_t z);
bool setRelativeLayer(const sp<IBinder>& relativeToHandle, int32_t relativeZ);
-#ifdef USE_HWC2
bool setAlpha(float alpha);
-#else
- bool setAlpha(uint8_t alpha);
-#endif
+ bool setColor(const half3& color);
bool setTransparentRegionHint(const Region& transparent);
bool setFlags(uint8_t flags, uint8_t mask);
bool setLayerStack(uint32_t layerStack);
@@ -238,19 +223,23 @@
bool setOverrideScalingMode(int32_t overrideScalingMode);
void setInfo(uint32_t type, uint32_t appId);
bool reparentChildren(const sp<IBinder>& layer);
+ bool reparent(const sp<IBinder>& newParentHandle);
bool detachChildren();
// If we have received a new buffer this frame, we will pass its surface
// damage down to hardware composer. Otherwise, we must send a region with
// one empty rect.
- void useSurfaceDamage();
- void useEmptyDamage();
+ virtual void useSurfaceDamage() = 0;
+ virtual void useEmptyDamage() = 0;
uint32_t getTransactionFlags(uint32_t flags);
uint32_t setTransactionFlags(uint32_t flags);
- void computeGeometry(const sp<const DisplayDevice>& hw, Mesh& mesh,
- bool useIdentityTransform) const;
+ bool belongsToDisplay(uint32_t layerStack, bool isPrimaryDisplay) const {
+ return getLayerStack() == layerStack && (!mPrimaryDisplayOnly || isPrimaryDisplay);
+ }
+
+ void computeGeometry(const RenderArea& renderArea, Mesh& mesh, bool useIdentityTransform) const;
Rect computeBounds(const Region& activeTransparentRegion) const;
Rect computeBounds() const;
@@ -258,8 +247,7 @@
// -----------------------------------------------------------------------
// Virtuals
-
- virtual const char* getTypeId() const { return "Layer"; }
+ virtual const char* getTypeId() const = 0;
/*
* isOpaque - true if this surface is opaque
@@ -268,24 +256,18 @@
* pixel format includes an alpha channel) and the "opaque" flag set
* on the layer. It does not examine the current plane alpha value.
*/
- virtual bool isOpaque(const Layer::State& s) const;
+ virtual bool isOpaque(const Layer::State& s) const = 0;
/*
* isSecure - true if this surface is secure, that is if it prevents
* screenshots or VNC servers.
*/
- virtual bool isSecure() const;
-
- /*
- * isProtected - true if the layer may contain protected content in the
- * GRALLOC_USAGE_PROTECTED sense.
- */
- virtual bool isProtected() const;
+ bool isSecure() const;
/*
* isVisible - true if this layer is visible, false otherwise
*/
- virtual bool isVisible() const;
+ virtual bool isVisible() const = 0;
/*
* isHiddenByPolicy - true if this layer has been forced invisible.
@@ -293,46 +275,45 @@
* For example if this layer has no active buffer, it may not be hidden by
* policy, but it still can not be visible.
*/
- virtual bool isHiddenByPolicy() const;
+ bool isHiddenByPolicy() const;
/*
* isFixedSize - true if content has a fixed size
*/
- virtual bool isFixedSize() const;
+ virtual bool isFixedSize() const = 0;
+
+ bool isPendingRemoval() const { return mPendingRemoval; }
+
+ void writeToProto(LayerProto* layerInfo,
+ LayerVector::StateSet stateSet = LayerVector::StateSet::Drawing);
protected:
/*
* onDraw - draws the surface.
*/
- virtual void onDraw(const sp<const DisplayDevice>& hw, const Region& clip,
- bool useIdentityTransform) const;
+ virtual void onDraw(const RenderArea& renderArea, const Region& clip,
+ bool useIdentityTransform) const = 0;
public:
- // -----------------------------------------------------------------------
+ virtual void setDefaultBufferSize(uint32_t w, uint32_t h) = 0;
#ifdef USE_HWC2
void setGeometry(const sp<const DisplayDevice>& displayDevice, uint32_t z);
void forceClientComposition(int32_t hwcId);
- void setPerFrameData(const sp<const DisplayDevice>& displayDevice);
+ virtual void setPerFrameData(const sp<const DisplayDevice>& displayDevice) = 0;
// callIntoHwc exists so we can update our local state and call
// acceptDisplayChanges without unnecessarily updating the device's state
- void setCompositionType(int32_t hwcId, HWC2::Composition type,
- bool callIntoHwc = true);
+ void setCompositionType(int32_t hwcId, HWC2::Composition type, bool callIntoHwc = true);
HWC2::Composition getCompositionType(int32_t hwcId) const;
-
void setClearClientTarget(int32_t hwcId, bool clear);
bool getClearClientTarget(int32_t hwcId) const;
-
void updateCursorPosition(const sp<const DisplayDevice>& hw);
#else
- void setGeometry(const sp<const DisplayDevice>& hw,
- HWComposer::HWCLayerInterface& layer);
- void setPerFrameData(const sp<const DisplayDevice>& hw,
- HWComposer::HWCLayerInterface& layer);
- void setAcquireFence(const sp<const DisplayDevice>& hw,
- HWComposer::HWCLayerInterface& layer);
-
+ void setGeometry(const sp<const DisplayDevice>& hw, HWComposer::HWCLayerInterface& layer);
+ void setPerFrameData(const sp<const DisplayDevice>& hw, HWComposer::HWCLayerInterface& layer);
+ virtual void setAcquireFence(const sp<const DisplayDevice>& hw,
+ HWComposer::HWCLayerInterface& layer) = 0;
Rect getPosition(const sp<const DisplayDevice>& hw);
#endif
@@ -340,40 +321,43 @@
* called after page-flip
*/
#ifdef USE_HWC2
- void onLayerDisplayed(const sp<Fence>& releaseFence);
+ virtual void onLayerDisplayed(const sp<Fence>& releaseFence);
#else
- void onLayerDisplayed(const sp<const DisplayDevice>& hw,
- HWComposer::HWCLayerInterface* layer);
+ virtual void onLayerDisplayed(const sp<const DisplayDevice>& hw,
+ HWComposer::HWCLayerInterface* layer);
#endif
- bool shouldPresentNow(const DispSync& dispSync) const;
+ virtual void abandon() = 0;
+
+ virtual bool shouldPresentNow(const DispSync& dispSync) const = 0;
+ virtual void setTransformHint(uint32_t orientation) const = 0;
/*
* called before composition.
* returns true if the layer has pending updates.
*/
- bool onPreComposition(nsecs_t refreshStartTime);
+ virtual bool onPreComposition(nsecs_t refreshStartTime) = 0;
/*
* called after composition.
* returns true if the layer latched a new buffer this frame.
*/
- bool onPostComposition(const std::shared_ptr<FenceTime>& glDoneFence,
- const std::shared_ptr<FenceTime>& presentFence,
- const CompositorTiming& compositorTiming);
+ virtual bool onPostComposition(const std::shared_ptr<FenceTime>& glDoneFence,
+ const std::shared_ptr<FenceTime>& presentFence,
+ const CompositorTiming& compositorTiming) = 0;
#ifdef USE_HWC2
// If a buffer was replaced this frame, release the former buffer
- void releasePendingBuffer(nsecs_t dequeueReadyTime);
+ virtual void releasePendingBuffer(nsecs_t dequeueReadyTime) = 0;
#endif
/*
* draw - performs some global clipping optimizations
* and calls onDraw().
*/
- void draw(const sp<const DisplayDevice>& hw, const Region& clip) const;
- void draw(const sp<const DisplayDevice>& hw, bool useIdentityTransform) const;
- void draw(const sp<const DisplayDevice>& hw) const;
+ void draw(const RenderArea& renderArea, const Region& clip) const;
+ void draw(const RenderArea& renderArea, bool useIdentityTransform) const;
+ void draw(const RenderArea& renderArea) const;
/*
* doTransaction - process the transaction. This is a good place to figure
@@ -398,8 +382,7 @@
* setVisibleNonTransparentRegion - called when the visible and
* non-transparent region changes.
*/
- void setVisibleNonTransparentRegion(const Region&
- visibleNonTransparentRegion);
+ void setVisibleNonTransparentRegion(const Region& visibleNonTransparentRegion);
/*
* latchBuffer - called each time the screen is redrawn and returns whether
@@ -407,17 +390,22 @@
* operation, so this should be set only if needed). Typically this is used
* to figure out if the content or size of a surface has changed.
*/
- Region latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime);
+ virtual Region latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime) = 0;
+ virtual bool isBufferLatched() const = 0;
- bool isPotentialCursor() const { return mPotentialCursor;}
+ bool isPotentialCursor() const { return mPotentialCursor; }
+ /*
+ * called with the state lock from a binder thread when the layer is
+ * removed from the current list to the pending removal list
+ */
+ void onRemovedFromCurrentState();
/*
- * called with the state lock when the surface is removed from the
- * current list
+ * called with the state lock from the main thread when the layer is
+ * removed from the pending removal list
*/
void onRemoved();
-
// Updates the transform hint in our SurfaceFlingerConsumer to match
// the current orientation of the display device.
void updateTransformHint(const sp<const DisplayDevice>& hw) const;
@@ -431,60 +419,45 @@
/*
* Returns if a frame is queued.
*/
- bool hasQueuedFrame() const { return mQueuedFrames > 0 ||
- mSidebandStreamChanged || mAutoRefresh; }
+ bool hasQueuedFrame() const {
+ return mQueuedFrames > 0 || mSidebandStreamChanged || mAutoRefresh;
+ }
+
+ int32_t getQueuedFrameCount() const { return mQueuedFrames; }
#ifdef USE_HWC2
// -----------------------------------------------------------------------
- bool hasHwcLayer(int32_t hwcId) {
- if (mHwcLayers.count(hwcId) == 0) {
- return false;
- }
- if (mHwcLayers[hwcId].layer->isAbandoned()) {
- ALOGI("Erasing abandoned layer %s on %d", mName.string(), hwcId);
- mHwcLayers.erase(hwcId);
- return false;
- }
- return true;
- }
+ bool createHwcLayer(HWComposer* hwc, int32_t hwcId);
+ void destroyHwcLayer(int32_t hwcId);
+ void destroyAllHwcLayers();
- std::shared_ptr<HWC2::Layer> getHwcLayer(int32_t hwcId) {
+ bool hasHwcLayer(int32_t hwcId) { return mHwcLayers.count(hwcId) > 0; }
+
+ HWC2::Layer* getHwcLayer(int32_t hwcId) {
if (mHwcLayers.count(hwcId) == 0) {
return nullptr;
}
return mHwcLayers[hwcId].layer;
}
- void setHwcLayer(int32_t hwcId, std::shared_ptr<HWC2::Layer>&& layer) {
- if (layer) {
- mHwcLayers[hwcId].layer = layer;
- } else {
- mHwcLayers.erase(hwcId);
- }
- }
-
- void clearHwcLayers() {
- mHwcLayers.clear();
- }
-
#endif
// -----------------------------------------------------------------------
- void clearWithOpenGL(const sp<const DisplayDevice>& hw) const;
+ void clearWithOpenGL(const RenderArea& renderArea) const;
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; }
- inline State& getCurrentState() { return mCurrentState; }
+ inline const State& getDrawingState() const { return mDrawingState; }
+ inline const State& getCurrentState() const { return mCurrentState; }
+ inline State& getCurrentState() { return mCurrentState; }
+ LayerDebugInfo getLayerDebugInfo() const;
/* always call base class first */
- void dump(String8& result, Colorizer& colorizer) const;
#ifdef USE_HWC2
static void miniDumpHeader(String8& result);
void miniDump(String8& result, int32_t hwcId) const;
@@ -495,44 +468,44 @@
void logFrameStats();
void getFrameStats(FrameStats* outStats) const;
- std::vector<OccupancyTracker::Segment> getOccupancyHistory(bool forceFlush);
+ virtual std::vector<OccupancyTracker::Segment> getOccupancyHistory(bool forceFlush) = 0;
void onDisconnect();
void addAndGetFrameTimestamps(const NewFrameEventsEntry* newEntry,
- FrameEventHistoryDelta* outDelta);
+ FrameEventHistoryDelta* outDelta);
- bool getTransformToDisplayInverse() const;
+ virtual bool getTransformToDisplayInverse() const = 0;
Transform getTransform() const;
// Returns the Alpha of the Surface, accounting for the Alpha
// of parent Surfaces in the hierarchy (alpha's will be multiplied
// down the hierarchy).
-#ifdef USE_HWC2
- float getAlpha() const;
-#else
- uint8_t getAlpha() const;
-#endif
+ half getAlpha() const;
+ half4 getColor() const;
void traverseInReverseZOrder(LayerVector::StateSet stateSet,
const LayerVector::Visitor& visitor);
void traverseInZOrder(LayerVector::StateSet stateSet, const LayerVector::Visitor& visitor);
+ void traverseChildrenInZOrder(LayerVector::StateSet stateSet,
+ const LayerVector::Visitor& visitor);
+
+ size_t getChildrenCount() const;
void addChild(const sp<Layer>& layer);
// Returns index if removed, or negative value otherwise
// for symmetry with Vector::remove
ssize_t removeChild(const sp<Layer>& layer);
- sp<Layer> getParent() const { return mParent.promote(); }
+ sp<Layer> getParent() const { return mCurrentParent.promote(); }
bool hasParent() const { return getParent() != nullptr; }
-
Rect computeScreenBounds(bool reduceTransparentRegion = true) const;
bool setChildLayer(const sp<Layer>& childLayer, int32_t z);
// Copy the current list of children to the drawing state. Called by
// SurfaceFlinger to complete a transaction.
void commitChildList();
-
int32_t getZ() const;
+
protected:
// constant
sp<SurfaceFlinger> mFlinger;
@@ -543,56 +516,36 @@
class LayerCleaner {
sp<SurfaceFlinger> mFlinger;
wp<Layer> mLayer;
+
protected:
~LayerCleaner() {
// destroy client resources
mFlinger->onLayerDestroyed(mLayer);
}
- public:
- LayerCleaner(const sp<SurfaceFlinger>& flinger,
- const sp<Layer>& layer)
- : mFlinger(flinger), mLayer(layer) {
- }
- };
+ public:
+ LayerCleaner(const sp<SurfaceFlinger>& flinger, const sp<Layer>& layer)
+ : mFlinger(flinger), mLayer(layer) {}
+ };
virtual void onFirstRef();
-
-
-private:
friend class SurfaceInterceptor;
- // Interface implementation for SurfaceFlingerConsumer::ContentsChangedListener
- virtual void onFrameAvailable(const BufferItem& item) override;
- virtual void onFrameReplaced(const BufferItem& item) override;
- virtual void onSidebandStreamChanged() override;
void commitTransaction(const State& stateToCommit);
- // needsLinearFiltering - true if this surface's state requires filtering
- bool needsFiltering(const sp<const DisplayDevice>& hw) const;
-
uint32_t getEffectiveUsage(uint32_t usage) const;
FloatRect computeCrop(const sp<const DisplayDevice>& hw) const;
- // Compute the initial crop as specified by parent layers and the SurfaceControl
- // for this layer. Does not include buffer crop from the IGraphicBufferProducer
- // client, as that should not affect child clipping. Returns in screen space.
+ // Compute the initial crop as specified by parent layers and the
+ // SurfaceControl for this layer. Does not include buffer crop from the
+ // IGraphicBufferProducer client, as that should not affect child clipping.
+ // Returns in screen space.
Rect computeInitialCrop(const sp<const DisplayDevice>& hw) const;
- bool isCropped() const;
- static bool getOpacityForFormat(uint32_t format);
// drawing
- void clearWithOpenGL(const sp<const DisplayDevice>& hw,
- float r, float g, float b, float alpha) const;
- void drawWithOpenGL(const sp<const DisplayDevice>& hw,
- bool useIdentityTransform) const;
-
- // Temporary - Used only for LEGACY camera mode.
- uint32_t getProducerStickyTransform() const;
-
- // Loads the corresponding system property once per process
- static bool latchUnsignaledBuffers();
+ void clearWithOpenGL(const RenderArea& renderArea, float r, float g, float b,
+ float alpha) const;
void setParent(const sp<Layer>& layer);
@@ -600,33 +553,20 @@
void addZOrderRelative(const wp<Layer>& relative);
void removeZOrderRelative(const wp<Layer>& relative);
- // -----------------------------------------------------------------------
-
- class SyncPoint
- {
+ class SyncPoint {
public:
- explicit SyncPoint(uint64_t frameNumber) : mFrameNumber(frameNumber),
- mFrameIsAvailable(false), mTransactionIsApplied(false) {}
+ explicit SyncPoint(uint64_t frameNumber)
+ : mFrameNumber(frameNumber), mFrameIsAvailable(false), mTransactionIsApplied(false) {}
- uint64_t getFrameNumber() const {
- return mFrameNumber;
- }
+ uint64_t getFrameNumber() const { return mFrameNumber; }
- bool frameIsAvailable() const {
- return mFrameIsAvailable;
- }
+ bool frameIsAvailable() const { return mFrameIsAvailable; }
- void setFrameAvailable() {
- mFrameIsAvailable = true;
- }
+ void setFrameAvailable() { mFrameIsAvailable = true; }
- bool transactionIsApplied() const {
- return mTransactionIsApplied;
- }
+ bool transactionIsApplied() const { return mTransactionIsApplied; }
- void setTransactionApplied() {
- mTransactionIsApplied = true;
- }
+ void setTransactionApplied() { mTransactionIsApplied = true; }
private:
const uint64_t mFrameNumber;
@@ -644,9 +584,6 @@
// is applied
std::list<std::shared_ptr<SyncPoint>> mRemoteSyncPoints;
- uint64_t getHeadFrameNumber() const;
- bool headFenceHasSignaled() const;
-
// Returns false if the relevant frame has already been latched
bool addSyncPoint(const std::shared_ptr<SyncPoint>& point);
@@ -659,7 +596,8 @@
// Returns mCurrentScaling mode (originating from the
// Client) or mOverrideScalingMode mode (originating from
// the Surface Controller) if set.
- uint32_t getEffectiveScalingMode() const;
+ virtual uint32_t getEffectiveScalingMode() const = 0;
+
public:
/*
* The layer handle is just a BBinder object passed to the client
@@ -670,34 +608,27 @@
* this layer when the handle is destroyed.
*/
class Handle : public BBinder, public LayerCleaner {
- public:
- Handle(const sp<SurfaceFlinger>& flinger, const sp<Layer>& layer)
- : LayerCleaner(flinger, layer), owner(layer) {}
+ public:
+ Handle(const sp<SurfaceFlinger>& flinger, const sp<Layer>& layer)
+ : LayerCleaner(flinger, layer), owner(layer) {}
- wp<Layer> owner;
+ wp<Layer> owner;
};
sp<IBinder> getHandle();
- sp<IGraphicBufferProducer> getProducer() const;
const String8& getName() const;
- void notifyAvailableFrames();
-private:
+ virtual void notifyAvailableFrames() = 0;
+ virtual PixelFormat getPixelFormat() const = 0;
+ bool getPremultipledAlpha() const;
+protected:
// -----------------------------------------------------------------------
- // Check all of the local sync points to ensure that all transactions
- // which need to have been applied prior to the frame which is about to
- // be latched have signaled
- bool allTransactionsSignaled();
-
- // constants
- sp<SurfaceFlingerConsumer> mSurfaceFlingerConsumer;
- sp<IGraphicBufferProducer> mProducer;
- uint32_t mTextureName; // from GLES
bool mPremultipliedAlpha;
String8 mName;
String8 mTransactionName; // A cached version of "TX - " + mName for systraces
- PixelFormat mFormat;
+
+ bool mPrimaryDisplayOnly = false;
// these are protected by an external lock
State mCurrentState;
@@ -728,14 +659,10 @@
sp<NativeHandle> mSidebandStream;
Rect mCurrentCrop;
uint32_t mCurrentTransform;
- uint32_t mCurrentScalingMode;
// We encode unset as -1.
int32_t mOverrideScalingMode;
bool mCurrentOpacity;
- bool mBufferLatched = false; // TODO: Use mActiveBuffer?
std::atomic<uint64_t> mCurrentFrameNumber;
- uint64_t mPreviousFrameNumber; // Only accessed on the main thread.
- bool mRefreshPending;
bool mFrameLatencyNeeded;
// Whether filtering is forced on or not
bool mFiltering;
@@ -743,19 +670,21 @@
bool mNeedsFiltering;
// The mesh used to draw the layer in GLES composition mode
mutable Mesh mMesh;
- // The texture used to draw the layer in GLES composition mode
- mutable Texture mTexture;
+
+ bool mPendingRemoval = false;
#ifdef USE_HWC2
// HWC items, accessed from the main thread
struct HWCInfo {
HWCInfo()
- : layer(),
- forceClientComposition(false),
- compositionType(HWC2::Composition::Invalid),
- clearClientTarget(false) {}
+ : hwc(nullptr),
+ layer(nullptr),
+ forceClientComposition(false),
+ compositionType(HWC2::Composition::Invalid),
+ clearClientTarget(false) {}
- std::shared_ptr<HWC2::Layer> layer;
+ HWComposer* hwc;
+ HWC2::Layer* layer;
bool forceClientComposition;
HWC2::Composition compositionType;
bool clearClientTarget;
@@ -778,8 +707,7 @@
// protected by mLock
mutable Mutex mLock;
- // Set to true once we've returned this surface's handle
- mutable bool mHasSurface;
+
const wp<Client> mClientRef;
// This layer can be a cursor on some displays.
@@ -790,8 +718,6 @@
Condition mQueueItemCondition;
Vector<BufferItem> mQueueItems;
std::atomic<uint64_t> mLastFrameNumberReceived;
- bool mUpdateTexImageFailed; // This is only accessed on the main thread.
-
bool mAutoRefresh;
bool mFreezeGeometryUpdates;
@@ -800,7 +726,8 @@
// Child list used for rendering.
LayerVector mDrawingChildren;
- wp<Layer> mParent;
+ wp<Layer> mCurrentParent;
+ wp<Layer> mDrawingParent;
};
// ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/LayerDim.cpp b/services/surfaceflinger/LayerDim.cpp
deleted file mode 100644
index daebf8a..0000000
--- a/services/surfaceflinger/LayerDim.cpp
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-// #define LOG_NDEBUG 0
-#undef LOG_TAG
-#define LOG_TAG "LayerDim"
-
-#include <stdlib.h>
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <utils/Errors.h>
-#include <utils/Log.h>
-
-#include <ui/GraphicBuffer.h>
-
-#include "LayerDim.h"
-#include "SurfaceFlinger.h"
-#include "DisplayDevice.h"
-#include "RenderEngine/RenderEngine.h"
-
-namespace android {
-// ---------------------------------------------------------------------------
-
-LayerDim::LayerDim(SurfaceFlinger* flinger, const sp<Client>& client,
- const String8& name, uint32_t w, uint32_t h, uint32_t flags)
- : Layer(flinger, client, name, w, h, flags) {
-}
-
-LayerDim::~LayerDim() {
-}
-
-void LayerDim::onDraw(const sp<const DisplayDevice>& hw,
- const Region& /* clip */, bool useIdentityTransform) const
-{
- const State& s(getDrawingState());
- if (s.alpha>0) {
- Mesh mesh(Mesh::TRIANGLE_FAN, 4, 2);
- computeGeometry(hw, mesh, useIdentityTransform);
- RenderEngine& engine(mFlinger->getRenderEngine());
- engine.setupDimLayerBlending(s.alpha);
- engine.drawMesh(mesh);
- engine.disableBlending();
- }
-}
-
-bool LayerDim::isVisible() const {
- const Layer::State& s(getDrawingState());
- return !isHiddenByPolicy() && s.alpha;
-}
-
-
-// ---------------------------------------------------------------------------
-
-}; // namespace android
diff --git a/services/surfaceflinger/LayerDim.h b/services/surfaceflinger/LayerDim.h
deleted file mode 100644
index a0cfca9..0000000
--- a/services/surfaceflinger/LayerDim.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_LAYER_DIM_H
-#define ANDROID_LAYER_DIM_H
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include "Layer.h"
-
-// ---------------------------------------------------------------------------
-
-namespace android {
-
-class LayerDim : public Layer
-{
-public:
- LayerDim(SurfaceFlinger* flinger, const sp<Client>& client,
- const String8& name, uint32_t w, uint32_t h, uint32_t flags);
- virtual ~LayerDim();
-
- virtual const char* getTypeId() const { return "LayerDim"; }
- virtual void onDraw(const sp<const DisplayDevice>& hw, const Region& clip,
- bool useIdentityTransform) const;
- virtual bool isOpaque(const Layer::State&) const { return false; }
- virtual bool isSecure() const { return false; }
- virtual bool isFixedSize() const { return true; }
- virtual bool isVisible() const;
-};
-
-// ---------------------------------------------------------------------------
-
-}; // namespace android
-
-#endif // ANDROID_LAYER_DIM_H
diff --git a/services/surfaceflinger/LayerProtoHelper.cpp b/services/surfaceflinger/LayerProtoHelper.cpp
new file mode 100644
index 0000000..6a33148
--- /dev/null
+++ b/services/surfaceflinger/LayerProtoHelper.cpp
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 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 "LayerProtoHelper.h"
+
+namespace android {
+namespace surfaceflinger {
+void LayerProtoHelper::writeToProto(const Region& region, RegionProto* regionProto) {
+ Region::const_iterator head = region.begin();
+ Region::const_iterator const tail = region.end();
+ uint64_t address = reinterpret_cast<uint64_t>(®ion);
+ regionProto->set_id(address);
+ while (head != tail) {
+ RectProto* rectProto = regionProto->add_rect();
+ writeToProto(*head, rectProto);
+ head++;
+ }
+}
+
+void LayerProtoHelper::writeToProto(const Rect& rect, RectProto* rectProto) {
+ rectProto->set_left(rect.left);
+ rectProto->set_top(rect.top);
+ rectProto->set_bottom(rect.bottom);
+ rectProto->set_right(rect.right);
+}
+
+void LayerProtoHelper::writeToProto(const half4 color, ColorProto* colorProto) {
+ colorProto->set_r(color.r);
+ colorProto->set_g(color.g);
+ colorProto->set_b(color.b);
+ colorProto->set_a(color.a);
+}
+
+void LayerProtoHelper::writeToProto(const Transform& transform, TransformProto* transformProto) {
+ transformProto->set_dsdx(transform[0][0]);
+ transformProto->set_dtdx(transform[0][1]);
+ transformProto->set_dsdy(transform[1][0]);
+ transformProto->set_dtdy(transform[1][1]);
+}
+
+void LayerProtoHelper::writeToProto(const sp<GraphicBuffer>& buffer,
+ ActiveBufferProto* activeBufferProto) {
+ activeBufferProto->set_width(buffer->getWidth());
+ activeBufferProto->set_height(buffer->getHeight());
+ activeBufferProto->set_stride(buffer->getStride());
+ activeBufferProto->set_format(buffer->format);
+}
+
+} // namespace surfaceflinger
+} // namespace android
diff --git a/services/surfaceflinger/LayerProtoHelper.h b/services/surfaceflinger/LayerProtoHelper.h
new file mode 100644
index 0000000..45a0b5d
--- /dev/null
+++ b/services/surfaceflinger/LayerProtoHelper.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 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 <layerproto/LayerProtoHeader.h>
+
+#include <ui/GraphicBuffer.h>
+#include <ui/Rect.h>
+#include <ui/Region.h>
+
+#include <Transform.h>
+
+#include <math/vec4.h>
+
+namespace android {
+namespace surfaceflinger {
+class LayerProtoHelper {
+public:
+ static void writeToProto(const Rect& rect, RectProto* rectProto);
+ static void writeToProto(const Region& region, RegionProto* regionProto);
+ static void writeToProto(const half4 color, ColorProto* colorProto);
+ static void writeToProto(const Transform& transform, TransformProto* transformProto);
+ static void writeToProto(const sp<GraphicBuffer>& buffer, ActiveBufferProto* activeBufferProto);
+};
+
+} // namespace surfaceflinger
+} // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/LayerVector.cpp b/services/surfaceflinger/LayerVector.cpp
index 2233e78..d0f8fbe 100644
--- a/services/surfaceflinger/LayerVector.cpp
+++ b/services/surfaceflinger/LayerVector.cpp
@@ -35,14 +35,17 @@
uint32_t ls = l->getCurrentState().layerStack;
uint32_t rs = r->getCurrentState().layerStack;
if (ls != rs)
- return ls - rs;
+ return (ls > rs) ? 1 : -1;
uint32_t lz = l->getCurrentState().z;
uint32_t rz = r->getCurrentState().z;
if (lz != rz)
- return lz - rz;
+ return (lz > rz) ? 1 : -1;
- return l->sequence - r->sequence;
+ if (l->sequence == r->sequence)
+ return 0;
+
+ return (l->sequence > r->sequence) ? 1 : -1;
}
void LayerVector::traverseInZOrder(StateSet stateSet, const Visitor& visitor) const {
diff --git a/services/surfaceflinger/MessageQueue.cpp b/services/surfaceflinger/MessageQueue.cpp
index bca3430..0b1199c 100644
--- a/services/surfaceflinger/MessageQueue.cpp
+++ b/services/surfaceflinger/MessageQueue.cpp
@@ -91,6 +91,14 @@
void MessageQueue::setEventThread(const sp<EventThread>& eventThread)
{
+ if (mEventThread == eventThread) {
+ return;
+ }
+
+ if (mEventTube.getFd() >= 0) {
+ mLooper->removeFd(mEventTube.getFd());
+ }
+
mEventThread = eventThread;
mEvents = eventThread->createEventConnection();
mEvents->stealReceiveChannel(&mEventTube);
diff --git a/services/surfaceflinger/MessageQueue.h b/services/surfaceflinger/MessageQueue.h
index 85a33c8..14f50bb 100644
--- a/services/surfaceflinger/MessageQueue.h
+++ b/services/surfaceflinger/MessageQueue.h
@@ -30,6 +30,8 @@
#include "Barrier.h"
+#include <functional>
+
namespace android {
class IDisplayEventConnection;
@@ -58,6 +60,21 @@
mutable Barrier barrier;
};
+class LambdaMessage : public MessageBase {
+public:
+ explicit LambdaMessage(std::function<void()> handler)
+ : MessageBase(), mHandler(std::move(handler)) {}
+
+ bool handler() override {
+ mHandler();
+ // This return value is no longer checked, so it's always safe to return true
+ return true;
+ }
+
+private:
+ const std::function<void()> mHandler;
+};
+
// ---------------------------------------------------------------------------
class MessageQueue {
diff --git a/services/surfaceflinger/MonitoredProducer.cpp b/services/surfaceflinger/MonitoredProducer.cpp
index 2ba1b33..1a5a85e 100644
--- a/services/surfaceflinger/MonitoredProducer.cpp
+++ b/services/surfaceflinger/MonitoredProducer.cpp
@@ -68,11 +68,11 @@
return mProducer->setAsyncMode(async);
}
-status_t MonitoredProducer::dequeueBuffer(int* slot, sp<Fence>* fence,
- uint32_t w, uint32_t h, PixelFormat format, uint32_t usage,
- FrameEventHistoryDelta* outTimestamps) {
- return mProducer->dequeueBuffer(
- slot, fence, w, h, format, usage, outTimestamps);
+status_t MonitoredProducer::dequeueBuffer(int* slot, sp<Fence>* fence, uint32_t w, uint32_t h,
+ PixelFormat format, uint64_t usage,
+ uint64_t* outBufferAge,
+ FrameEventHistoryDelta* outTimestamps) {
+ return mProducer->dequeueBuffer(slot, fence, w, h, format, usage, outBufferAge, outTimestamps);
}
status_t MonitoredProducer::detachBuffer(int slot) {
@@ -116,7 +116,7 @@
}
void MonitoredProducer::allocateBuffers(uint32_t width, uint32_t height,
- PixelFormat format, uint32_t usage) {
+ PixelFormat format, uint64_t usage) {
mProducer->allocateBuffers(width, height, format, usage);
}
@@ -158,6 +158,10 @@
return mProducer->getUniqueId(outId);
}
+status_t MonitoredProducer::getConsumerUsage(uint64_t* outUsage) const {
+ return mProducer->getConsumerUsage(outUsage);
+}
+
IBinder* MonitoredProducer::onAsBinder() {
return this;
}
diff --git a/services/surfaceflinger/MonitoredProducer.h b/services/surfaceflinger/MonitoredProducer.h
index a3ec29d..1246d14 100644
--- a/services/surfaceflinger/MonitoredProducer.h
+++ b/services/surfaceflinger/MonitoredProducer.h
@@ -39,9 +39,9 @@
virtual status_t requestBuffer(int slot, sp<GraphicBuffer>* buf);
virtual status_t setMaxDequeuedBufferCount(int maxDequeuedBuffers);
virtual status_t setAsyncMode(bool async);
- virtual status_t dequeueBuffer(int* slot, sp<Fence>* fence, uint32_t w,
- uint32_t h, PixelFormat format, uint32_t usage,
- FrameEventHistoryDelta* outTimestamps);
+ virtual status_t dequeueBuffer(int* slot, sp<Fence>* fence, uint32_t w, uint32_t h,
+ PixelFormat format, uint64_t usage, uint64_t* outBufferAge,
+ FrameEventHistoryDelta* outTimestamps);
virtual status_t detachBuffer(int slot);
virtual status_t detachNextBuffer(sp<GraphicBuffer>* outBuffer,
sp<Fence>* outFence);
@@ -56,7 +56,7 @@
virtual status_t disconnect(int api, DisconnectMode mode);
virtual status_t setSidebandStream(const sp<NativeHandle>& stream);
virtual void allocateBuffers(uint32_t width, uint32_t height,
- PixelFormat format, uint32_t usage);
+ PixelFormat format, uint64_t usage);
virtual status_t allowAllocation(bool allow);
virtual status_t setGenerationNumber(uint32_t generationNumber);
virtual String8 getConsumerName() const override;
@@ -68,6 +68,7 @@
virtual status_t setAutoRefresh(bool autoRefresh) override;
virtual void getFrameTimestamps(FrameEventHistoryDelta *outDelta) override;
virtual status_t getUniqueId(uint64_t* outId) const override;
+ virtual status_t getConsumerUsage(uint64_t* outUsage) const override;
// The Layer which created this producer, and on which queued Buffer's will be displayed.
sp<Layer> getLayer() const;
diff --git a/services/surfaceflinger/RenderArea.cpp b/services/surfaceflinger/RenderArea.cpp
new file mode 100644
index 0000000..6225df1
--- /dev/null
+++ b/services/surfaceflinger/RenderArea.cpp
@@ -0,0 +1,34 @@
+#include "RenderArea.h"
+
+namespace android {
+
+/*
+ * Checks that the requested width and height are valid and updates them to the render area
+ * dimensions if they are set to 0
+ */
+status_t RenderArea::updateDimensions() {
+ // get screen geometry
+
+ uint32_t width = getWidth();
+ uint32_t height = getHeight();
+
+ if (mRotationFlags & Transform::ROT_90) {
+ std::swap(width, height);
+ }
+
+ if ((mReqWidth > width) || (mReqHeight > height)) {
+ ALOGE("size mismatch (%d, %d) > (%d, %d)", mReqWidth, mReqHeight, width, height);
+ return BAD_VALUE;
+ }
+
+ if (mReqWidth == 0) {
+ mReqWidth = width;
+ }
+ if (mReqHeight == 0) {
+ mReqHeight = height;
+ }
+
+ return NO_ERROR;
+}
+
+} // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/RenderArea.h b/services/surfaceflinger/RenderArea.h
new file mode 100644
index 0000000..faf1ec6
--- /dev/null
+++ b/services/surfaceflinger/RenderArea.h
@@ -0,0 +1,40 @@
+#pragma once
+
+#include "Transform.h"
+
+namespace android {
+
+class RenderArea {
+public:
+ RenderArea(uint32_t reqHeight, uint32_t reqWidth, ISurfaceComposer::Rotation rotation)
+ : mReqHeight(reqHeight), mReqWidth(reqWidth) {
+ mRotationFlags = Transform::fromRotation(rotation);
+ }
+
+ virtual ~RenderArea() = default;
+
+ virtual const Transform& getTransform() const = 0;
+ virtual Rect getBounds() const = 0;
+ virtual int getHeight() const = 0;
+ virtual int getWidth() const = 0;
+ virtual bool isSecure() const = 0;
+ virtual bool needsFiltering() const = 0;
+ virtual Rect getSourceCrop() const = 0;
+
+ int getReqHeight() const { return mReqHeight; };
+ int getReqWidth() const { return mReqWidth; };
+ Transform::orientation_flags getRotationFlags() const { return mRotationFlags; };
+#ifdef USE_HWC2
+ virtual bool getWideColorSupport() const = 0;
+ virtual android_color_mode_t getActiveColorMode() const = 0;
+#endif
+
+ status_t updateDimensions();
+
+private:
+ uint32_t mReqHeight;
+ uint32_t mReqWidth;
+ Transform::orientation_flags mRotationFlags;
+};
+
+} // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/RenderEngine/Description.cpp b/services/surfaceflinger/RenderEngine/Description.cpp
index 0dab872..706960c 100644
--- a/services/surfaceflinger/RenderEngine/Description.cpp
+++ b/services/surfaceflinger/RenderEngine/Description.cpp
@@ -26,60 +26,39 @@
namespace android {
-Description::Description() :
- mUniformsDirty(true) {
- mPlaneAlpha = 1.0f;
+Description::Description() {
mPremultipliedAlpha = false;
mOpaque = true;
mTextureEnabled = false;
mColorMatrixEnabled = false;
-
- memset(mColor, 0, sizeof(mColor));
}
Description::~Description() {
}
-void Description::setPlaneAlpha(GLclampf planeAlpha) {
- if (planeAlpha != mPlaneAlpha) {
- mUniformsDirty = true;
- mPlaneAlpha = planeAlpha;
- }
-}
-
void Description::setPremultipliedAlpha(bool premultipliedAlpha) {
- if (premultipliedAlpha != mPremultipliedAlpha) {
- mPremultipliedAlpha = premultipliedAlpha;
- }
+ mPremultipliedAlpha = premultipliedAlpha;
}
void Description::setOpaque(bool opaque) {
- if (opaque != mOpaque) {
- mOpaque = opaque;
- }
+ mOpaque = opaque;
}
void Description::setTexture(const Texture& texture) {
mTexture = texture;
mTextureEnabled = true;
- mUniformsDirty = true;
}
void Description::disableTexture() {
mTextureEnabled = false;
}
-void Description::setColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) {
- mColor[0] = red;
- mColor[1] = green;
- mColor[2] = blue;
- mColor[3] = alpha;
- mUniformsDirty = true;
+void Description::setColor(const half4& color) {
+ mColor = color;
}
void Description::setProjectionMatrix(const mat4& mtx) {
mProjectionMatrix = mtx;
- mUniformsDirty = true;
}
void Description::setColorMatrix(const mat4& mtx) {
@@ -92,5 +71,8 @@
return mColorMatrix;
}
+void Description::setWideGamut(bool wideGamut) {
+ mIsWideGamut = wideGamut;
+}
} /* namespace android */
diff --git a/services/surfaceflinger/RenderEngine/Description.h b/services/surfaceflinger/RenderEngine/Description.h
index 8a3447c..cbac855 100644
--- a/services/surfaceflinger/RenderEngine/Description.h
+++ b/services/surfaceflinger/RenderEngine/Description.h
@@ -35,8 +35,6 @@
friend class Program;
friend class ProgramCache;
- // value of the plane-alpha, between 0 and 1
- GLclampf mPlaneAlpha;
// whether textures are premultiplied
bool mPremultipliedAlpha;
// whether this layer is marked as opaque
@@ -46,30 +44,29 @@
Texture mTexture;
bool mTextureEnabled;
- // color used when texturing is disabled
- GLclampf mColor[4];
+ // color used when texturing is disabled or when setting alpha.
+ half4 mColor;
// projection matrix
mat4 mProjectionMatrix;
bool mColorMatrixEnabled;
mat4 mColorMatrix;
+ bool mIsWideGamut;
+
public:
Description();
~Description();
- void setPlaneAlpha(GLclampf planeAlpha);
void setPremultipliedAlpha(bool premultipliedAlpha);
void setOpaque(bool opaque);
void setTexture(const Texture& texture);
void disableTexture();
- void setColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
+ void setColor(const half4& color);
void setProjectionMatrix(const mat4& mtx);
void setColorMatrix(const mat4& mtx);
const mat4& getColorMatrix() const;
-
-private:
- bool mUniformsDirty;
+ void setWideGamut(bool wideGamut);
};
} /* namespace android */
diff --git a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp
index a1ee294..daaa11e 100644
--- a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp
+++ b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp
@@ -139,11 +139,10 @@
// Display-P3 only.
mat3 srgbToP3 = ColorSpaceConnector(ColorSpace::sRGB(), ColorSpace::DisplayP3()).getTransform();
- // color transform needs to be transposed and expanded to 4x4
- // to be what the shader wants
+ // color transform needs to be expanded to 4x4 to be what the shader wants
// mat has an initializer that expands mat3 to mat4, but
// not an assignment operator
- mat4 gamutTransform(transpose(srgbToP3));
+ mat4 gamutTransform(srgbToP3);
mSrgbToDisplayP3 = gamutTransform;
}
#endif
@@ -205,25 +204,17 @@
mVpHeight = vph;
}
-#ifdef USE_HWC2
void GLES20RenderEngine::setupLayerBlending(bool premultipliedAlpha,
- bool opaque, float alpha) {
-#else
-void GLES20RenderEngine::setupLayerBlending(
- bool premultipliedAlpha, bool opaque, int alpha) {
-#endif
-
+ bool opaque, bool disableTexture, const half4& color) {
mState.setPremultipliedAlpha(premultipliedAlpha);
mState.setOpaque(opaque);
-#ifdef USE_HWC2
- mState.setPlaneAlpha(alpha);
+ mState.setColor(color);
- if (alpha < 1.0f || !opaque) {
-#else
- mState.setPlaneAlpha(alpha / 255.0f);
+ if (disableTexture) {
+ mState.disableTexture();
+ }
- if (alpha < 0xFF || !opaque) {
-#endif
+ if (color.a < 1.0f || !opaque) {
glEnable(GL_BLEND);
glBlendFunc(premultipliedAlpha ? GL_ONE : GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
} else {
@@ -232,33 +223,6 @@
}
#ifdef USE_HWC2
-void GLES20RenderEngine::setupDimLayerBlending(float alpha) {
-#else
-void GLES20RenderEngine::setupDimLayerBlending(int alpha) {
-#endif
- mState.setPlaneAlpha(1.0f);
- mState.setPremultipliedAlpha(true);
- mState.setOpaque(false);
-#ifdef USE_HWC2
- mState.setColor(0, 0, 0, alpha);
-#else
- mState.setColor(0, 0, 0, alpha/255.0f);
-#endif
- mState.disableTexture();
-
-#ifdef USE_HWC2
- if (alpha == 1.0f) {
-#else
- if (alpha == 0xFF) {
-#endif
- glDisable(GL_BLEND);
- } else {
- glEnable(GL_BLEND);
- glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
- }
-}
-
-#ifdef USE_HWC2
void GLES20RenderEngine::setColorMode(android_color_mode mode) {
ALOGV("setColorMode: %s (0x%x)", decodeColorMode(mode).c_str(), mode);
@@ -356,10 +320,9 @@
}
void GLES20RenderEngine::setupFillWithColor(float r, float g, float b, float a) {
- mState.setPlaneAlpha(1.0f);
mState.setPremultipliedAlpha(true);
mState.setOpaque(false);
- mState.setColor(r, g, b, a);
+ mState.setColor(half4(r, g, b, a));
mState.disableTexture();
glDisable(GL_BLEND);
}
@@ -386,6 +349,7 @@
Description wideColorState = mState;
if (mDataSpace != HAL_DATASPACE_DISPLAY_P3) {
wideColorState.setColorMatrix(mState.getColorMatrix() * mSrgbToDisplayP3);
+ wideColorState.setWideGamut(true);
ALOGV("drawMesh: gamut transform applied");
}
ProgramCache::getInstance().useProgram(wideColorState);
diff --git a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h
index eaf94af..5ac12fc 100644
--- a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h
+++ b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h
@@ -68,10 +68,9 @@
virtual void setViewportAndProjection(size_t vpw, size_t vph,
Rect sourceCrop, size_t hwh, bool yswap,
Transform::orientation_flags rotation);
-#ifdef USE_HWC2
virtual void setupLayerBlending(bool premultipliedAlpha, bool opaque,
- float alpha) override;
- virtual void setupDimLayerBlending(float alpha) override;
+ bool disableTexture, const half4& color) override;
+#ifdef USE_HWC2
// Color management related functions and state
void setColorMode(android_color_mode mode);
@@ -92,10 +91,6 @@
// Currently only supporting sRGB and DisplayP3 color spaces
mat4 mSrgbToDisplayP3;
-#else
- virtual void setupLayerBlending(bool premultipliedAlpha, bool opaque,
- int alpha);
- virtual void setupDimLayerBlending(int alpha);
#endif
bool mPlatformHasWideColor = false;
diff --git a/services/surfaceflinger/RenderEngine/Program.cpp b/services/surfaceflinger/RenderEngine/Program.cpp
index 48a8da5..bd2188b 100644
--- a/services/surfaceflinger/RenderEngine/Program.cpp
+++ b/services/surfaceflinger/RenderEngine/Program.cpp
@@ -22,6 +22,7 @@
#include "Program.h"
#include "ProgramCache.h"
#include "Description.h"
+#include <math/mat4.h>
namespace android {
@@ -63,7 +64,6 @@
mTextureMatrixLoc = glGetUniformLocation(programId, "texture");
mSamplerLoc = glGetUniformLocation(programId, "sampler");
mColorLoc = glGetUniformLocation(programId, "color");
- mAlphaPlaneLoc = glGetUniformLocation(programId, "alphaPlane");
// set-up the default values for our uniforms
glUseProgram(programId);
@@ -132,11 +132,9 @@
glUniform1i(mSamplerLoc, 0);
glUniformMatrix4fv(mTextureMatrixLoc, 1, GL_FALSE, desc.mTexture.getMatrix().asArray());
}
- if (mAlphaPlaneLoc >= 0) {
- glUniform1f(mAlphaPlaneLoc, desc.mPlaneAlpha);
- }
if (mColorLoc >= 0) {
- glUniform4fv(mColorLoc, 1, desc.mColor);
+ const float color[4] = {desc.mColor.r, desc.mColor.g, desc.mColor.b, desc.mColor.a};
+ glUniform4fv(mColorLoc, 1, color);
}
if (mColorMatrixLoc >= 0) {
glUniformMatrix4fv(mColorMatrixLoc, 1, GL_FALSE, desc.mColorMatrix.asArray());
diff --git a/services/surfaceflinger/RenderEngine/Program.h b/services/surfaceflinger/RenderEngine/Program.h
index 36bd120..a2ae2ee 100644
--- a/services/surfaceflinger/RenderEngine/Program.h
+++ b/services/surfaceflinger/RenderEngine/Program.h
@@ -79,9 +79,6 @@
/* location of the sampler uniform */
GLint mSamplerLoc;
- /* location of the alpha plane uniform */
- GLint mAlphaPlaneLoc;
-
/* location of the color uniform */
GLint mColorLoc;
};
diff --git a/services/surfaceflinger/RenderEngine/ProgramCache.cpp b/services/surfaceflinger/RenderEngine/ProgramCache.cpp
index ba11259..b437545 100644
--- a/services/surfaceflinger/RenderEngine/ProgramCache.cpp
+++ b/services/surfaceflinger/RenderEngine/ProgramCache.cpp
@@ -89,7 +89,7 @@
void ProgramCache::primeCache() {
uint32_t shaderCount = 0;
uint32_t keyMask = Key::BLEND_MASK | Key::OPACITY_MASK |
- Key::PLANE_ALPHA_MASK | Key::TEXTURE_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.
@@ -122,14 +122,16 @@
description.mTexture.getTextureTarget() == GL_TEXTURE_EXTERNAL_OES ? Key::TEXTURE_EXT :
description.mTexture.getTextureTarget() == GL_TEXTURE_2D ? Key::TEXTURE_2D :
Key::TEXTURE_OFF)
- .set(Key::PLANE_ALPHA_MASK,
- (description.mPlaneAlpha < 1) ? Key::PLANE_ALPHA_LT_ONE : Key::PLANE_ALPHA_EQ_ONE)
+ .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);
+ 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;
}
@@ -166,44 +168,91 @@
} else if (needs.getTextureTarget() == Key::TEXTURE_2D) {
fs << "uniform sampler2D sampler;"
<< "varying vec2 outTexCoords;";
- } else if (needs.getTextureTarget() == Key::TEXTURE_OFF) {
+ }
+
+ if (needs.getTextureTarget() == Key::TEXTURE_OFF || needs.hasAlpha()) {
fs << "uniform vec4 color;";
}
- if (needs.hasPlaneAlpha()) {
- fs << "uniform float alphaPlane;";
- }
+
if (needs.hasColorMatrix()) {
fs << "uniform mat4 colorMatrix;";
}
+ if (needs.hasColorMatrix()) {
+ // When in wide gamut mode, the color matrix will contain a color space
+ // conversion matrix that needs to be applied in linear space
+ // When not in wide gamut, we can simply no-op the transfer functions
+ // and let the shader compiler get rid of them
+ if (needs.isWideGamut()) {
+ fs << R"__SHADER__(
+ float OETF_sRGB(const float linear) {
+ return linear <= 0.0031308 ?
+ linear * 12.92 : (pow(linear, 1.0 / 2.4) * 1.055) - 0.055;
+ }
+
+ vec3 OETF_sRGB(const vec3 linear) {
+ return vec3(OETF_sRGB(linear.r), OETF_sRGB(linear.g), OETF_sRGB(linear.b));
+ }
+
+ vec3 OETF_scRGB(const vec3 linear) {
+ return sign(linear.rgb) * OETF_sRGB(abs(linear.rgb));
+ }
+
+ float EOTF_sRGB(float srgb) {
+ return srgb <= 0.04045 ? srgb / 12.92 : pow((srgb + 0.055) / 1.055, 2.4);
+ }
+
+ vec3 EOTF_sRGB(const vec3 srgb) {
+ return vec3(EOTF_sRGB(srgb.r), EOTF_sRGB(srgb.g), EOTF_sRGB(srgb.b));
+ }
+
+ vec3 EOTF_scRGB(const vec3 srgb) {
+ return sign(srgb.rgb) * EOTF_sRGB(abs(srgb.rgb));
+ }
+ )__SHADER__";
+ } else {
+ fs << R"__SHADER__(
+ vec3 OETF_scRGB(const vec3 linear) {
+ return linear;
+ }
+
+ vec3 EOTF_scRGB(const vec3 srgb) {
+ return srgb;
+ }
+ )__SHADER__";
+ }
+ }
fs << "void main(void) {" << indent;
if (needs.isTexturing()) {
fs << "gl_FragColor = texture2D(sampler, outTexCoords);";
} else {
- fs << "gl_FragColor = color;";
+ fs << "gl_FragColor.rgb = color.rgb;";
+ fs << "gl_FragColor.a = 1.0;";
}
if (needs.isOpaque()) {
fs << "gl_FragColor.a = 1.0;";
}
- if (needs.hasPlaneAlpha()) {
- // modulate the alpha value with planeAlpha
+ if (needs.hasAlpha()) {
+ // modulate the current alpha value with alpha set
if (needs.isPremultiplied()) {
// ... and the color too if we're premultiplied
- fs << "gl_FragColor *= alphaPlane;";
+ fs << "gl_FragColor *= color.a;";
} else {
- fs << "gl_FragColor.a *= alphaPlane;";
+ fs << "gl_FragColor.a *= color.a;";
}
}
if (needs.hasColorMatrix()) {
if (!needs.isOpaque() && needs.isPremultiplied()) {
// un-premultiply if needed before linearization
- fs << "gl_FragColor.rgb = gl_FragColor.rgb/gl_FragColor.a;";
+ // avoid divide by 0 by adding 0.5/256 to the alpha channel
+ fs << "gl_FragColor.rgb = gl_FragColor.rgb / (gl_FragColor.a + 0.0019);";
}
- fs << "vec4 transformed = colorMatrix * vec4(gl_FragColor.rgb, 1);";
- fs << "gl_FragColor.rgb = transformed.rgb/transformed.a;";
+ fs << "vec4 transformed = colorMatrix * vec4(EOTF_scRGB(gl_FragColor.rgb), 1);";
+ // We assume the last row is always {0,0,0,1} and we skip the division by w
+ fs << "gl_FragColor.rgb = OETF_scRGB(transformed.rgb);";
if (!needs.isOpaque() && needs.isPremultiplied()) {
// and re-premultiply if needed after gamma correction
- fs << "gl_FragColor.rgb = gl_FragColor.rgb*gl_FragColor.a;";
+ fs << "gl_FragColor.rgb = gl_FragColor.rgb * (gl_FragColor.a + 0.0019);";
}
}
diff --git a/services/surfaceflinger/RenderEngine/ProgramCache.h b/services/surfaceflinger/RenderEngine/ProgramCache.h
index 1fa53d3..ff5cf0f 100644
--- a/services/surfaceflinger/RenderEngine/ProgramCache.h
+++ b/services/surfaceflinger/RenderEngine/ProgramCache.h
@@ -57,9 +57,9 @@
OPACITY_TRANSLUCENT = 0x00000000,
OPACITY_MASK = 0x00000002,
- PLANE_ALPHA_LT_ONE = 0x00000004,
- PLANE_ALPHA_EQ_ONE = 0x00000000,
- PLANE_ALPHA_MASK = 0x00000004,
+ ALPHA_LT_ONE = 0x00000004,
+ ALPHA_EQ_ONE = 0x00000000,
+ ALPHA_MASK = 0x00000004,
TEXTURE_OFF = 0x00000000,
TEXTURE_EXT = 0x00000008,
@@ -69,6 +69,10 @@
COLOR_MATRIX_OFF = 0x00000000,
COLOR_MATRIX_ON = 0x00000020,
COLOR_MATRIX_MASK = 0x00000020,
+
+ WIDE_GAMUT_OFF = 0x00000000,
+ WIDE_GAMUT_ON = 0x00000040,
+ WIDE_GAMUT_MASK = 0x00000040,
};
inline Key() : mKey(0) { }
@@ -91,16 +95,19 @@
inline bool isOpaque() const {
return (mKey & OPACITY_MASK) == OPACITY_OPAQUE;
}
- inline bool hasPlaneAlpha() const {
- return (mKey & PLANE_ALPHA_MASK) == PLANE_ALPHA_LT_ONE;
+ 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) {
- return (lhs.mKey < rhs.mKey) ? 1 : 0;
+ return (lhs.mKey < rhs.mKey) ? 1 : 0;
}
};
diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.cpp b/services/surfaceflinger/RenderEngine/RenderEngine.cpp
index ac2d8b2..56e9ac0 100644
--- a/services/surfaceflinger/RenderEngine/RenderEngine.cpp
+++ b/services/surfaceflinger/RenderEngine/RenderEngine.cpp
@@ -26,7 +26,7 @@
#include <vector>
#include <SurfaceFlinger.h>
-EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name);
+extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name);
// ---------------------------------------------------------------------------
namespace android {
@@ -64,7 +64,7 @@
"EGL_ANDROIDX_no_config_context") &&
!findExtension(eglQueryStringImplementationANDROID(display, EGL_EXTENSIONS),
"EGL_KHR_no_config_context")) {
- config = chooseEglConfig(display, hwcFormat);
+ config = chooseEglConfig(display, hwcFormat, /*logConfig*/ true);
}
EGLint renderableType = 0;
@@ -108,7 +108,7 @@
EGLConfig dummyConfig = config;
if (dummyConfig == EGL_NO_CONFIG) {
- dummyConfig = chooseEglConfig(display, hwcFormat);
+ dummyConfig = chooseEglConfig(display, hwcFormat, /*logConfig*/ true);
}
EGLint attribs[] = { EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE, EGL_NONE };
EGLSurface dummy = eglCreatePbufferSurface(display, dummyConfig, attribs);
@@ -406,7 +406,8 @@
return err;
}
-EGLConfig RenderEngine::chooseEglConfig(EGLDisplay display, int format) {
+EGLConfig RenderEngine::chooseEglConfig(EGLDisplay display, int format,
+ bool logConfig) {
status_t err;
EGLConfig config;
@@ -427,18 +428,20 @@
}
}
- // print some debugging info
- 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_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("EGLSurface: %d-%d-%d-%d, config=%p", r, g, b, a, config);
+ if (logConfig) {
+ // print some debugging info
+ 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_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("EGLSurface: %d-%d-%d-%d, config=%p", r, g, b, a, config);
+ }
return config;
}
diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.h b/services/surfaceflinger/RenderEngine/RenderEngine.h
index 56f5827..fa65979 100644
--- a/services/surfaceflinger/RenderEngine/RenderEngine.h
+++ b/services/surfaceflinger/RenderEngine/RenderEngine.h
@@ -25,6 +25,7 @@
#include <EGL/eglext.h>
#include <math/mat4.h>
#include <Transform.h>
+#include <gui/SurfaceControl.h>
#define EGL_NO_CONFIG ((EGLConfig)0)
@@ -64,7 +65,7 @@
};
static RenderEngine* create(EGLDisplay display, int hwcFormat, uint32_t featureFlags);
- static EGLConfig chooseEglConfig(EGLDisplay display, int format);
+ static EGLConfig chooseEglConfig(EGLDisplay display, int format, bool logConfig);
void primeCache() const;
@@ -98,16 +99,13 @@
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;
#ifdef USE_HWC2
- virtual void setupLayerBlending(bool premultipliedAlpha, bool opaque, float alpha) = 0;
- virtual void setupDimLayerBlending(float alpha) = 0;
virtual void setColorMode(android_color_mode mode) = 0;
virtual void setSourceDataSpace(android_dataspace source) = 0;
virtual void setWideColor(bool hasWideColor) = 0;
virtual bool usesWideColor() = 0;
-#else
- virtual void setupLayerBlending(bool premultipliedAlpha, bool opaque, int alpha) = 0;
- virtual void setupDimLayerBlending(int alpha) = 0;
#endif
virtual void setupLayerTexturing(const Texture& texture) = 0;
virtual void setupLayerBlackedOut() = 0;
diff --git a/services/surfaceflinger/StartBootAnimThread.cpp b/services/surfaceflinger/StartBootAnimThread.cpp
deleted file mode 100644
index c3f7296..0000000
--- a/services/surfaceflinger/StartBootAnimThread.cpp
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 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 <cutils/properties.h>
-#include "StartBootAnimThread.h"
-
-namespace android {
-
-StartBootAnimThread::StartBootAnimThread():
- Thread(false) {
-}
-
-status_t StartBootAnimThread::Start() {
- return run("SurfaceFlinger::StartBootAnimThread", PRIORITY_NORMAL);
-}
-
-bool StartBootAnimThread::threadLoop() {
- property_set("service.bootanim.exit", "0");
- property_set("ctl.start", "bootanim");
- // Exit immediately
- return false;
-}
-
-} // namespace android
diff --git a/services/surfaceflinger/StartPropertySetThread.cpp b/services/surfaceflinger/StartPropertySetThread.cpp
new file mode 100644
index 0000000..db82772
--- /dev/null
+++ b/services/surfaceflinger/StartPropertySetThread.cpp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 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 <cutils/properties.h>
+#include "StartPropertySetThread.h"
+
+namespace android {
+
+StartPropertySetThread::StartPropertySetThread(bool timestampPropertyValue):
+ Thread(false), mTimestampPropertyValue(timestampPropertyValue) {}
+
+status_t StartPropertySetThread::Start() {
+ return run("SurfaceFlinger::StartPropertySetThread", PRIORITY_NORMAL);
+}
+
+bool StartPropertySetThread::threadLoop() {
+ // Set property service.sf.present_timestamp, consumer need check its readiness
+ property_set(kTimestampProperty, mTimestampPropertyValue ? "1" : "0");
+ // Clear BootAnimation exit flag
+ property_set("service.bootanim.exit", "0");
+ // Start BootAnimation if not started
+ property_set("ctl.start", "bootanim");
+ // Exit immediately
+ return false;
+}
+
+} // namespace android
diff --git a/services/surfaceflinger/StartBootAnimThread.h b/services/surfaceflinger/StartPropertySetThread.h
similarity index 78%
rename from services/surfaceflinger/StartBootAnimThread.h
rename to services/surfaceflinger/StartPropertySetThread.h
index dba2bee..a64c21b 100644
--- a/services/surfaceflinger/StartBootAnimThread.h
+++ b/services/surfaceflinger/StartPropertySetThread.h
@@ -24,17 +24,21 @@
namespace android {
-class StartBootAnimThread : public Thread {
+class StartPropertySetThread : public Thread {
// Boot animation is triggered via calls to "property_set()" which can block
// if init's executing slow operation such as 'mount_all --late' (currently
// happening 1/10th with fsck) concurrently. Running in a separate thread
// allows to pursue the SurfaceFlinger's init process without blocking.
// see b/34499826.
+// Any property_set() will block during init stage so need to be offloaded
+// to this thread. see b/63844978.
public:
- StartBootAnimThread();
+ StartPropertySetThread(bool timestampPropertyValue);
status_t Start();
private:
virtual bool threadLoop();
+ static constexpr const char* kTimestampProperty = "service.sf.present_timestamp";
+ const bool mTimestampPropertyValue;
};
}
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index ee63ebc..d13b188 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -19,12 +19,14 @@
#include <stdint.h>
#include <sys/types.h>
+#include <algorithm>
#include <errno.h>
#include <math.h>
#include <mutex>
#include <dlfcn.h>
#include <inttypes.h>
#include <stdatomic.h>
+#include <optional>
#include <EGL/egl.h>
@@ -44,6 +46,7 @@
#include <gui/BufferQueue.h>
#include <gui/GuiConfig.h>
#include <gui/IDisplayEventConnection.h>
+#include <gui/LayerDebugInfo.h>
#include <gui/Surface.h>
#include <ui/GraphicBufferAllocator.h>
@@ -69,11 +72,13 @@
#include "EventControlThread.h"
#include "EventThread.h"
#include "Layer.h"
+#include "BufferLayer.h"
#include "LayerVector.h"
-#include "LayerDim.h"
+#include "ColorLayer.h"
#include "MonitoredProducer.h"
#include "SurfaceFlinger.h"
+#include "DisplayHardware/ComposerHal.h"
#include "DisplayHardware/FramebufferSurface.h"
#include "DisplayHardware/HWComposer.h"
#include "DisplayHardware/VirtualDisplaySurface.h"
@@ -86,6 +91,8 @@
#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
#include <configstore/Utils.h>
+#include <layerproto/LayerProtoParser.h>
+
#define DISPLAY_COUNT 1
/*
@@ -94,14 +101,28 @@
*/
#define DEBUG_SCREENSHOTS false
-EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name);
+extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name);
namespace android {
-
using namespace android::hardware::configstore;
using namespace android::hardware::configstore::V1_0;
+namespace {
+class ConditionalLock {
+public:
+ ConditionalLock(Mutex& mutex, bool lock) : mMutex(mutex), mLocked(lock) {
+ if (lock) {
+ mMutex.lock();
+ }
+ }
+ ~ConditionalLock() { if (mLocked) mMutex.unlock(); }
+private:
+ Mutex& mMutex;
+ bool mLocked;
+};
+} // namespace anonymous
+
// ---------------------------------------------------------------------------
const String16 sHardwareTest("android.permission.HARDWARE_TEST");
@@ -121,6 +142,21 @@
int64_t SurfaceFlinger::maxFrameBufferAcquiredBuffers;
bool SurfaceFlinger::hasWideColorDisplay;
+
+std::string getHwcServiceName() {
+ char value[PROPERTY_VALUE_MAX] = {};
+ property_get("debug.sf.hwc_service_name", value, "default");
+ ALOGI("Using HWComposer service: '%s'", value);
+ return std::string(value);
+}
+
+bool useTrebleTestingOverride() {
+ char value[PROPERTY_VALUE_MAX] = {};
+ property_get("debug.sf.treble_testing_override", value, "false");
+ ALOGI("Treble testing override: '%s'", value);
+ return std::string(value) == "true";
+}
+
SurfaceFlinger::SurfaceFlinger()
: BnSurfaceComposer(),
mTransactionFlags(0),
@@ -129,9 +165,7 @@
mLayersRemoved(false),
mLayersAdded(false),
mRepaintEverything(0),
- mHwc(nullptr),
- mRealHwc(nullptr),
- mVrHwc(nullptr),
+ mHwcServiceName(getHwcServiceName()),
mRenderEngine(nullptr),
mBootTime(systemTime()),
mBuiltinDisplays(),
@@ -158,7 +192,9 @@
mTotalTime(0),
mLastSwapTime(0),
mNumLayers(0),
- mVrFlingerRequestsDisplay(false)
+ mVrFlingerRequestsDisplay(false),
+ mMainThreadId(std::this_thread::get_id()),
+ mComposerSequenceId(0)
{
ALOGI("SurfaceFlinger is starting");
@@ -193,6 +229,8 @@
hasWideColorDisplay =
getBool<ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::hasWideColorDisplay>(false);
+ mPrimaryDispSync.init(hasSyncFramework, dispSyncPresentTimeOffset);
+
// debugging stuff...
char value[PROPERTY_VALUE_MAX];
@@ -224,6 +262,20 @@
property_get("ro.sf.disable_triple_buffer", value, "1");
mLayerTripleBufferingDisabled = atoi(value);
ALOGI_IF(mLayerTripleBufferingDisabled, "Disabling Triple Buffering");
+
+ // We should be reading 'persist.sys.sf.color_saturation' here
+ // but since /data may be encrypted, we need to wait until after vold
+ // comes online to attempt to read the property. The property is
+ // instead read after the boot animation
+
+ if (useTrebleTestingOverride()) {
+ // Without the override SurfaceFlinger cannot connect to HIDL
+ // services that are not listed in the manifests. Considered
+ // deriving the setting from the set service name, but it
+ // would be brittle if the name that's not 'default' is used
+ // for production purposes later on.
+ setenv("TREBLE_TESTING_OVERRIDE", "true", true);
+ }
}
void SurfaceFlinger::onFirstRef()
@@ -341,13 +393,12 @@
void SurfaceFlinger::bootFinished()
{
- if (mStartBootAnimThread->join() != NO_ERROR) {
- ALOGE("Join StartBootAnimThread failed!");
+ if (mStartPropertySetThread->join() != NO_ERROR) {
+ ALOGE("Join StartPropertySetThread failed!");
}
const nsecs_t now = systemTime();
const nsecs_t duration = now - mBootTime;
ALOGI("Boot is finished (%ld ms)", long(ns2ms(duration)) );
- mBootFinished = true;
// wait patiently for the window manager death
const String16 name("window");
@@ -368,6 +419,11 @@
const int LOGTAG_SF_STOP_BOOTANIM = 60110;
LOG_EVENT_LONG(LOGTAG_SF_STOP_BOOTANIM,
ns2ms(systemTime(SYSTEM_TIME_MONOTONIC)));
+
+ sp<LambdaMessage> readProperties = new LambdaMessage([&]() {
+ readPersistentProperties();
+ });
+ postMessageAsync(readProperties);
}
void SurfaceFlinger::deleteTextureAsync(uint32_t texture) {
@@ -515,7 +571,9 @@
virtual void onInjectSyncEvent(nsecs_t when) {
std::lock_guard<std::mutex> lock(mCallbackMutex);
- mCallback->onVSyncEvent(when);
+ if (mCallback) {
+ mCallback->onVSyncEvent(when);
+ }
}
virtual void setVSyncEnabled(bool) {}
@@ -526,75 +584,43 @@
sp<VSyncSource::Callback> mCallback;
};
+// Do not call property_set on main thread which will be blocked by init
+// Use StartPropertySetThread instead.
void SurfaceFlinger::init() {
ALOGI( "SurfaceFlinger's main thread ready to run. "
"Initializing graphics H/W...");
ALOGI("Phase offest NS: %" PRId64 "", vsyncPhaseOffsetNs);
- { // Autolock scope
- 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");
- mEventThread = new EventThread(vsyncSrc, *this, false);
- sp<VSyncSource> sfVsyncSrc = new DispSyncSource(&mPrimaryDispSync,
- sfVsyncPhaseOffsetNs, true, "sf");
- mSFEventThread = new EventThread(sfVsyncSrc, *this, true);
- mEventQueue.setEventThread(mSFEventThread);
-
- // set EventThread and SFEventThread to SCHED_FIFO to minimize jitter
- struct sched_param param = {0};
- param.sched_priority = 2;
- if (sched_setscheduler(mSFEventThread->getTid(), SCHED_FIFO, ¶m) != 0) {
- ALOGE("Couldn't set SCHED_FIFO for SFEventThread");
- }
- if (sched_setscheduler(mEventThread->getTid(), SCHED_FIFO, ¶m) != 0) {
- ALOGE("Couldn't set SCHED_FIFO for EventThread");
- }
-
- // Get a RenderEngine for the given display / config (can't fail)
- mRenderEngine = RenderEngine::create(mEGLDisplay,
- HAL_PIXEL_FORMAT_RGBA_8888,
- hasWideColorDisplay ? RenderEngine::WIDE_COLOR_SUPPORT : 0);
- }
-
- // Drop the state lock while we initialize the hardware composer. We drop
- // the lock because on creation, it will call back into SurfaceFlinger to
- // initialize the primary display.
- LOG_ALWAYS_FATAL_IF(mVrFlingerRequestsDisplay,
- "Starting with vr flinger active is not currently supported.");
- mRealHwc = new HWComposer(false);
- mHwc = mRealHwc;
- mHwc->setEventHandler(static_cast<HWComposer::EventHandler*>(this));
-
Mutex::Autolock _l(mStateLock);
- // Inform native graphics APIs whether the present timestamp is supported:
- if (getHwComposer().hasCapability(
- HWC2::Capability::PresentFenceIsNotReliable)) {
- property_set(kTimestampProperty, "0");
- } else {
- property_set(kTimestampProperty, "1");
+ // 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");
+ mEventThread = new EventThread(vsyncSrc, *this, false);
+ sp<VSyncSource> sfVsyncSrc = new DispSyncSource(&mPrimaryDispSync,
+ sfVsyncPhaseOffsetNs, true, "sf");
+ mSFEventThread = new EventThread(sfVsyncSrc, *this, true);
+ mEventQueue.setEventThread(mSFEventThread);
+
+ // set EventThread and SFEventThread to SCHED_FIFO to minimize jitter
+ struct sched_param param = {0};
+ param.sched_priority = 2;
+ if (sched_setscheduler(mSFEventThread->getTid(), SCHED_FIFO, ¶m) != 0) {
+ ALOGE("Couldn't set SCHED_FIFO for SFEventThread");
+ }
+ if (sched_setscheduler(mEventThread->getTid(), SCHED_FIFO, ¶m) != 0) {
+ ALOGE("Couldn't set SCHED_FIFO for EventThread");
}
- if (useVrFlinger) {
- auto vrFlingerRequestDisplayCallback = [this] (bool requestDisplay) {
- ALOGI("VR request display mode: requestDisplay=%d", requestDisplay);
- mVrFlingerRequestsDisplay = requestDisplay;
- signalTransaction();
- };
- mVrFlinger = dvr::VrFlinger::Create(mHwc->getComposer(),
- vrFlingerRequestDisplayCallback);
- if (!mVrFlinger) {
- ALOGE("Failed to start vrflinger");
- }
- }
+ // Get a RenderEngine for the given display / config (can't fail)
+ mRenderEngine = RenderEngine::create(mEGLDisplay,
+ HAL_PIXEL_FORMAT_RGBA_8888,
+ hasWideColorDisplay ? RenderEngine::WIDE_COLOR_SUPPORT : 0);
// retrieve the EGL context that was selected/created
mEGLContext = mRenderEngine->getEGLContext();
@@ -602,9 +628,32 @@
LOG_ALWAYS_FATAL_IF(mEGLContext == EGL_NO_CONTEXT,
"couldn't create EGLContext");
- // make the GLContext current so that we can create textures when creating
- // Layers (which may happens before we render something)
- getDefaultDisplayDeviceLocked()->makeCurrent(mEGLDisplay, mEGLContext);
+ LOG_ALWAYS_FATAL_IF(mVrFlingerRequestsDisplay,
+ "Starting with vr flinger active is not currently supported.");
+ mHwc.reset(new HWComposer(mHwcServiceName));
+ mHwc->registerCallback(this, mComposerSequenceId);
+
+ if (useVrFlinger) {
+ auto vrFlingerRequestDisplayCallback = [this] (bool requestDisplay) {
+ // This callback is called from the vr flinger dispatch thread. We
+ // need to call signalTransaction(), which requires holding
+ // mStateLock when we're not on the main thread. Acquiring
+ // mStateLock from the vr flinger dispatch thread might trigger a
+ // deadlock in surface flinger (see b/66916578), so post a message
+ // to be handled on the main thread instead.
+ sp<LambdaMessage> message = new LambdaMessage([=]() {
+ ALOGI("VR request display mode: requestDisplay=%d", requestDisplay);
+ mVrFlingerRequestsDisplay = requestDisplay;
+ signalTransaction();
+ });
+ postMessageAsync(message);
+ };
+ mVrFlinger = dvr::VrFlinger::Create(mHwc->getComposer(),
+ vrFlingerRequestDisplayCallback);
+ if (!mVrFlinger) {
+ ALOGE("Failed to start vrflinger");
+ }
+ }
mEventControlThread = new EventControlThread(this);
mEventControlThread->run("EventControl", PRIORITY_URGENT_DISPLAY);
@@ -617,21 +666,42 @@
mRenderEngine->primeCache();
- mStartBootAnimThread = new StartBootAnimThread();
- if (mStartBootAnimThread->Start() != NO_ERROR) {
- ALOGE("Run StartBootAnimThread failed!");
+ // Inform native graphics APIs whether the present timestamp is supported:
+ if (getHwComposer().hasCapability(
+ HWC2::Capability::PresentFenceIsNotReliable)) {
+ mStartPropertySetThread = new StartPropertySetThread(false);
+ } else {
+ mStartPropertySetThread = new StartPropertySetThread(true);
+ }
+
+ if (mStartPropertySetThread->Start() != NO_ERROR) {
+ ALOGE("Run StartPropertySetThread failed!");
}
ALOGV("Done initializing");
}
+void SurfaceFlinger::readPersistentProperties() {
+ char value[PROPERTY_VALUE_MAX];
+
+ property_get("persist.sys.sf.color_saturation", value, "1.0");
+ mSaturation = atof(value);
+ ALOGV("Saturation is set to %.2f", mSaturation);
+
+ property_get("persist.sys.sf.native_mode", value, "0");
+ mForceNativeColorMode = atoi(value) == 1;
+ if (mForceNativeColorMode) {
+ ALOGV("Forcing native color mode");
+ }
+}
+
void SurfaceFlinger::startBootAnim() {
// Start boot animation service by setting a property mailbox
// if property setting thread is already running, Start() will be just a NOP
- mStartBootAnimThread->Start();
+ mStartPropertySetThread->Start();
// Wait until property was set
- if (mStartBootAnimThread->join() != NO_ERROR) {
- ALOGE("Join StartBootAnimThread failed!");
+ if (mStartPropertySetThread->join() != NO_ERROR) {
+ ALOGE("Join StartPropertySetThread failed!");
}
}
@@ -669,6 +739,8 @@
FrameEvent::DEQUEUE_READY,
FrameEvent::RELEASE,
};
+ ConditionalLock _l(mStateLock,
+ std::this_thread::get_id() != mMainThreadId);
if (!getHwComposer().hasCapability(
HWC2::Capability::PresentFenceIsNotReliable)) {
outSupported->push_back(FrameEvent::DISPLAY_PRESENT);
@@ -716,6 +788,8 @@
configs->clear();
+ ConditionalLock _l(mStateLock,
+ std::this_thread::get_id() != mMainThreadId);
for (const auto& hwConfig : getHwComposer().getConfigs(type)) {
DisplayInfo info = DisplayInfo();
@@ -739,7 +813,7 @@
info.density = density;
// TODO: this needs to go away (currently needed only by webkit)
- sp<const DisplayDevice> hw(getDefaultDisplayDevice());
+ sp<const DisplayDevice> hw(getDefaultDisplayDeviceLocked());
info.orientation = hw->getOrientation();
} else {
// TODO: where should this value come from?
@@ -882,7 +956,12 @@
return type;
}
- std::vector<android_color_mode_t> modes = getHwComposer().getColorModes(type);
+ std::vector<android_color_mode_t> modes;
+ {
+ ConditionalLock _l(mStateLock,
+ std::this_thread::get_id() != mMainThreadId);
+ modes = getHwComposer().getColorModes(type);
+ }
outColorModes->clear();
std::copy(modes.cbegin(), modes.cend(), std::back_inserter(*outColorModes));
@@ -990,28 +1069,34 @@
}
status_t SurfaceFlinger::enableVSyncInjections(bool enable) {
- if (enable == mInjectVSyncs) {
- return NO_ERROR;
- }
+ sp<LambdaMessage> enableVSyncInjections = new LambdaMessage([&]() {
+ Mutex::Autolock _l(mStateLock);
- if (enable) {
- mInjectVSyncs = enable;
- ALOGV("VSync Injections enabled");
- if (mVSyncInjector.get() == nullptr) {
- mVSyncInjector = new InjectVSyncSource();
- mInjectorEventThread = new EventThread(mVSyncInjector, *this, false);
+ if (mInjectVSyncs == enable) {
+ return;
}
- mEventQueue.setEventThread(mInjectorEventThread);
- } else {
+
+ if (enable) {
+ ALOGV("VSync Injections enabled");
+ if (mVSyncInjector.get() == nullptr) {
+ mVSyncInjector = new InjectVSyncSource();
+ mInjectorEventThread = new EventThread(mVSyncInjector, *this, false);
+ }
+ mEventQueue.setEventThread(mInjectorEventThread);
+ } else {
+ ALOGV("VSync Injections disabled");
+ mEventQueue.setEventThread(mSFEventThread);
+ }
+
mInjectVSyncs = enable;
- ALOGV("VSync Injections disabled");
- mEventQueue.setEventThread(mSFEventThread);
- mVSyncInjector.clear();
- }
+ });
+ postMessageSync(enableVSyncInjections);
return NO_ERROR;
}
status_t SurfaceFlinger::injectVSync(nsecs_t when) {
+ Mutex::Autolock _l(mStateLock);
+
if (!mInjectVSyncs) {
ALOGE("VSync Injections not enabled");
return BAD_VALUE;
@@ -1023,10 +1108,42 @@
return NO_ERROR;
}
+status_t SurfaceFlinger::getLayerDebugInfo(std::vector<LayerDebugInfo>* outLayers) const {
+ IPCThreadState* ipc = IPCThreadState::self();
+ const int pid = ipc->getCallingPid();
+ const int uid = ipc->getCallingUid();
+ if ((uid != AID_SHELL) &&
+ !PermissionCache::checkPermission(sDump, pid, uid)) {
+ ALOGE("Layer debug info permission denied for pid=%d, uid=%d", pid, uid);
+ return PERMISSION_DENIED;
+ }
+
+ // Try to acquire a lock for 1s, fail gracefully
+ const status_t err = mStateLock.timedLock(s2ns(1));
+ const bool locked = (err == NO_ERROR);
+ if (!locked) {
+ ALOGE("LayerDebugInfo: SurfaceFlinger unresponsive (%s [%d]) - exit", strerror(-err), err);
+ return TIMED_OUT;
+ }
+
+ outLayers->clear();
+ mCurrentState.traverseInZOrder([&](Layer* layer) {
+ outLayers->push_back(layer->getLayerDebugInfo());
+ });
+
+ mStateLock.unlock();
+ return NO_ERROR;
+}
+
// ----------------------------------------------------------------------------
-sp<IDisplayEventConnection> SurfaceFlinger::createDisplayEventConnection() {
- return mEventThread->createEventConnection();
+sp<IDisplayEventConnection> SurfaceFlinger::createDisplayEventConnection(
+ ISurfaceComposer::VsyncSource vsyncSource) {
+ if (vsyncSource == eVsyncSourceSurfaceFlinger) {
+ return mSFEventThread->createEventConnection();
+ } else {
+ return mEventThread->createEventConnection();
+ }
}
// ----------------------------------------------------------------------------
@@ -1044,6 +1161,7 @@
}
void SurfaceFlinger::signalRefresh() {
+ mRefreshPending = true;
mEventQueue.refresh();
}
@@ -1127,11 +1245,16 @@
sLastResyncAttempted = now;
}
-void SurfaceFlinger::onVSyncReceived(HWComposer* composer, int32_t type,
- nsecs_t timestamp) {
+void SurfaceFlinger::onVsyncReceived(int32_t sequenceId,
+ hwc2_display_t displayId, int64_t timestamp) {
Mutex::Autolock lock(mStateLock);
- // Ignore any vsyncs from the non-active hardware composer.
- if (composer != mHwc) {
+ // Ignore any vsyncs from a previous hardware composer.
+ if (sequenceId != mComposerSequenceId) {
+ return;
+ }
+
+ int32_t type;
+ if (!mHwc->onVsync(displayId, timestamp, &type)) {
return;
}
@@ -1139,7 +1262,7 @@
{ // Scope for the lock
Mutex::Autolock _l(mHWVsyncLock);
- if (type == 0 && mPrimaryHWVsyncEnabled) {
+ if (type == DisplayDevice::DISPLAY_PRIMARY && mPrimaryHWVsyncEnabled) {
needsHwVsync = mPrimaryDispSync.addResyncSample(timestamp);
}
}
@@ -1157,7 +1280,7 @@
}
void SurfaceFlinger::createDefaultDisplayDevice() {
- const int32_t type = DisplayDevice::DISPLAY_PRIMARY;
+ const DisplayDevice::DisplayType type = DisplayDevice::DISPLAY_PRIMARY;
wp<IBinder> token = mBuiltinDisplays[type];
// All non-virtual displays are currently considered secure.
@@ -1182,37 +1305,60 @@
break;
}
}
+ bool useWideColorMode = hasWideColorModes && hasWideColorDisplay && !mForceNativeColorMode;
sp<DisplayDevice> hw = new DisplayDevice(this, DisplayDevice::DISPLAY_PRIMARY, type, isSecure,
token, fbs, producer, mRenderEngine->getEGLConfig(),
- hasWideColorModes && hasWideColorDisplay);
+ useWideColorMode);
mDisplays.add(token, hw);
android_color_mode defaultColorMode = HAL_COLOR_MODE_NATIVE;
- if (hasWideColorModes && hasWideColorDisplay) {
+ if (useWideColorMode) {
defaultColorMode = HAL_COLOR_MODE_SRGB;
}
setActiveColorModeInternal(hw, defaultColorMode);
+ hw->setCompositionDataSpace(HAL_DATASPACE_UNKNOWN);
+
+ // Add the primary display token to mDrawingState so we don't try to
+ // recreate the DisplayDevice for the primary display.
+ mDrawingState.displays.add(token, DisplayDeviceState(type, true));
+
+ // make the GLContext current so that we can create textures when creating
+ // Layers (which may happens before we render something)
+ hw->makeCurrent(mEGLDisplay, mEGLContext);
}
-void SurfaceFlinger::onHotplugReceived(HWComposer* composer, int32_t disp, bool connected) {
- ALOGV("onHotplugReceived(%d, %s)", disp, connected ? "true" : "false");
+void SurfaceFlinger::onHotplugReceived(int32_t sequenceId,
+ hwc2_display_t display, HWC2::Connection connection,
+ bool primaryDisplay) {
+ ALOGV("onHotplugReceived(%d, %" PRIu64 ", %s, %s)",
+ sequenceId, display,
+ connection == HWC2::Connection::Connected ?
+ "connected" : "disconnected",
+ primaryDisplay ? "primary" : "external");
- if (composer->isUsingVrComposer()) {
- // We handle initializing the primary display device for the VR
- // window manager hwc explicitly at the time of transition.
- if (disp != DisplayDevice::DISPLAY_PRIMARY) {
- ALOGE("External displays are not supported by the vr hardware composer.");
+ // Only lock if we're not on the main thread. This function is normally
+ // called on a hwbinder thread, but for the primary display it's called on
+ // the main thread with the state lock already held, so don't attempt to
+ // acquire it here.
+ ConditionalLock lock(mStateLock,
+ std::this_thread::get_id() != mMainThreadId);
+
+ if (primaryDisplay) {
+ mHwc->onHotplug(display, connection);
+ if (!mBuiltinDisplays[DisplayDevice::DISPLAY_PRIMARY].get()) {
+ createBuiltinDisplayLocked(DisplayDevice::DISPLAY_PRIMARY);
}
- return;
- }
-
- if (disp == DisplayDevice::DISPLAY_PRIMARY) {
- Mutex::Autolock lock(mStateLock);
- createBuiltinDisplayLocked(DisplayDevice::DISPLAY_PRIMARY);
createDefaultDisplayDevice();
} else {
+ if (sequenceId != mComposerSequenceId) {
+ return;
+ }
+ if (mHwc->isUsingVrComposer()) {
+ ALOGE("External displays are not supported by the vr hardware composer.");
+ return;
+ }
+ mHwc->onHotplug(display, connection);
auto type = DisplayDevice::DISPLAY_EXTERNAL;
- Mutex::Autolock _l(mStateLock);
- if (connected) {
+ if (connection == HWC2::Connection::Connected) {
createBuiltinDisplayLocked(type);
} else {
mCurrentState.displays.removeItem(mBuiltinDisplays[type]);
@@ -1224,49 +1370,31 @@
}
}
-void SurfaceFlinger::onInvalidateReceived(HWComposer* composer) {
+void SurfaceFlinger::onRefreshReceived(int sequenceId,
+ hwc2_display_t /*display*/) {
Mutex::Autolock lock(mStateLock);
- if (composer == mHwc) {
- repaintEverything();
- } else {
- // This isn't from our current hardware composer. If it's a callback
- // from the real composer, forward the refresh request to vr
- // flinger. Otherwise ignore it.
- if (!composer->isUsingVrComposer()) {
- mVrFlinger->OnHardwareComposerRefresh();
- }
+ if (sequenceId != mComposerSequenceId) {
+ return;
}
+ repaintEverythingLocked();
}
void SurfaceFlinger::setVsyncEnabled(int disp, int enabled) {
ATRACE_CALL();
+ Mutex::Autolock lock(mStateLock);
getHwComposer().setVsyncEnabled(disp,
enabled ? HWC2::Vsync::Enable : HWC2::Vsync::Disable);
}
-void SurfaceFlinger::clearHwcLayers(const LayerVector& layers) {
- for (size_t i = 0; i < layers.size(); ++i) {
- layers[i]->clearHwcLayers();
- }
-}
-
// Note: it is assumed the caller holds |mStateLock| when this is called
-void SurfaceFlinger::resetHwcLocked() {
+void SurfaceFlinger::resetDisplayState() {
disableHardwareVsync(true);
- clearHwcLayers(mDrawingState.layersSortedByZ);
- clearHwcLayers(mCurrentState.layersSortedByZ);
// Clear the drawing state so that the logic inside of
// handleTransactionLocked will fire. It will determine the delta between
// mCurrentState and mDrawingState and re-apply all changes when we make the
// transition.
mDrawingState.displays.clear();
- // Release virtual display hwcId during vr mode transition.
- for (size_t displayId = 0; displayId < mDisplays.size(); ++displayId) {
- const sp<DisplayDevice>& displayDevice = mDisplays[displayId];
- if (displayDevice->getDisplayType() == DisplayDevice::DISPLAY_VIRTUAL) {
- displayDevice->disconnect(getHwComposer());
- }
- }
+ eglMakeCurrent(mEGLDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
mDisplays.clear();
}
@@ -1278,46 +1406,53 @@
return;
}
- if (vrFlingerRequestsDisplay && !mVrHwc) {
- // Construct new HWComposer without holding any locks.
- mVrHwc = new HWComposer(true);
-
- // Set up the event handlers. This step is neccessary to initialize the internal state of
- // the hardware composer object properly. Our callbacks are designed such that if they are
- // triggered between now and the point where the display is properly re-initialized, they
- // will not have any effect, so this is safe to do here, before the lock is aquired.
- mVrHwc->setEventHandler(static_cast<HWComposer::EventHandler*>(this));
- ALOGV("Vr HWC created");
+ if (vrFlingerRequestsDisplay && !mHwc->getComposer()->isRemote()) {
+ ALOGE("Vr flinger is only supported for remote hardware composer"
+ " service connections. Ignoring request to transition to vr"
+ " flinger.");
+ mVrFlingerRequestsDisplay = false;
+ return;
}
Mutex::Autolock _l(mStateLock);
- if (vrFlingerRequestsDisplay) {
- resetHwcLocked();
+ int currentDisplayPowerMode = getDisplayDeviceLocked(
+ mBuiltinDisplays[DisplayDevice::DISPLAY_PRIMARY])->getPowerMode();
- mHwc = mVrHwc;
- mVrFlinger->GrantDisplayOwnership();
-
- } else {
+ if (!vrFlingerRequestsDisplay) {
mVrFlinger->SeizeDisplayOwnership();
+ }
- resetHwcLocked();
+ resetDisplayState();
+ mHwc.reset(); // Delete the current instance before creating the new one
+ mHwc.reset(new HWComposer(
+ vrFlingerRequestsDisplay ? "vr" : mHwcServiceName));
+ mHwc->registerCallback(this, ++mComposerSequenceId);
- mHwc = mRealHwc;
+ LOG_ALWAYS_FATAL_IF(!mHwc->getComposer()->isRemote(),
+ "Switched to non-remote hardware composer");
+
+ if (vrFlingerRequestsDisplay) {
+ mVrFlinger->GrantDisplayOwnership();
+ } else {
enableHardwareVsync();
}
mVisibleRegionsDirty = true;
invalidateHwcGeometry();
- // Explicitly re-initialize the primary display. This is because some other
- // parts of this class rely on the primary display always being available.
- createDefaultDisplayDevice();
+ // Re-enable default display.
+ sp<DisplayDevice> hw(getDisplayDeviceLocked(
+ mBuiltinDisplays[DisplayDevice::DISPLAY_PRIMARY]));
+ setPowerModeInternal(hw, currentDisplayPowerMode, /*stateLockHeld*/ true);
// Reset the timing values to account for the period of the swapped in HWC
const auto& activeConfig = mHwc->getActiveConfig(HWC_DISPLAY_PRIMARY);
const nsecs_t period = activeConfig->getVsyncPeriod();
mAnimFrameTracker.setDisplayRefreshPeriod(period);
+
+ // Use phase of 0 since phase is not known.
+ // Use latency of 0, which will snap to the ideal latency.
setCompositorTimingSnapped(0, period, 0);
android_atomic_or(1, &mRepaintEverything);
@@ -1334,7 +1469,6 @@
Fence::SIGNAL_TIME_PENDING);
ATRACE_INT("FrameMissed", static_cast<int>(frameMissed));
if (mPropagateBackpressure && frameMissed) {
- ALOGD("Backpressure trigger, skipping transaction & refresh!");
signalLayerUpdate();
break;
}
@@ -1379,12 +1513,15 @@
void SurfaceFlinger::handleMessageRefresh() {
ATRACE_CALL();
+ mRefreshPending = false;
+
nsecs_t refreshStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
preComposition(refreshStartTime);
rebuildLayerStacks();
setUpHWComposer();
doDebugFlashRegions();
+ doTracing("handleRefresh");
doComposition();
postComposition(refreshStartTime);
@@ -1444,6 +1581,14 @@
}
}
+void SurfaceFlinger::doTracing(const char* where) {
+ ATRACE_CALL();
+ ATRACE_NAME(where);
+ if (CC_UNLIKELY(mTracing.isEnabled())) {
+ mTracing.traceLayers(where, dumpProtoInfo());
+ }
+}
+
void SurfaceFlinger::preComposition(nsecs_t refreshStartTime)
{
ATRACE_CALL();
@@ -1534,6 +1679,7 @@
// |mStateLock| not needed as we are on the main thread
const sp<const DisplayDevice> hw(getDefaultDisplayDeviceLocked());
+ mGlCompositionDoneTimeline.updateSignalTimes();
std::shared_ptr<FenceTime> glCompositionDoneFenceTime;
if (mHwc->hasClientComposition(HWC_DISPLAY_PRIMARY)) {
glCompositionDoneFenceTime =
@@ -1542,12 +1688,11 @@
} else {
glCompositionDoneFenceTime = FenceTime::NO_FENCE;
}
- mGlCompositionDoneTimeline.updateSignalTimes();
+ mDisplayTimeline.updateSignalTimes();
sp<Fence> presentFence = mHwc->getPresentFence(HWC_DISPLAY_PRIMARY);
auto presentFenceTime = std::make_shared<FenceTime>(presentFence);
mDisplayTimeline.push(presentFenceTime);
- mDisplayTimeline.updateSignalTimes();
nsecs_t vsyncPhase = mPrimaryDispSync.computeNextRefresh(0);
nsecs_t vsyncInterval = mPrimaryDispSync.getPeriod();
@@ -1572,8 +1717,8 @@
}
});
- if (presentFence->isValid()) {
- if (mPrimaryDispSync.addPresentFence(presentFence)) {
+ if (presentFenceTime->isValid()) {
+ if (mPrimaryDispSync.addPresentFence(presentFenceTime)) {
enableHardwareVsync();
} else {
disableHardwareVsync(false);
@@ -1628,7 +1773,7 @@
// rebuild the visible layer list per screen
if (CC_UNLIKELY(mVisibleRegionsDirty)) {
- ATRACE_CALL();
+ ATRACE_NAME("rebuildLayerStacks VR Dirty");
mVisibleRegionsDirty = false;
invalidateHwcGeometry();
@@ -1640,12 +1785,11 @@
const Transform& tr(displayDevice->getTransform());
const Rect bounds(displayDevice->getBounds());
if (displayDevice->isDisplayOn()) {
- computeVisibleRegions(
- displayDevice->getLayerStack(), dirtyRegion,
- opaqueRegion);
+ computeVisibleRegions(displayDevice, dirtyRegion, opaqueRegion);
mDrawingState.traverseInZOrder([&](Layer* layer) {
- if (layer->getLayerStack() == displayDevice->getLayerStack()) {
+ if (layer->belongsToDisplay(displayDevice->getLayerStack(),
+ displayDevice->isPrimary())) {
Region drawRegion(tr.transform(
layer->visibleNonTransparentRegion));
drawRegion.andSelf(bounds);
@@ -1654,15 +1798,14 @@
} else {
// Clear out the HWC layer if this layer was
// previously visible, but no longer is
- layer->setHwcLayer(displayDevice->getHwcDisplayId(),
- nullptr);
+ layer->destroyHwcLayer(
+ displayDevice->getHwcDisplayId());
}
} else {
// WM changes displayDevice->layerStack upon sleep/awake.
// Here we make sure we delete the HWC layers even if
// WM changed their layer stack.
- layer->setHwcLayer(displayDevice->getHwcDisplayId(),
- nullptr);
+ layer->destroyHwcLayer(displayDevice->getHwcDisplayId());
}
});
}
@@ -1675,9 +1818,29 @@
}
}
+mat4 SurfaceFlinger::computeSaturationMatrix() const {
+ if (mSaturation == 1.0f) {
+ return mat4();
+ }
+
+ // Rec.709 luma coefficients
+ float3 luminance{0.213f, 0.715f, 0.072f};
+ luminance *= 1.0f - mSaturation;
+ return mat4(
+ vec4{luminance.r + mSaturation, luminance.r, luminance.r, 0.0f},
+ vec4{luminance.g, luminance.g + mSaturation, luminance.g, 0.0f},
+ vec4{luminance.b, luminance.b, luminance.b + mSaturation, 0.0f},
+ vec4{0.0f, 0.0f, 0.0f, 1.0f}
+ );
+}
+
// pickColorMode translates a given dataspace into the best available color mode.
// Currently only support sRGB and Display-P3.
-android_color_mode SurfaceFlinger::pickColorMode(android_dataspace dataSpace) {
+android_color_mode SurfaceFlinger::pickColorMode(android_dataspace dataSpace) const {
+ if (mForceNativeColorMode) {
+ return HAL_COLOR_MODE_NATIVE;
+ }
+
switch (dataSpace) {
// treat Unknown as regular SRGB buffer, since that's what the rest of the
// system expects.
@@ -1700,11 +1863,19 @@
}
}
-android_dataspace SurfaceFlinger::bestTargetDataSpace(android_dataspace a, android_dataspace b) {
+android_dataspace SurfaceFlinger::bestTargetDataSpace(
+ android_dataspace a, android_dataspace b) const {
// Only support sRGB and Display-P3 right now.
if (a == HAL_DATASPACE_DISPLAY_P3 || b == HAL_DATASPACE_DISPLAY_P3) {
return HAL_DATASPACE_DISPLAY_P3;
}
+ if (a == HAL_DATASPACE_V0_SCRGB_LINEAR || b == HAL_DATASPACE_V0_SCRGB_LINEAR) {
+ return HAL_DATASPACE_DISPLAY_P3;
+ }
+ if (a == HAL_DATASPACE_V0_SCRGB || b == HAL_DATASPACE_V0_SCRGB) {
+ return HAL_DATASPACE_DISPLAY_P3;
+ }
+
return HAL_DATASPACE_V0_SRGB;
}
@@ -1753,10 +1924,7 @@
for (size_t i = 0; i < currentLayers.size(); i++) {
const auto& layer = currentLayers[i];
if (!layer->hasHwcLayer(hwcId)) {
- auto hwcLayer = mHwc->createLayer(hwcId);
- if (hwcLayer) {
- layer->setHwcLayer(hwcId, std::move(hwcLayer));
- } else {
+ if (!layer->createHwcLayer(mHwc.get(), hwcId)) {
layer->forceClientComposition(hwcId);
continue;
}
@@ -1772,7 +1940,7 @@
}
- mat4 colorMatrix = mColorMatrix * mDaltonizer();
+ mat4 colorMatrix = mColorMatrix * computeSaturationMatrix() * mDaltonizer();
// Set the per-frame data
for (size_t displayId = 0; displayId < mDisplays.size(); ++displayId) {
@@ -2037,7 +2205,7 @@
if (state.surface != NULL) {
// Allow VR composer to use virtual displays.
- if (mUseHwcVirtualDisplays || mHwc == mVrHwc) {
+ if (mUseHwcVirtualDisplays || mHwc->isUsingVrComposer()) {
int width = 0;
int status = state.surface->query(
NATIVE_WINDOW_WIDTH, &width);
@@ -2138,9 +2306,9 @@
disp.clear();
for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
sp<const DisplayDevice> hw(mDisplays[dpy]);
- if (hw->getLayerStack() == currentlayerStack) {
+ if (layer->belongsToDisplay(hw->getLayerStack(), hw->isPrimary())) {
if (disp == NULL) {
- disp = hw;
+ disp = std::move(hw);
} else {
disp = NULL;
break;
@@ -2187,7 +2355,7 @@
// TODO: we could cache the transformed region
Region visibleReg;
visibleReg.set(layer->computeScreenBounds());
- invalidateLayerStack(layer->getLayerStack(), visibleReg);
+ invalidateLayerStack(layer, visibleReg);
}
});
}
@@ -2236,7 +2404,7 @@
mTransactionCV.broadcast();
}
-void SurfaceFlinger::computeVisibleRegions(uint32_t layerStack,
+void SurfaceFlinger::computeVisibleRegions(const sp<const DisplayDevice>& displayDevice,
Region& outDirtyRegion, Region& outOpaqueRegion)
{
ATRACE_CALL();
@@ -2253,7 +2421,7 @@
const Layer::State& s(layer->getDrawingState());
// only consider the layers on the given layer stack
- if (layer->getLayerStack() != layerStack)
+ if (!layer->belongsToDisplay(displayDevice->getLayerStack(), displayDevice->isPrimary()))
return;
/*
@@ -2307,7 +2475,7 @@
// compute the opaque region
const int32_t layerOrientation = tr.getOrientation();
- if (s.alpha == 1.0f && !translucent &&
+ if (layer->getAlpha() == 1.0f && !translucent &&
((layerOrientation & Transform::ROT_INVALID) == false)) {
// the opaque region is the layer's footprint
opaqueRegion = visibleRegion;
@@ -2368,11 +2536,10 @@
outOpaqueRegion = aboveOpaqueLayers;
}
-void SurfaceFlinger::invalidateLayerStack(uint32_t layerStack,
- const Region& dirty) {
+void SurfaceFlinger::invalidateLayerStack(const sp<const Layer>& layer, const Region& dirty) {
for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
const sp<DisplayDevice>& hw(mDisplays[dpy]);
- if (hw->getLayerStack() == layerStack) {
+ if (layer->belongsToDisplay(hw->getLayerStack(), hw->isPrimary())) {
hw->dirtyRegion.orSelf(dirty);
}
}
@@ -2413,8 +2580,8 @@
for (auto& layer : mLayersWithQueuedFrames) {
const Region dirty(layer->latchBuffer(visibleRegions, latchTime));
layer->useSurfaceDamage();
- invalidateLayerStack(layer->getLayerStack(), dirty);
- if (!dirty.isEmpty()) {
+ invalidateLayerStack(layer, dirty);
+ if (layer->isBufferLatched()) {
newDataLatched = true;
}
}
@@ -2424,7 +2591,7 @@
// If we will need to wake up at some time in the future to deal with a
// queued frame that shouldn't be displayed during this vsync period, wake
// up during the next vsync period to check again.
- if (frameQueued && mLayersWithQueuedFrames.empty()) {
+ if (frameQueued && (mLayersWithQueuedFrames.empty() || !newDataLatched)) {
signalLayerUpdate();
}
@@ -2493,6 +2660,7 @@
{
ALOGV("doComposeSurfaces");
+ const DisplayRenderArea renderArea(displayDevice);
const auto hwcId = displayDevice->getHwcDisplayId();
mat4 oldColorMatrix;
@@ -2508,8 +2676,10 @@
ALOGV("hasClientComposition");
#ifdef USE_HWC2
- mRenderEngine->setColorMode(displayDevice->getActiveColorMode());
- mRenderEngine->setWideColor(displayDevice->getWideColorSupport());
+ mRenderEngine->setWideColor(
+ displayDevice->getWideColorSupport() && !mForceNativeColorMode);
+ mRenderEngine->setColorMode(mForceNativeColorMode ?
+ HAL_COLOR_MODE_NATIVE : displayDevice->getActiveColorMode());
#endif
if (!displayDevice->makeCurrent(mEGLDisplay, mEGLContext)) {
ALOGW("DisplayDevice::makeCurrent failed. Aborting surface composition for display %s",
@@ -2596,16 +2766,16 @@
case HWC2::Composition::SolidColor: {
const Layer::State& state(layer->getDrawingState());
if (layer->getClearClientTarget(hwcId) && !firstLayer &&
- layer->isOpaque(state) && (state.alpha == 1.0f)
+ layer->isOpaque(state) && (state.color.a == 1.0f)
&& hasClientComposition) {
// never clear the very first layer since we're
// guaranteed the FB is already cleared
- layer->clearWithOpenGL(displayDevice);
+ layer->clearWithOpenGL(renderArea);
}
break;
}
case HWC2::Composition::Client: {
- layer->draw(displayDevice, clip);
+ layer->draw(renderArea, clip);
break;
}
default:
@@ -2622,7 +2792,7 @@
const Region clip(dirty.intersect(
displayTransform.transform(layer->visibleRegion)));
if (!clip.isEmpty()) {
- layer->draw(displayDevice, clip);
+ layer->draw(renderArea, clip);
}
}
}
@@ -2659,8 +2829,20 @@
if (parent == nullptr) {
mCurrentState.layersSortedByZ.add(lbc);
} else {
+ bool found = false;
+ mCurrentState.traverseInZOrder([&](Layer* layer) {
+ if (layer == parent.get()) {
+ found = true;
+ }
+ });
+
+ if (!found) {
+ ALOGE("addClientLayer called with a removed parent");
+ return NAME_NOT_FOUND;
+ }
parent->addChild(lbc);
}
+
mGraphicBufferProducerList.add(IInterface::asBinder(gbc));
mLayersAdded = true;
mNumLayers++;
@@ -2672,12 +2854,33 @@
return NO_ERROR;
}
-status_t SurfaceFlinger::removeLayer(const sp<Layer>& layer) {
+status_t SurfaceFlinger::removeLayer(const sp<Layer>& layer, bool topLevelOnly) {
Mutex::Autolock _l(mStateLock);
+ if (layer->isPendingRemoval()) {
+ return NO_ERROR;
+ }
+
const auto& p = layer->getParent();
- const ssize_t index = (p != nullptr) ? p->removeChild(layer) :
- mCurrentState.layersSortedByZ.remove(layer);
+ ssize_t index;
+ if (p != nullptr) {
+ if (topLevelOnly) {
+ return NO_ERROR;
+ }
+
+ sp<Layer> ancestor = p;
+ while (ancestor->getParent() != nullptr) {
+ ancestor = ancestor->getParent();
+ }
+ if (mCurrentState.layersSortedByZ.indexOf(ancestor) < 0) {
+ ALOGE("removeLayer called with a layer whose parent has been removed");
+ return NAME_NOT_FOUND;
+ }
+
+ index = p->removeChild(layer);
+ } else {
+ index = mCurrentState.layersSortedByZ.remove(layer);
+ }
// As a matter of normal operation, the LayerCleaner will produce a second
// attempt to remove the surface. The Layer will be kept alive in mDrawingState
@@ -2693,9 +2896,10 @@
return NO_ERROR;
}
+ layer->onRemovedFromCurrentState();
mLayersPendingRemoval.add(layer);
mLayersRemoved = true;
- mNumLayers--;
+ mNumLayers -= 1 + layer->getChildrenCount();
setTransactionFlags(eTransactionNeeded);
return NO_ERROR;
}
@@ -2768,10 +2972,12 @@
}
}
- // If a synchronous transaction is explicitly requested without any changes,
- // force a transaction anyway. This can be used as a flush mechanism for
- // previous async transactions.
- if (transactionFlags == 0 && (flags & eSynchronous)) {
+ // If a synchronous transaction is explicitly requested without any changes, force a transaction
+ // anyway. This can be used as a flush mechanism for previous async transactions.
+ // Empty animation transaction can be used to simulate back-pressure, so also force a
+ // transaction for empty animation transactions.
+ if (transactionFlags == 0 &&
+ ((flags & eSynchronous) || (flags & eAnimation))) {
transactionFlags = eTransactionNeeded;
}
@@ -2858,119 +3064,139 @@
const sp<Client>& client,
const layer_state_t& s)
{
- uint32_t flags = 0;
sp<Layer> layer(client->getLayerUser(s.surface));
- if (layer != 0) {
- const uint32_t what = s.what;
- bool geometryAppliesWithResize =
- what & layer_state_t::eGeometryAppliesWithResize;
- if (what & layer_state_t::ePositionChanged) {
- if (layer->setPosition(s.x, s.y, !geometryAppliesWithResize)) {
- flags |= eTraversalNeeded;
- }
+ if (layer == nullptr) {
+ return 0;
+ }
+
+ if (layer->isPendingRemoval()) {
+ ALOGW("Attempting to set client state on removed layer: %s", layer->getName().string());
+ return 0;
+ }
+
+ uint32_t flags = 0;
+
+ const uint32_t what = s.what;
+ bool geometryAppliesWithResize =
+ what & layer_state_t::eGeometryAppliesWithResize;
+ if (what & layer_state_t::ePositionChanged) {
+ if (layer->setPosition(s.x, s.y, !geometryAppliesWithResize)) {
+ flags |= eTraversalNeeded;
}
- if (what & layer_state_t::eLayerChanged) {
- // NOTE: index needs to be calculated before we update the state
- const auto& p = layer->getParent();
- if (p == nullptr) {
- ssize_t idx = mCurrentState.layersSortedByZ.indexOf(layer);
- if (layer->setLayer(s.z) && idx >= 0) {
- mCurrentState.layersSortedByZ.removeAt(idx);
- mCurrentState.layersSortedByZ.add(layer);
- // we need traversal (state changed)
- // AND transaction (list changed)
- flags |= eTransactionNeeded|eTraversalNeeded;
- }
- } else {
- if (p->setChildLayer(layer, s.z)) {
- flags |= eTransactionNeeded|eTraversalNeeded;
- }
- }
- }
- if (what & layer_state_t::eRelativeLayerChanged) {
- if (layer->setRelativeLayer(s.relativeLayerHandle, s.z)) {
- flags |= eTransactionNeeded|eTraversalNeeded;
- }
- }
- if (what & layer_state_t::eSizeChanged) {
- if (layer->setSize(s.w, s.h)) {
- flags |= eTraversalNeeded;
- }
- }
- if (what & layer_state_t::eAlphaChanged) {
- if (layer->setAlpha(s.alpha))
- flags |= eTraversalNeeded;
- }
- if (what & layer_state_t::eMatrixChanged) {
- if (layer->setMatrix(s.matrix))
- flags |= eTraversalNeeded;
- }
- if (what & layer_state_t::eTransparentRegionChanged) {
- if (layer->setTransparentRegionHint(s.transparentRegion))
- flags |= eTraversalNeeded;
- }
- if (what & layer_state_t::eFlagsChanged) {
- if (layer->setFlags(s.flags, s.mask))
- flags |= eTraversalNeeded;
- }
- if (what & layer_state_t::eCropChanged) {
- if (layer->setCrop(s.crop, !geometryAppliesWithResize))
- flags |= eTraversalNeeded;
- }
- if (what & layer_state_t::eFinalCropChanged) {
- if (layer->setFinalCrop(s.finalCrop, !geometryAppliesWithResize))
- flags |= eTraversalNeeded;
- }
- if (what & layer_state_t::eLayerStackChanged) {
+ }
+ if (what & layer_state_t::eLayerChanged) {
+ // NOTE: index needs to be calculated before we update the state
+ const auto& p = layer->getParent();
+ if (p == nullptr) {
ssize_t idx = mCurrentState.layersSortedByZ.indexOf(layer);
- // We only allow setting layer stacks for top level layers,
- // everything else inherits layer stack from its parent.
- if (layer->hasParent()) {
- ALOGE("Attempt to set layer stack on layer with parent (%s) is invalid",
- layer->getName().string());
- } else if (idx < 0) {
- ALOGE("Attempt to set layer stack on layer without parent (%s) that "
- "that also does not appear in the top level layer list. Something"
- " has gone wrong.", layer->getName().string());
- } else if (layer->setLayerStack(s.layerStack)) {
+ if (layer->setLayer(s.z) && idx >= 0) {
mCurrentState.layersSortedByZ.removeAt(idx);
mCurrentState.layersSortedByZ.add(layer);
// we need traversal (state changed)
// AND transaction (list changed)
flags |= eTransactionNeeded|eTraversalNeeded;
}
- }
- if (what & layer_state_t::eDeferTransaction) {
- if (s.barrierHandle != nullptr) {
- layer->deferTransactionUntil(s.barrierHandle, s.frameNumber);
- } else if (s.barrierGbp != nullptr) {
- const sp<IGraphicBufferProducer>& gbp = s.barrierGbp;
- if (authenticateSurfaceTextureLocked(gbp)) {
- const auto& otherLayer =
- (static_cast<MonitoredProducer*>(gbp.get()))->getLayer();
- layer->deferTransactionUntil(otherLayer, s.frameNumber);
- } else {
- ALOGE("Attempt to defer transaction to to an"
- " unrecognized GraphicBufferProducer");
- }
- }
- // We don't trigger a traversal here because if no other state is
- // changed, we don't want this to cause any more work
- }
- if (what & layer_state_t::eReparentChildren) {
- if (layer->reparentChildren(s.reparentHandle)) {
+ } else {
+ if (p->setChildLayer(layer, s.z)) {
flags |= eTransactionNeeded|eTraversalNeeded;
}
}
- if (what & layer_state_t::eDetachChildren) {
- layer->detachChildren();
+ }
+ if (what & layer_state_t::eRelativeLayerChanged) {
+ ssize_t idx = mCurrentState.layersSortedByZ.indexOf(layer);
+ if (layer->setRelativeLayer(s.relativeLayerHandle, s.z)) {
+ mCurrentState.layersSortedByZ.removeAt(idx);
+ mCurrentState.layersSortedByZ.add(layer);
+ flags |= eTransactionNeeded|eTraversalNeeded;
}
- if (what & layer_state_t::eOverrideScalingModeChanged) {
- layer->setOverrideScalingMode(s.overrideScalingMode);
- // We don't trigger a traversal here because if no other state is
- // changed, we don't want this to cause any more work
+ }
+ if (what & layer_state_t::eSizeChanged) {
+ if (layer->setSize(s.w, s.h)) {
+ flags |= eTraversalNeeded;
}
}
+ if (what & layer_state_t::eAlphaChanged) {
+ if (layer->setAlpha(s.alpha))
+ flags |= eTraversalNeeded;
+ }
+ if (what & layer_state_t::eColorChanged) {
+ if (layer->setColor(s.color))
+ flags |= eTraversalNeeded;
+ }
+ if (what & layer_state_t::eMatrixChanged) {
+ if (layer->setMatrix(s.matrix))
+ flags |= eTraversalNeeded;
+ }
+ if (what & layer_state_t::eTransparentRegionChanged) {
+ if (layer->setTransparentRegionHint(s.transparentRegion))
+ flags |= eTraversalNeeded;
+ }
+ if (what & layer_state_t::eFlagsChanged) {
+ if (layer->setFlags(s.flags, s.mask))
+ flags |= eTraversalNeeded;
+ }
+ if (what & layer_state_t::eCropChanged) {
+ if (layer->setCrop(s.crop, !geometryAppliesWithResize))
+ flags |= eTraversalNeeded;
+ }
+ if (what & layer_state_t::eFinalCropChanged) {
+ if (layer->setFinalCrop(s.finalCrop, !geometryAppliesWithResize))
+ flags |= eTraversalNeeded;
+ }
+ if (what & layer_state_t::eLayerStackChanged) {
+ ssize_t idx = mCurrentState.layersSortedByZ.indexOf(layer);
+ // We only allow setting layer stacks for top level layers,
+ // everything else inherits layer stack from its parent.
+ if (layer->hasParent()) {
+ ALOGE("Attempt to set layer stack on layer with parent (%s) is invalid",
+ layer->getName().string());
+ } else if (idx < 0) {
+ ALOGE("Attempt to set layer stack on layer without parent (%s) that "
+ "that also does not appear in the top level layer list. Something"
+ " has gone wrong.", layer->getName().string());
+ } else if (layer->setLayerStack(s.layerStack)) {
+ mCurrentState.layersSortedByZ.removeAt(idx);
+ mCurrentState.layersSortedByZ.add(layer);
+ // we need traversal (state changed)
+ // AND transaction (list changed)
+ flags |= eTransactionNeeded|eTraversalNeeded;
+ }
+ }
+ if (what & layer_state_t::eDeferTransaction) {
+ if (s.barrierHandle != nullptr) {
+ layer->deferTransactionUntil(s.barrierHandle, s.frameNumber);
+ } else if (s.barrierGbp != nullptr) {
+ const sp<IGraphicBufferProducer>& gbp = s.barrierGbp;
+ if (authenticateSurfaceTextureLocked(gbp)) {
+ const auto& otherLayer =
+ (static_cast<MonitoredProducer*>(gbp.get()))->getLayer();
+ layer->deferTransactionUntil(otherLayer, s.frameNumber);
+ } else {
+ ALOGE("Attempt to defer transaction to to an"
+ " unrecognized GraphicBufferProducer");
+ }
+ }
+ // We don't trigger a traversal here because if no other state is
+ // changed, we don't want this to cause any more work
+ }
+ if (what & layer_state_t::eReparent) {
+ if (layer->reparent(s.parentHandleForChild)) {
+ flags |= eTransactionNeeded|eTraversalNeeded;
+ }
+ }
+ if (what & layer_state_t::eReparentChildren) {
+ if (layer->reparentChildren(s.reparentHandle)) {
+ flags |= eTransactionNeeded|eTraversalNeeded;
+ }
+ }
+ if (what & layer_state_t::eDetachChildren) {
+ layer->detachChildren();
+ }
+ if (what & layer_state_t::eOverrideScalingModeChanged) {
+ layer->setOverrideScalingMode(s.overrideScalingMode);
+ // We don't trigger a traversal here because if no other state is
+ // changed, we don't want this to cause any more work
+ }
return flags;
}
@@ -2995,14 +3221,15 @@
switch (flags & ISurfaceComposerClient::eFXSurfaceMask) {
case ISurfaceComposerClient::eFXSurfaceNormal:
- result = createNormalLayer(client,
+ result = createBufferLayer(client,
uniqueName, w, h, flags, format,
handle, gbp, &layer);
+
break;
- case ISurfaceComposerClient::eFXSurfaceDim:
- result = createDimLayer(client,
+ case ISurfaceComposerClient::eFXSurfaceColor:
+ result = createColorLayer(client,
uniqueName, w, h, flags,
- handle, gbp, &layer);
+ handle, &layer);
break;
default:
result = BAD_VALUE;
@@ -3013,6 +3240,13 @@
return result;
}
+ // window type is WINDOW_TYPE_DONT_SCREENSHOT from SurfaceControl.java
+ // TODO b/64227542
+ if (windowType == 441731) {
+ windowType = 2024; // TYPE_NAVIGATION_BAR_PANEL
+ layer->setPrimaryDisplayOnly();
+ }
+
layer->setInfo(windowType, ownerUid);
result = addClientLayer(client, *handle, *gbp, layer, *parent);
@@ -3049,7 +3283,7 @@
return uniqueName;
}
-status_t SurfaceFlinger::createNormalLayer(const sp<Client>& client,
+status_t SurfaceFlinger::createBufferLayer(const sp<Client>& client,
const String8& name, uint32_t w, uint32_t h, uint32_t flags, PixelFormat& format,
sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp, sp<Layer>* outLayer)
{
@@ -3064,24 +3298,24 @@
break;
}
- *outLayer = new Layer(this, client, name, w, h, flags);
- status_t err = (*outLayer)->setBuffers(w, h, format, flags);
+ sp<BufferLayer> layer = new BufferLayer(this, client, name, w, h, flags);
+ status_t err = layer->setBuffers(w, h, format, flags);
if (err == NO_ERROR) {
- *handle = (*outLayer)->getHandle();
- *gbp = (*outLayer)->getProducer();
+ *handle = layer->getHandle();
+ *gbp = layer->getProducer();
+ *outLayer = layer;
}
- ALOGE_IF(err, "createNormalLayer() failed (%s)", strerror(-err));
+ ALOGE_IF(err, "createBufferLayer() failed (%s)", strerror(-err));
return err;
}
-status_t SurfaceFlinger::createDimLayer(const sp<Client>& client,
+status_t SurfaceFlinger::createColorLayer(const sp<Client>& client,
const String8& name, uint32_t w, uint32_t h, uint32_t flags,
- sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp, sp<Layer>* outLayer)
+ sp<IBinder>* handle, sp<Layer>* outLayer)
{
- *outLayer = new LayerDim(this, client, name, w, h, flags);
+ *outLayer = new ColorLayer(this, client, name, w, h, flags);
*handle = (*outLayer)->getHandle();
- *gbp = (*outLayer)->getProducer();
return NO_ERROR;
}
@@ -3107,11 +3341,9 @@
if (l == nullptr) {
// The layer has already been removed, carry on
return NO_ERROR;
- } if (l->getParent() != nullptr) {
- // If we have a parent, then we can continue to live as long as it does.
- return NO_ERROR;
}
- return removeLayer(l);
+ // If we have a parent, then we can continue to live as long as it does.
+ return removeLayer(l, true);
}
// ---------------------------------------------------------------------------
@@ -3132,7 +3364,8 @@
d.height = 0;
displays.add(d);
setTransactionState(state, displays, 0);
- setPowerModeInternal(getDisplayDevice(d.token), HWC_POWER_MODE_NORMAL);
+ setPowerModeInternal(getDisplayDevice(d.token), HWC_POWER_MODE_NORMAL,
+ /*stateLockHeld*/ false);
const auto& activeConfig = mHwc->getActiveConfig(HWC_DISPLAY_PRIMARY);
const nsecs_t period = activeConfig->getVsyncPeriod();
@@ -3158,7 +3391,7 @@
}
void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& hw,
- int mode) {
+ int mode, bool stateLockHeld) {
ALOGD("Set power mode=%d, type=%d flinger=%p", mode, hw->getDisplayType(),
this);
int32_t type = hw->getDisplayType();
@@ -3175,7 +3408,7 @@
}
if (mInterceptor.isEnabled()) {
- Mutex::Autolock _l(mStateLock);
+ ConditionalLock lock(mStateLock, !stateLockHeld);
ssize_t idx = mCurrentState.displays.indexOfKey(hw->getDisplayToken());
if (idx < 0) {
ALOGW("Surface Interceptor SavePowerMode: invalid display token");
@@ -3196,7 +3429,7 @@
mVisibleRegionsDirty = true;
mHasPoweredOff = true;
- repaintEverything();
+ repaintEverythingLocked();
struct sched_param param = {0};
param.sched_priority = 1;
@@ -3263,7 +3496,8 @@
ALOGW("Attempt to set power mode = %d for virtual display",
mMode);
} else {
- mFlinger.setPowerModeInternal(hw, mMode);
+ mFlinger.setPowerModeInternal(
+ hw, mMode, /*stateLockHeld*/ false);
}
return true;
}
@@ -3274,13 +3508,13 @@
// ---------------------------------------------------------------------------
-status_t SurfaceFlinger::dump(int fd, const Vector<String16>& args)
-{
+status_t SurfaceFlinger::doDump(int fd, const Vector<String16>& args, bool asProto) {
String8 result;
IPCThreadState* ipc = IPCThreadState::self();
const int pid = ipc->getCallingPid();
const int uid = ipc->getCallingUid();
+
if ((uid != AID_SHELL) &&
!PermissionCache::checkPermission(sDump, pid, uid)) {
result.appendFormat("Permission Denial: "
@@ -3300,6 +3534,13 @@
bool dumpAll = true;
size_t index = 0;
size_t numArgs = args.size();
+
+ if (asProto) {
+ LayersProto layersProto = dumpProtoInfo();
+ result.append(layersProto.SerializeAsString().c_str(), layersProto.ByteSize());
+ dumpAll = false;
+ }
+
if (numArgs) {
if ((index < numArgs) &&
(args[index] == String16("--list"))) {
@@ -3520,6 +3761,7 @@
void SurfaceFlinger::dumpWideColorInfo(String8& result) const {
result.appendFormat("hasWideColorDisplay: %d\n", hasWideColorDisplay);
+ result.appendFormat("forceNativeColorMode: %d\n", mForceNativeColorMode);
// TODO: print out if wide-color mode is active or not
@@ -3543,6 +3785,16 @@
result.append("\n");
}
+LayersProto SurfaceFlinger::dumpProtoInfo() const {
+ LayersProto layersProto;
+ mCurrentState.traverseInZOrder([&](Layer* layer) {
+ LayerProto* layerProto = layersProto.add_layers();
+ layer->writeToProto(layerProto, LayerVector::StateSet::Current);
+ });
+
+ return layersProto;
+}
+
void SurfaceFlinger::dumpAllLocked(const Vector<String16>& args, size_t& index,
String8& result) const
{
@@ -3607,9 +3859,10 @@
colorizer.bold(result);
result.appendFormat("Visible layers (count = %zu)\n", mNumLayers);
colorizer.reset(result);
- mCurrentState.traverseInZOrder([&](Layer* layer) {
- layer->dump(result, colorizer);
- });
+
+ LayersProto layersProto = dumpProtoInfo();
+ auto layerTree = LayerProtoParser::generateLayerTree(layersProto);
+ result.append(LayerProtoParser::layersToString(layerTree).c_str());
/*
* Dump Display state
@@ -3709,6 +3962,15 @@
*/
const GraphicBufferAllocator& alloc(GraphicBufferAllocator::get());
alloc.dump(result);
+
+ /*
+ * Dump VrFlinger state if in use.
+ */
+ if (mVrFlingerRequestsDisplay && mVrFlinger) {
+ result.append("VrFlinger state:\n");
+ result.append(mVrFlinger->Dump().c_str());
+ result.append("\n");
+ }
}
const Vector< sp<Layer> >&
@@ -3756,6 +4018,8 @@
case GET_ANIMATION_FRAME_STATS:
case SET_POWER_MODE:
case GET_HDR_CAPABILITIES:
+ case ENABLE_VSYNC_INJECTIONS:
+ case INJECT_VSYNC:
{
// codes that require permission check
IPCThreadState* ipc = IPCThreadState::self();
@@ -3792,6 +4056,17 @@
}
break;
}
+ case CAPTURE_LAYERS: {
+ IPCThreadState* ipc = IPCThreadState::self();
+ const int pid = ipc->getCallingPid();
+ const int uid = ipc->getCallingUid();
+ if ((uid != AID_GRAPHICS) &&
+ !PermissionCache::checkPermission(sReadFramebuffer, pid, uid)) {
+ ALOGE("Permission Denial: can't read framebuffer pid=%d, uid=%d", pid, uid);
+ return PERMISSION_DENIED;
+ }
+ break;
+ }
}
return OK;
}
@@ -3807,10 +4082,11 @@
status_t err = BnSurfaceComposer::onTransact(code, data, reply, flags);
if (err == UNKNOWN_TRANSACTION || err == PERMISSION_DENIED) {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
- if (CC_UNLIKELY(!PermissionCache::checkCallingPermission(sHardwareTest))) {
- IPCThreadState* ipc = IPCThreadState::self();
+ IPCThreadState* ipc = IPCThreadState::self();
+ const int uid = ipc->getCallingUid();
+ if (CC_UNLIKELY(uid != AID_SYSTEM
+ && !PermissionCache::checkCallingPermission(sHardwareTest))) {
const int pid = ipc->getCallingPid();
- const int uid = ipc->getCallingUid();
ALOGE("Permission Denial: "
"can't access SurfaceFlinger pid=%d, uid=%d", pid, uid);
return PERMISSION_DENIED;
@@ -3831,6 +4107,7 @@
return NO_ERROR;
}
case 1005:{ // force transaction
+ Mutex::Autolock _l(mStateLock);
setTransactionFlags(
eTransactionNeeded|
eDisplayTransactionNeeded|
@@ -3895,9 +4172,7 @@
// apply a color matrix
n = data.readInt32();
if (n) {
- // color matrix is sent as mat3 matrix followed by vec3
- // offset, then packed into a mat4 where the last row is
- // the offset and extra values are 0
+ // color matrix is sent as a column-major mat4 matrix
for (size_t i = 0 ; i < 4; i++) {
for (size_t j = 0; j < 4; j++) {
mColorMatrix[i][j] = data.readFloat();
@@ -3906,6 +4181,14 @@
} else {
mColorMatrix = mat4();
}
+
+ // Check that supplied matrix's last row is {0,0,0,1} so we can avoid
+ // the division by w in the fragment shader
+ float4 lastRow(transpose(mColorMatrix)[3]);
+ if (any(greaterThan(abs(lastRow - float4{0, 0, 0, 1}), float4{1e-4f}))) {
+ ALOGE("The color transform's last row must be (0, 0, 0, 1)");
+ }
+
invalidateHwcGeometry();
repaintEverything();
return NO_ERROR;
@@ -3949,495 +4232,461 @@
mUseHwcVirtualDisplays = !n;
return NO_ERROR;
}
+ case 1022: { // Set saturation boost
+ mSaturation = std::max(0.0f, std::min(data.readFloat(), 2.0f));
+
+ invalidateHwcGeometry();
+ repaintEverything();
+ return NO_ERROR;
+ }
+ case 1023: { // Set native mode
+ mForceNativeColorMode = data.readInt32() == 1;
+
+ invalidateHwcGeometry();
+ repaintEverything();
+ return NO_ERROR;
+ }
+ case 1024: { // Is wide color gamut rendering/color management supported?
+ reply->writeBool(hasWideColorDisplay);
+ return NO_ERROR;
+ }
+ case 1025: { // tracing
+ n = data.readInt32();
+ if (n) {
+ ALOGV("LayerTracing enabled");
+ mTracing.enable();
+ doTracing("tracing.enable");
+ reply->writeInt32(NO_ERROR);
+ } else {
+ ALOGV("LayerTracing disabled");
+ status_t err = mTracing.disable();
+ reply->writeInt32(err);
+ }
+ return NO_ERROR;
+ }
}
}
return err;
}
-void SurfaceFlinger::repaintEverything() {
+void SurfaceFlinger::repaintEverythingLocked() {
android_atomic_or(1, &mRepaintEverything);
signalTransaction();
}
-// ---------------------------------------------------------------------------
-// Capture screen into an IGraphiBufferProducer
-// ---------------------------------------------------------------------------
+void SurfaceFlinger::repaintEverything() {
+ ConditionalLock _l(mStateLock,
+ std::this_thread::get_id() != mMainThreadId);
+ repaintEverythingLocked();
+}
-/* The code below is here to handle b/8734824
- *
- * We create a IGraphicBufferProducer wrapper that forwards all calls
- * from the surfaceflinger thread to the calling binder thread, where they
- * are executed. This allows the calling thread in the calling process to be
- * reused and not depend on having "enough" binder threads to handle the
- * requests.
- */
-class GraphicProducerWrapper : public BBinder, public MessageHandler {
- /* Parts of GraphicProducerWrapper are run on two different threads,
- * communicating by sending messages via Looper but also by shared member
- * data. Coherence maintenance is subtle and in places implicit (ugh).
- *
- * Don't rely on Looper's sendMessage/handleMessage providing
- * release/acquire semantics for any data not actually in the Message.
- * Data going from surfaceflinger to binder threads needs to be
- * synchronized explicitly.
- *
- * Barrier open/wait do provide release/acquire semantics. This provides
- * implicit synchronization for data coming back from binder to
- * surfaceflinger threads.
- */
-
- sp<IGraphicBufferProducer> impl;
- sp<Looper> looper;
- status_t result;
- bool exitPending;
- bool exitRequested;
- Barrier barrier;
- uint32_t code;
- Parcel const* data;
- Parcel* reply;
-
- enum {
- MSG_API_CALL,
- MSG_EXIT
- };
-
- /*
- * Called on surfaceflinger thread. This is called by our "fake"
- * BpGraphicBufferProducer. We package the data and reply Parcel and
- * forward them to the binder thread.
- */
- virtual status_t transact(uint32_t code,
- const Parcel& data, Parcel* reply, uint32_t /* flags */) {
- this->code = code;
- this->data = &data;
- this->reply = reply;
- if (exitPending) {
- // if we've exited, we run the message synchronously right here.
- // note (JH): as far as I can tell from looking at the code, this
- // never actually happens. if it does, i'm not sure if it happens
- // on the surfaceflinger or binder thread.
- handleMessage(Message(MSG_API_CALL));
- } else {
- barrier.close();
- // Prevent stores to this->{code, data, reply} from being
- // reordered later than the construction of Message.
- atomic_thread_fence(memory_order_release);
- looper->sendMessage(this, Message(MSG_API_CALL));
- barrier.wait();
- }
- return result;
- }
-
- /*
- * here we run on the binder thread. All we've got to do is
- * call the real BpGraphicBufferProducer.
- */
- virtual void handleMessage(const Message& message) {
- int what = message.what;
- // Prevent reads below from happening before the read from Message
- atomic_thread_fence(memory_order_acquire);
- if (what == MSG_API_CALL) {
- result = IInterface::asBinder(impl)->transact(code, data[0], reply);
- barrier.open();
- } else if (what == MSG_EXIT) {
- exitRequested = true;
- }
- }
-
+// A simple RAII class to disconnect from an ANativeWindow* when it goes out of scope
+class WindowDisconnector {
public:
- explicit GraphicProducerWrapper(const sp<IGraphicBufferProducer>& impl)
- : impl(impl),
- looper(new Looper(true)),
- result(NO_ERROR),
- exitPending(false),
- exitRequested(false),
- code(0),
- data(NULL),
- reply(NULL)
- {}
-
- // Binder thread
- status_t waitForResponse() {
- do {
- looper->pollOnce(-1);
- } while (!exitRequested);
- return result;
+ WindowDisconnector(ANativeWindow* window, int api) : mWindow(window), mApi(api) {}
+ ~WindowDisconnector() {
+ native_window_api_disconnect(mWindow, mApi);
}
- // Client thread
- void exit(status_t result) {
- this->result = result;
- exitPending = true;
- // Ensure this->result is visible to the binder thread before it
- // handles the message.
- atomic_thread_fence(memory_order_release);
- looper->sendMessage(this, Message(MSG_EXIT));
- }
+private:
+ ANativeWindow* mWindow;
+ const int mApi;
};
+static status_t getWindowBuffer(ANativeWindow* window, uint32_t requestedWidth,
+ uint32_t requestedHeight, bool hasWideColorDisplay,
+ bool renderEngineUsesWideColor, ANativeWindowBuffer** outBuffer) {
+ const uint32_t usage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN |
+ GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE;
+
+ int err = 0;
+ err = native_window_set_buffers_dimensions(window, requestedWidth, requestedHeight);
+ err |= native_window_set_scaling_mode(window, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
+ err |= native_window_set_buffers_format(window, HAL_PIXEL_FORMAT_RGBA_8888);
+ err |= native_window_set_usage(window, usage);
+
+ if (hasWideColorDisplay) {
+ err |= native_window_set_buffers_data_space(window,
+ renderEngineUsesWideColor
+ ? HAL_DATASPACE_DISPLAY_P3
+ : HAL_DATASPACE_V0_SRGB);
+ }
+
+ if (err != NO_ERROR) {
+ return BAD_VALUE;
+ }
+
+ /* TODO: Once we have the sync framework everywhere this can use
+ * server-side waits on the fence that dequeueBuffer returns.
+ */
+ err = native_window_dequeue_buffer_and_wait(window, outBuffer);
+ if (err != NO_ERROR) {
+ return err;
+ }
+
+ return NO_ERROR;
+}
status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
- const sp<IGraphicBufferProducer>& producer,
- Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
- int32_t minLayerZ, int32_t maxLayerZ,
- bool useIdentityTransform, ISurfaceComposer::Rotation rotation) {
+ const sp<IGraphicBufferProducer>& producer, Rect sourceCrop,
+ uint32_t reqWidth, uint32_t reqHeight, int32_t minLayerZ,
+ int32_t maxLayerZ, bool useIdentityTransform,
+ ISurfaceComposer::Rotation rotation) {
+ ATRACE_CALL();
- if (CC_UNLIKELY(display == 0))
- return BAD_VALUE;
+ if (CC_UNLIKELY(display == 0)) return BAD_VALUE;
+
+ const sp<const DisplayDevice> device(getDisplayDeviceLocked(display));
+ DisplayRenderArea renderArea(device, sourceCrop, reqHeight, reqWidth, rotation);
+
+ auto traverseLayers = std::bind(std::mem_fn(&SurfaceFlinger::traverseLayersInDisplay), this,
+ device, minLayerZ, maxLayerZ, std::placeholders::_1);
+ return captureScreenCommon(renderArea, traverseLayers, producer, useIdentityTransform);
+}
+
+status_t SurfaceFlinger::captureLayers(const sp<IBinder>& layerHandleBinder,
+ const sp<IGraphicBufferProducer>& producer,
+ ISurfaceComposer::Rotation rotation) {
+ 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) {}
+ 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
+ return *new Transform(mLayer->getTransform().inverse());
+ }
+ Rect getBounds() const override {
+ const Layer::State& layerState(mLayer->getDrawingState());
+ return Rect(layerState.active.w, layerState.active.h);
+ }
+ int getHeight() const override { return mLayer->getDrawingState().active.h; }
+ int getWidth() const override { return mLayer->getDrawingState().active.w; }
+ bool isSecure() const override { return false; }
+ bool needsFiltering() const override { return false; }
+
+ Rect getSourceCrop() const override { return getBounds(); }
+ bool getWideColorSupport() const override { return false; }
+ android_color_mode_t getActiveColorMode() const override { return HAL_COLOR_MODE_NATIVE; }
+
+ private:
+ const sp<Layer>& mLayer;
+ };
+
+ auto layerHandle = reinterpret_cast<Layer::Handle*>(layerHandleBinder.get());
+ auto parent = layerHandle->owner.promote();
+
+ LayerRenderArea renderArea(parent, rotation);
+ auto traverseLayers = [parent](const LayerVector::Visitor& visitor) {
+ parent->traverseChildrenInZOrder(LayerVector::StateSet::Drawing, [&](Layer* layer) {
+ if (!layer->isVisible()) {
+ return;
+ }
+ visitor(layer);
+ });
+ };
+ return captureScreenCommon(renderArea, traverseLayers, producer, false);
+}
+
+status_t SurfaceFlinger::captureScreenCommon(RenderArea& renderArea,
+ TraverseLayersFunction traverseLayers,
+ const sp<IGraphicBufferProducer>& producer,
+ bool useIdentityTransform) {
+ ATRACE_CALL();
if (CC_UNLIKELY(producer == 0))
return BAD_VALUE;
+ renderArea.updateDimensions();
+
// if we have secure windows on this display, never allow the screen capture
// unless the producer interface is local (i.e.: we can take a screenshot for
// ourselves).
bool isLocalScreenshot = IInterface::asBinder(producer)->localBinder();
- // Convert to surfaceflinger's internal rotation type.
- Transform::orientation_flags rotationFlags;
- switch (rotation) {
- case ISurfaceComposer::eRotateNone:
- rotationFlags = Transform::ROT_0;
- break;
- case ISurfaceComposer::eRotate90:
- rotationFlags = Transform::ROT_90;
- break;
- case ISurfaceComposer::eRotate180:
- rotationFlags = Transform::ROT_180;
- break;
- case ISurfaceComposer::eRotate270:
- rotationFlags = Transform::ROT_270;
- break;
- default:
- rotationFlags = Transform::ROT_0;
- ALOGE("Invalid rotation passed to captureScreen(): %d\n", rotation);
- break;
- }
-
- class MessageCaptureScreen : public MessageBase {
- SurfaceFlinger* flinger;
- sp<IBinder> display;
- sp<IGraphicBufferProducer> producer;
- Rect sourceCrop;
- uint32_t reqWidth, reqHeight;
- uint32_t minLayerZ,maxLayerZ;
- bool useIdentityTransform;
- Transform::orientation_flags rotation;
- status_t result;
- bool isLocalScreenshot;
- public:
- MessageCaptureScreen(SurfaceFlinger* flinger,
- const sp<IBinder>& display,
- const sp<IGraphicBufferProducer>& producer,
- Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
- int32_t minLayerZ, int32_t maxLayerZ,
- bool useIdentityTransform,
- Transform::orientation_flags rotation,
- bool isLocalScreenshot)
- : flinger(flinger), display(display), producer(producer),
- sourceCrop(sourceCrop), reqWidth(reqWidth), reqHeight(reqHeight),
- minLayerZ(minLayerZ), maxLayerZ(maxLayerZ),
- useIdentityTransform(useIdentityTransform),
- rotation(rotation), result(PERMISSION_DENIED),
- isLocalScreenshot(isLocalScreenshot)
- {
- }
- status_t getResult() const {
- return result;
- }
- virtual bool handler() {
- Mutex::Autolock _l(flinger->mStateLock);
- sp<const DisplayDevice> hw(flinger->getDisplayDeviceLocked(display));
- result = flinger->captureScreenImplLocked(hw, producer,
- sourceCrop, reqWidth, reqHeight, minLayerZ, maxLayerZ,
- useIdentityTransform, rotation, isLocalScreenshot);
- static_cast<GraphicProducerWrapper*>(IInterface::asBinder(producer).get())->exit(result);
- return true;
- }
- };
-
- // this creates a "fake" BBinder which will serve as a "fake" remote
- // binder to receive the marshaled calls and forward them to the
- // real remote (a BpGraphicBufferProducer)
- sp<GraphicProducerWrapper> wrapper = new GraphicProducerWrapper(producer);
-
- // the asInterface() call below creates our "fake" BpGraphicBufferProducer
- // which does the marshaling work forwards to our "fake remote" above.
- sp<MessageBase> msg = new MessageCaptureScreen(this,
- display, IGraphicBufferProducer::asInterface( wrapper ),
- sourceCrop, reqWidth, reqHeight, minLayerZ, maxLayerZ,
- useIdentityTransform, rotationFlags, isLocalScreenshot);
-
- status_t res = postMessageAsync(msg);
- if (res == NO_ERROR) {
- res = wrapper->waitForResponse();
- }
- return res;
-}
-
-
-void SurfaceFlinger::renderScreenImplLocked(
- const sp<const DisplayDevice>& hw,
- Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
- int32_t minLayerZ, int32_t maxLayerZ,
- bool yswap, bool useIdentityTransform, Transform::orientation_flags rotation)
-{
- ATRACE_CALL();
- RenderEngine& engine(getRenderEngine());
-
- // get screen geometry
- const int32_t hw_w = hw->getWidth();
- const int32_t hw_h = hw->getHeight();
- const bool filtering = static_cast<int32_t>(reqWidth) != hw_w ||
- static_cast<int32_t>(reqHeight) != hw_h;
-
- // if a default or invalid sourceCrop is passed in, set reasonable values
- if (sourceCrop.width() == 0 || sourceCrop.height() == 0 ||
- !sourceCrop.isValid()) {
- sourceCrop.setLeftTop(Point(0, 0));
- sourceCrop.setRightBottom(Point(hw_w, hw_h));
- }
-
- // ensure that sourceCrop is inside screen
- if (sourceCrop.left < 0) {
- ALOGE("Invalid crop rect: l = %d (< 0)", sourceCrop.left);
- }
- if (sourceCrop.right > hw_w) {
- ALOGE("Invalid crop rect: r = %d (> %d)", sourceCrop.right, hw_w);
- }
- if (sourceCrop.top < 0) {
- ALOGE("Invalid crop rect: t = %d (< 0)", sourceCrop.top);
- }
- if (sourceCrop.bottom > hw_h) {
- ALOGE("Invalid crop rect: b = %d (> %d)", sourceCrop.bottom, hw_h);
- }
-
- // make sure to clear all GL error flags
- engine.checkErrors();
-
- // set-up our viewport
- engine.setViewportAndProjection(
- reqWidth, reqHeight, sourceCrop, hw_h, yswap, rotation);
- engine.disableTexturing();
-
- // redraw the screen entirely...
- engine.clearWithColor(0, 0, 0, 1);
-
- // We loop through the first level of layers without traversing,
- // as we need to interpret min/max layer Z in the top level Z space.
- for (const auto& layer : mDrawingState.layersSortedByZ) {
- if (layer->getLayerStack() != hw->getLayerStack()) {
- continue;
- }
- const Layer::State& state(layer->getDrawingState());
- if (state.z < minLayerZ || state.z > maxLayerZ) {
- continue;
- }
- layer->traverseInZOrder(LayerVector::StateSet::Drawing, [&](Layer* layer) {
- if (!layer->isVisible()) {
- return;
- }
- if (filtering) layer->setFiltering(true);
- layer->draw(hw, useIdentityTransform);
- if (filtering) layer->setFiltering(false);
- });
- }
-
- hw->setViewportAndProjection();
-}
-
-
-status_t SurfaceFlinger::captureScreenImplLocked(
- const sp<const DisplayDevice>& hw,
- const sp<IGraphicBufferProducer>& producer,
- Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
- int32_t minLayerZ, int32_t maxLayerZ,
- bool useIdentityTransform, Transform::orientation_flags rotation,
- bool isLocalScreenshot)
-{
- ATRACE_CALL();
-
- // get screen geometry
- uint32_t hw_w = hw->getWidth();
- uint32_t hw_h = hw->getHeight();
-
- if (rotation & Transform::ROT_90) {
- std::swap(hw_w, hw_h);
- }
-
- if ((reqWidth > hw_w) || (reqHeight > hw_h)) {
- ALOGE("size mismatch (%d, %d) > (%d, %d)",
- reqWidth, reqHeight, hw_w, hw_h);
- return BAD_VALUE;
- }
-
- reqWidth = (!reqWidth) ? hw_w : reqWidth;
- reqHeight = (!reqHeight) ? hw_h : reqHeight;
-
- bool secureLayerIsVisible = false;
- for (const auto& layer : mDrawingState.layersSortedByZ) {
- const Layer::State& state(layer->getDrawingState());
- if ((layer->getLayerStack() != hw->getLayerStack()) ||
- (state.z < minLayerZ || state.z > maxLayerZ)) {
- continue;
- }
- layer->traverseInZOrder(LayerVector::StateSet::Drawing, [&](Layer *layer) {
- secureLayerIsVisible = secureLayerIsVisible || (layer->isVisible() &&
- layer->isSecure());
- });
- }
-
- if (!isLocalScreenshot && secureLayerIsVisible) {
- ALOGW("FB is protected: PERMISSION_DENIED");
- return PERMISSION_DENIED;
- }
-
// create a surface (because we're a producer, and we need to
// dequeue/queue a buffer)
- sp<Surface> sur = new Surface(producer, false);
+ sp<Surface> surface = new Surface(producer, false);
// Put the screenshot Surface into async mode so that
// Layer::headFenceHasSignaled will always return true and we'll latch the
// first buffer regardless of whether or not its acquire fence has
// signaled. This is needed to avoid a race condition in the rotation
// animation. See b/30209608
- sur->setAsyncMode(true);
+ surface->setAsyncMode(true);
- ANativeWindow* window = sur.get();
+ ANativeWindow* window = surface.get();
status_t result = native_window_api_connect(window, NATIVE_WINDOW_API_EGL);
- if (result == NO_ERROR) {
- uint32_t usage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN |
- GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE;
+ if (result != NO_ERROR) {
+ return result;
+ }
+ WindowDisconnector disconnector(window, NATIVE_WINDOW_API_EGL);
- int err = 0;
- err = native_window_set_buffers_dimensions(window, reqWidth, reqHeight);
- err |= native_window_set_scaling_mode(window, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
- err |= native_window_set_buffers_format(window, HAL_PIXEL_FORMAT_RGBA_8888);
- err |= native_window_set_usage(window, usage);
-
- if (err == NO_ERROR) {
- ANativeWindowBuffer* buffer;
- /* TODO: Once we have the sync framework everywhere this can use
- * server-side waits on the fence that dequeueBuffer returns.
- */
- result = native_window_dequeue_buffer_and_wait(window, &buffer);
- if (result == NO_ERROR) {
- 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) {
- // this binds the given EGLImage as a framebuffer for the
- // duration of this scope.
- RenderEngine::BindImageAsFramebuffer imageBond(getRenderEngine(), image);
- if (imageBond.getStatus() == NO_ERROR) {
- // this will in fact render into our dequeued buffer
- // via an FBO, which means we didn't have to create
- // an EGLSurface and therefore we're not
- // dependent on the context's EGLConfig.
- renderScreenImplLocked(
- hw, sourceCrop, reqWidth, reqHeight, minLayerZ, maxLayerZ, true,
- useIdentityTransform, rotation);
-
- // 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 (!DEBUG_SCREENSHOTS) {
- sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_NATIVE_FENCE_ANDROID, NULL);
- // native fence fd will not be populated until flush() is done.
- getRenderEngine().flush();
- } else {
- sync = EGL_NO_SYNC_KHR;
- }
- 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());
- }
- }
- if (DEBUG_SCREENSHOTS) {
- uint32_t* pixels = new uint32_t[reqWidth*reqHeight];
- getRenderEngine().readPixels(0, 0, reqWidth, reqHeight, pixels);
- checkScreenshot(reqWidth, reqHeight, reqWidth, pixels,
- hw, minLayerZ, maxLayerZ);
- delete [] pixels;
- }
-
- } else {
- ALOGE("got GL_FRAMEBUFFER_COMPLETE_OES error while taking screenshot");
- result = INVALID_OPERATION;
- window->cancelBuffer(window, buffer, syncFd);
- buffer = NULL;
- }
- // destroy our image
- eglDestroyImageKHR(mEGLDisplay, image);
- } else {
- result = BAD_VALUE;
- }
- if (buffer) {
- // queueBuffer takes ownership of syncFd
- result = window->queueBuffer(window, buffer, syncFd);
- }
- }
- } else {
- result = BAD_VALUE;
- }
- native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL);
+ ANativeWindowBuffer* buffer = nullptr;
+ result = getWindowBuffer(window, renderArea.getReqWidth(), renderArea.getReqHeight(),
+ hasWideColorDisplay && !mForceNativeColorMode,
+ getRenderEngine().usesWideColor(), &buffer);
+ if (result != NO_ERROR) {
+ return result;
}
+ // This mutex protects syncFd and captureResult for communication of the return values from the
+ // main thread back to this Binder thread
+ std::mutex captureMutex;
+ std::condition_variable captureCondition;
+ std::unique_lock<std::mutex> captureLock(captureMutex);
+ int syncFd = -1;
+ std::optional<status_t> captureResult;
+
+ sp<LambdaMessage> message = new LambdaMessage([&]() {
+ // If there is a refresh pending, bug out early and tell the binder thread to try again
+ // after the refresh.
+ if (mRefreshPending) {
+ ATRACE_NAME("Skipping screenshot for now");
+ std::unique_lock<std::mutex> captureLock(captureMutex);
+ captureResult = std::make_optional<status_t>(EAGAIN);
+ captureCondition.notify_one();
+ return;
+ }
+
+ status_t result = NO_ERROR;
+ int fd = -1;
+ {
+ Mutex::Autolock _l(mStateLock);
+ result = captureScreenImplLocked(renderArea, traverseLayers, buffer,
+ useIdentityTransform, isLocalScreenshot, &fd);
+ }
+
+ {
+ std::unique_lock<std::mutex> captureLock(captureMutex);
+ syncFd = fd;
+ captureResult = std::make_optional<status_t>(result);
+ captureCondition.notify_one();
+ }
+ });
+
+ result = postMessageAsync(message);
+ if (result == NO_ERROR) {
+ captureCondition.wait(captureLock, [&]() { return captureResult; });
+ while (*captureResult == EAGAIN) {
+ captureResult.reset();
+ result = postMessageAsync(message);
+ if (result != NO_ERROR) {
+ return result;
+ }
+ captureCondition.wait(captureLock, [&]() { return captureResult; });
+ }
+ result = *captureResult;
+ }
+
+ if (result == NO_ERROR) {
+ // queueBuffer takes ownership of syncFd
+ result = window->queueBuffer(window, buffer, syncFd);
+ }
return result;
}
-void SurfaceFlinger::checkScreenshot(size_t w, size_t s, size_t h, void const* vaddr,
- const sp<const DisplayDevice>& hw, int32_t minLayerZ, int32_t maxLayerZ) {
+void SurfaceFlinger::renderScreenImplLocked(const RenderArea& renderArea,
+ TraverseLayersFunction traverseLayers, bool yswap,
+ bool useIdentityTransform) {
+ ATRACE_CALL();
+
+ RenderEngine& engine(getRenderEngine());
+
+ // get screen geometry
+ const auto raWidth = renderArea.getWidth();
+ const auto raHeight = renderArea.getHeight();
+
+ const auto reqWidth = renderArea.getReqWidth();
+ const auto reqHeight = renderArea.getReqHeight();
+ Rect sourceCrop = renderArea.getSourceCrop();
+
+ const bool filtering = static_cast<int32_t>(reqWidth) != raWidth ||
+ static_cast<int32_t>(reqHeight) != raHeight;
+
+ // if a default or invalid sourceCrop is passed in, set reasonable values
+ if (sourceCrop.width() == 0 || sourceCrop.height() == 0 || !sourceCrop.isValid()) {
+ sourceCrop.setLeftTop(Point(0, 0));
+ sourceCrop.setRightBottom(Point(raWidth, raHeight));
+ }
+
+ // ensure that sourceCrop is inside screen
+ if (sourceCrop.left < 0) {
+ ALOGE("Invalid crop rect: l = %d (< 0)", sourceCrop.left);
+ }
+ if (sourceCrop.right > raWidth) {
+ ALOGE("Invalid crop rect: r = %d (> %d)", sourceCrop.right, raWidth);
+ }
+ if (sourceCrop.top < 0) {
+ ALOGE("Invalid crop rect: t = %d (< 0)", sourceCrop.top);
+ }
+ if (sourceCrop.bottom > raHeight) {
+ ALOGE("Invalid crop rect: b = %d (> %d)", sourceCrop.bottom, raHeight);
+ }
+
+ engine.setWideColor(renderArea.getWideColorSupport() && !mForceNativeColorMode);
+ engine.setColorMode(mForceNativeColorMode ? HAL_COLOR_MODE_NATIVE : renderArea.getActiveColorMode());
+
+ // make sure to clear all GL error flags
+ engine.checkErrors();
+
+ // set-up our viewport
+ engine.setViewportAndProjection(reqWidth, reqHeight, sourceCrop, raHeight, yswap,
+ renderArea.getRotationFlags());
+ engine.disableTexturing();
+
+ // redraw the screen entirely...
+ engine.clearWithColor(0, 0, 0, 1);
+
+ traverseLayers([&](Layer* layer) {
+ if (filtering) layer->setFiltering(true);
+ layer->draw(renderArea, useIdentityTransform);
+ if (filtering) layer->setFiltering(false);
+ });
+}
+
+// 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,
+ bool useIdentityTransform, bool isLocalScreenshot,
+ int* outSyncFd) {
+ ATRACE_CALL();
+
+ bool secureLayerIsVisible = false;
+
+ traverseLayers([&](Layer* layer) {
+ secureLayerIsVisible = secureLayerIsVisible || (layer->isVisible() && layer->isSecure());
+ });
+
+ if (!isLocalScreenshot && secureLayerIsVisible) {
+ ALOGW("FB is protected: PERMISSION_DENIED");
+ 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");
+ return INVALID_OPERATION;
+ }
+
+ // this will in fact render into our dequeued buffer
+ // via an FBO, which means we didn't have to create
+ // an EGLSurface and therefore we're not
+ // 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;
+
if (DEBUG_SCREENSHOTS) {
- for (size_t y=0 ; y<h ; y++) {
- uint32_t const * p = (uint32_t const *)vaddr + y*s;
- for (size_t x=0 ; x<w ; x++) {
+ const auto reqWidth = renderArea.getReqWidth();
+ const auto reqHeight = renderArea.getReqHeight();
+
+ uint32_t* pixels = new uint32_t[reqWidth*reqHeight];
+ getRenderEngine().readPixels(0, 0, reqWidth, reqHeight, pixels);
+ checkScreenshot(reqWidth, reqHeight, reqWidth, pixels, traverseLayers);
+ delete [] pixels;
+ }
+
+ // destroy our image
+ imageHolder.destroy();
+ return NO_ERROR;
+}
+
+void SurfaceFlinger::checkScreenshot(size_t w, size_t s, size_t h, void const* vaddr,
+ TraverseLayersFunction traverseLayers) {
+ if (DEBUG_SCREENSHOTS) {
+ for (size_t y = 0; y < h; y++) {
+ uint32_t const* p = (uint32_t const*)vaddr + y * s;
+ for (size_t x = 0; x < w; x++) {
if (p[x] != 0xFF000000) return;
}
}
- ALOGE("*** we just took a black screenshot ***\n"
- "requested minz=%d, maxz=%d, layerStack=%d",
- minLayerZ, maxLayerZ, hw->getLayerStack());
+ ALOGE("*** we just took a black screenshot ***");
size_t i = 0;
- for (const auto& layer : mDrawingState.layersSortedByZ) {
+ traverseLayers([&](Layer* layer) {
const Layer::State& state(layer->getDrawingState());
- if (layer->getLayerStack() == hw->getLayerStack() && state.z >= minLayerZ &&
- state.z <= maxLayerZ) {
- layer->traverseInZOrder(LayerVector::StateSet::Drawing, [&](Layer* layer) {
- ALOGE("%c index=%zu, name=%s, layerStack=%d, z=%d, visible=%d, flags=%x, alpha=%.3f",
- layer->isVisible() ? '+' : '-',
- i, layer->getName().string(), layer->getLayerStack(), state.z,
- layer->isVisible(), state.flags, state.alpha);
- i++;
- });
- }
- }
+ ALOGE("%c index=%zu, name=%s, layerStack=%d, z=%d, visible=%d, flags=%x, alpha=%.3f",
+ layer->isVisible() ? '+' : '-', i, layer->getName().string(),
+ layer->getLayerStack(), state.z, layer->isVisible(), state.flags,
+ static_cast<float>(state.color.a));
+ i++;
+ });
}
}
@@ -4451,6 +4700,28 @@
layersSortedByZ.traverseInReverseZOrder(stateSet, visitor);
}
+void SurfaceFlinger::traverseLayersInDisplay(const sp<const DisplayDevice>& hw, int32_t minLayerZ,
+ int32_t maxLayerZ,
+ const LayerVector::Visitor& visitor) {
+ // We loop through the first level of layers without traversing,
+ // as we need to interpret min/max layer Z in the top level Z space.
+ for (const auto& layer : mDrawingState.layersSortedByZ) {
+ if (!layer->belongsToDisplay(hw->getLayerStack(), false)) {
+ continue;
+ }
+ const Layer::State& state(layer->getDrawingState());
+ if (state.z < minLayerZ || state.z > maxLayerZ) {
+ continue;
+ }
+ layer->traverseInZOrder(LayerVector::StateSet::Drawing, [&](Layer* layer) {
+ if (!layer->isVisible()) {
+ return;
+ }
+ visitor(layer);
+ });
+ }
+}
+
}; // namespace android
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 1bc689d..d10b41b 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -43,13 +43,15 @@
#include <gui/FrameTimestamps.h>
#include <gui/ISurfaceComposer.h>
#include <gui/ISurfaceComposerClient.h>
+#include <gui/LayerState.h>
+
#include <gui/OccupancyTracker.h>
#include <hardware/hwcomposer_defs.h>
-#include <system/graphics.h>
+#include <serviceutils/PriorityDumper.h>
-#include <private/gui/LayerState.h>
+#include <system/graphics.h>
#include "Barrier.h"
#include "DisplayDevice.h"
@@ -58,16 +60,29 @@
#include "LayerVector.h"
#include "MessageQueue.h"
#include "SurfaceInterceptor.h"
-#include "StartBootAnimThread.h"
+#include "SurfaceTracing.h"
+#include "StartPropertySetThread.h"
+#ifdef USE_HWC2
+#include "DisplayHardware/HWC2.h"
#include "DisplayHardware/HWComposer.h"
+#else
+#include "DisplayHardware/HWComposer_hwc1.h"
+#endif
+
#include "Effects/Daltonizer.h"
#include <map>
#include <mutex>
#include <queue>
#include <string>
+#include <thread>
#include <utility>
+#include "RenderArea.h"
+
+#include <layerproto/LayerProtoHeader.h>
+
+using namespace android::surfaceflinger;
namespace android {
@@ -77,13 +92,15 @@
class DisplayEventConnection;
class EventThread;
class Layer;
-class LayerDim;
+class ColorLayer;
class Surface;
class RenderEngine;
class EventControlThread;
class VSyncSource;
class InjectVSyncSource;
+typedef std::function<void(const LayerVector::Visitor&)> TraverseLayersFunction;
+
namespace dvr {
class VrFlinger;
} // namespace dvr
@@ -98,8 +115,13 @@
};
class SurfaceFlinger : public BnSurfaceComposer,
+ public PriorityDumper,
private IBinder::DeathRecipient,
+#ifdef USE_HWC2
+ private HWC2::ComposerCallback
+#else
private HWComposer::EventHandler
+#endif
{
public:
@@ -181,6 +203,8 @@
// force full composition on all displays
void repaintEverything();
+ // Can only be called from the main thread or with mStateLock held
+ void repaintEverythingLocked();
// returns the default Display
sp<const DisplayDevice> getDefaultDisplayDevice() const {
@@ -220,6 +244,7 @@
friend class DisplayEventConnection;
friend class EventThread;
friend class Layer;
+ friend class BufferLayer;
friend class MonitoredProducer;
// This value is specified in number of frames. Log frame stats at most
@@ -227,7 +252,6 @@
enum { LOG_FRAME_STATS_PERIOD = 30*60*60 };
static const size_t MAX_LAYERS = 4096;
- static constexpr const char* kTimestampProperty = "service.sf.present_timestamp";
// We're reference counted, never destroy SurfaceFlinger directly
virtual ~SurfaceFlinger();
@@ -260,7 +284,7 @@
*/
virtual status_t onTransact(uint32_t code, const Parcel& data,
Parcel* reply, uint32_t flags);
- virtual status_t dump(int fd, const Vector<String16>& args);
+ virtual status_t dump(int fd, const Vector<String16>& args) { return priorityDump(fd, args); }
/* ------------------------------------------------------------------------
* ISurfaceComposer interface
@@ -277,12 +301,16 @@
const sp<IGraphicBufferProducer>& bufferProducer) const;
virtual status_t getSupportedFrameTimestamps(
std::vector<FrameEvent>* outSupported) const;
- virtual sp<IDisplayEventConnection> createDisplayEventConnection();
+ virtual sp<IDisplayEventConnection> createDisplayEventConnection(
+ ISurfaceComposer::VsyncSource vsyncSource = eVsyncSourceApp);
virtual status_t captureScreen(const sp<IBinder>& display,
const sp<IGraphicBufferProducer>& producer,
Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
int32_t minLayerZ, int32_t maxLayerZ,
bool useIdentityTransform, ISurfaceComposer::Rotation rotation);
+ virtual status_t captureLayers(const sp<IBinder>& parentHandle,
+ const sp<IGraphicBufferProducer>& producer,
+ ISurfaceComposer::Rotation rotation);
virtual status_t getDisplayStats(const sp<IBinder>& display,
DisplayStatInfo* stats);
virtual status_t getDisplayConfigs(const sp<IBinder>& display,
@@ -300,6 +328,7 @@
HdrCapabilities* outCapabilities) const;
virtual status_t enableVSyncInjections(bool enable);
virtual status_t injectVSync(nsecs_t when);
+ virtual status_t getLayerDebugInfo(std::vector<LayerDebugInfo>* outLayers) const;
/* ------------------------------------------------------------------------
@@ -313,17 +342,28 @@
virtual void onFirstRef();
/* ------------------------------------------------------------------------
- * HWComposer::EventHandler interface
+ * HWC2::ComposerCallback / HWComposer::EventHandler interface
*/
- virtual void onVSyncReceived(HWComposer* composer, int type, nsecs_t timestamp);
- virtual void onHotplugReceived(HWComposer* composer, int disp, bool connected);
- virtual void onInvalidateReceived(HWComposer* composer);
+#ifdef USE_HWC2
+ void onVsyncReceived(int32_t sequenceId, hwc2_display_t display,
+ int64_t timestamp) override;
+ void onHotplugReceived(int32_t sequenceId, hwc2_display_t display,
+ HWC2::Connection connection,
+ bool primaryDisplay) override;
+ void onRefreshReceived(int32_t sequenceId, hwc2_display_t display) override;
+#else
+ void onVSyncReceived(HWComposer* composer, int type, nsecs_t timestamp) override;
+ void onHotplugReceived(HWComposer* composer, int disp, bool connected) override;
+ void onInvalidateReceived(HWComposer* composer) override;
+#endif
/* ------------------------------------------------------------------------
* Message handling
*/
void waitForEvent();
+ // Can only be called from the main thread or with mStateLock held
void signalTransaction();
+ // Can only be called from the main thread or with mStateLock held
void signalLayerUpdate();
void signalRefresh();
@@ -332,7 +372,12 @@
// called on the main thread in response to setActiveConfig()
void setActiveConfigInternal(const sp<DisplayDevice>& hw, int mode);
// called on the main thread in response to setPowerMode()
+#ifdef USE_HWC2
+ void setPowerModeInternal(const sp<DisplayDevice>& hw, int mode,
+ bool stateLockHeld);
+#else
void setPowerModeInternal(const sp<DisplayDevice>& hw, int mode);
+#endif
// Called on the main thread in response to setActiveColorMode()
void setActiveColorModeInternal(const sp<DisplayDevice>& hw, android_color_mode_t colorMode);
@@ -361,6 +406,7 @@
*/
uint32_t getTransactionFlags(uint32_t flags);
uint32_t peekTransactionFlags();
+ // Can only be called from the main thread or with mStateLock held
uint32_t setTransactionFlags(uint32_t flags);
void commitTransaction();
uint32_t setClientStateLocked(const sp<Client>& client, const layer_state_t& s);
@@ -374,14 +420,14 @@
uint32_t windowType, uint32_t ownerUid, sp<IBinder>* handle,
sp<IGraphicBufferProducer>* gbp, sp<Layer>* parent);
- status_t createNormalLayer(const sp<Client>& client, const String8& name,
+ status_t createBufferLayer(const sp<Client>& client, const String8& name,
uint32_t w, uint32_t h, uint32_t flags, PixelFormat& format,
sp<IBinder>* outHandle, sp<IGraphicBufferProducer>* outGbp,
sp<Layer>* outLayer);
- status_t createDimLayer(const sp<Client>& client, const String8& name,
+ status_t createColorLayer(const sp<Client>& client, const String8& name,
uint32_t w, uint32_t h, uint32_t flags, sp<IBinder>* outHandle,
- sp<IGraphicBufferProducer>* outGbp, sp<Layer>* outLayer);
+ sp<Layer>* outLayer);
String8 getUniqueLayerName(const String8& name);
@@ -395,7 +441,7 @@
status_t onLayerDestroyed(const wp<Layer>& layer);
// remove a layer from SurfaceFlinger immediately
- status_t removeLayer(const sp<Layer>& layer);
+ status_t removeLayer(const sp<Layer>& layer, bool topLevelOnly = false);
// add a layer to SurfaceFlinger
status_t addClientLayer(const sp<Client>& client,
@@ -410,21 +456,33 @@
void startBootAnim();
- void renderScreenImplLocked(
- const sp<const DisplayDevice>& hw,
- Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
- int32_t minLayerZ, int32_t maxLayerZ,
- bool yswap, bool useIdentityTransform, Transform::orientation_flags rotation);
+ void renderScreenImplLocked(const RenderArea& renderArea, TraverseLayersFunction traverseLayers,
+ bool yswap, bool useIdentityTransform);
- status_t captureScreenImplLocked(
- const sp<const DisplayDevice>& hw,
- const sp<IGraphicBufferProducer>& producer,
- Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
- int32_t minLayerZ, int32_t maxLayerZ,
- bool useIdentityTransform, Transform::orientation_flags rotation,
- bool isLocalScreenshot);
+ status_t captureScreenCommon(RenderArea& renderArea, TraverseLayersFunction traverseLayers,
+ const sp<IGraphicBufferProducer>& producer,
+ bool useIdentityTransform);
- sp<StartBootAnimThread> mStartBootAnimThread = nullptr;
+#ifdef USE_HWC2
+ status_t captureScreenImplLocked(const RenderArea& renderArea,
+ TraverseLayersFunction traverseLayers,
+ ANativeWindowBuffer* buffer, bool useIdentityTransform,
+ bool isLocalScreenshot, int* outSyncFd);
+#else
+ status_t captureScreenImplLocked(const RenderArea& renderArea,
+ TraverseLayersFunction traverseLayers,
+ const sp<IGraphicBufferProducer>& producer,
+ bool useIdentityTransform, bool isLocalScreenshot);
+#endif
+ void traverseLayersInDisplay(const sp<const DisplayDevice>& display, int32_t minLayerZ,
+ int32_t maxLayerZ, const LayerVector::Visitor& visitor);
+
+ sp<StartPropertySetThread> mStartPropertySetThread = nullptr;
+
+ /* ------------------------------------------------------------------------
+ * Properties
+ */
+ void readPersistentProperties();
/* ------------------------------------------------------------------------
* EGL
@@ -480,7 +538,7 @@
// mark a region of a layer stack dirty. this updates the dirty
// region of all screens presenting this layer stack.
- void invalidateLayerStack(uint32_t layerStack, const Region& dirty);
+ void invalidateLayerStack(const sp<const Layer>& layer, const Region& dirty);
#ifndef USE_HWC2
int32_t allocateHwcDisplayId(DisplayDevice::DisplayType type);
@@ -496,7 +554,7 @@
* Compositing
*/
void invalidateHwcGeometry();
- void computeVisibleRegions(uint32_t layerStack,
+ void computeVisibleRegions(const sp<const DisplayDevice>& displayDevice,
Region& dirtyRegion, Region& opaqueRegion);
void preComposition(nsecs_t refreshStartTime);
@@ -511,12 +569,15 @@
// Given a dataSpace, returns the appropriate color_mode to use
// to display that dataSpace.
- android_color_mode pickColorMode(android_dataspace dataSpace);
- android_dataspace bestTargetDataSpace(android_dataspace a, android_dataspace b);
+ android_color_mode pickColorMode(android_dataspace dataSpace) const;
+ android_dataspace bestTargetDataSpace(android_dataspace a, android_dataspace b) const;
+
+ mat4 computeSaturationMatrix() const;
void setUpHWComposer();
void doComposition();
void doDebugFlashRegions();
+ void doTracing(const char* where);
void doDisplayComposition(const sp<const DisplayDevice>& displayDevice, const Region& dirtyRegion);
// compose surfaces for display hw. this fails if using GL and the surface
@@ -545,6 +606,16 @@
/* ------------------------------------------------------------------------
* Debugging & dumpsys
*/
+public:
+ status_t dumpCritical(int fd, const Vector<String16>& /*args*/, bool asProto) {
+ return doDump(fd, Vector<String16>(), asProto);
+ }
+
+ status_t dumpAll(int fd, const Vector<String16>& args, bool asProto) {
+ return doDump(fd, args, asProto);
+ }
+
+private:
void listLayersLocked(const Vector<String16>& args, size_t& index, String8& result) const;
void dumpStatsLocked(const Vector<String16>& args, size_t& index, String8& result) const;
void clearStatsLocked(const Vector<String16>& args, size_t& index, String8& result);
@@ -552,8 +623,7 @@
bool startDdmConnection();
void appendSfConfigString(String8& result) const;
void checkScreenshot(size_t w, size_t s, size_t h, void const* vaddr,
- const sp<const DisplayDevice>& hw,
- int32_t minLayerZ, int32_t maxLayerZ);
+ TraverseLayersFunction traverseLayers);
void logFrameStats();
@@ -565,17 +635,18 @@
std::vector<OccupancyTracker::Segment>&& history);
void dumpBufferingStats(String8& result) const;
void dumpWideColorInfo(String8& result) const;
+ LayersProto dumpProtoInfo() const;
bool isLayerTripleBufferingDisabled() const {
return this->mLayerTripleBufferingDisabled;
}
+ status_t doDump(int fd, const Vector<String16>& args, bool asProto);
#ifdef USE_HWC2
/* ------------------------------------------------------------------------
* VrFlinger
*/
- void clearHwcLayers(const LayerVector& layers);
- void resetHwcLocked();
+ void resetDisplayState();
// Check to see if we should handoff to vr flinger.
void updateVrFlinger();
@@ -602,12 +673,32 @@
// access must be protected by mInvalidateLock
volatile int32_t mRepaintEverything;
- // current, real and vr hardware composers.
- HWComposer* mHwc;
+ // The current hardware composer interface.
+ //
+ // The following thread safety rules apply when accessing mHwc, either
+ // directly or via getHwComposer():
+ //
+ // 1. When recreating mHwc, acquire mStateLock. We currently recreate mHwc
+ // only when switching into and out of vr. Recreating mHwc must only be
+ // done on the main thread.
+ //
+ // 2. When accessing mHwc on the main thread, it's not necessary to acquire
+ // mStateLock.
+ //
+ // 3. When accessing mHwc on a thread other than the main thread, we always
+ // need to acquire mStateLock. This is because the main thread could be
+ // in the process of destroying the current mHwc instance.
+ //
+ // The above thread safety rules only apply to SurfaceFlinger.cpp. In
+ // SurfaceFlinger_hwc1.cpp we create mHwc at surface flinger init and never
+ // destroy it, so it's always safe to access mHwc from any thread without
+ // acquiring mStateLock.
+ std::unique_ptr<HWComposer> mHwc;
+
#ifdef USE_HWC2
- HWComposer* mRealHwc;
- HWComposer* mVrHwc;
+ const std::string mHwcServiceName; // "default" for real use, something else for testing.
#endif
+
// constant members (no synchronization needed for access)
RenderEngine* mRenderEngine;
nsecs_t mBootTime;
@@ -621,10 +712,6 @@
EGLDisplay mEGLDisplay;
sp<IBinder> mBuiltinDisplays[DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES];
-#ifdef USE_HWC2
- std::unique_ptr<dvr::VrFlinger> mVrFlinger;
-#endif
-
// Can only accessed from the main thread, these members
// don't need synchronization
State mDrawingState{LayerVector::StateSet::Drawing};
@@ -662,6 +749,7 @@
bool mPropagateBackpressure = true;
#endif
SurfaceInterceptor mInterceptor;
+ SurfaceTracing mTracing;
bool mUseHwcVirtualDisplays = false;
// Restrict layers to use two buffers in their bufferqueues.
@@ -692,6 +780,8 @@
};
std::queue<CompositePresentTime> mCompositePresentTimes;
+ std::atomic<bool> mRefreshPending{false};
+
/* ------------------------------------------------------------------------
* Feature prototyping
*/
@@ -744,10 +834,19 @@
status_t CheckTransactCodeCredentials(uint32_t code);
#ifdef USE_HWC2
+ std::unique_ptr<dvr::VrFlinger> mVrFlinger;
std::atomic<bool> mVrFlingerRequestsDisplay;
static bool useVrFlinger;
+ std::thread::id mMainThreadId;
+ // The composer sequence id is a monotonically increasing integer that we
+ // use to differentiate callbacks from different hardware composer
+ // instances. Each hardware composer instance gets a different sequence id.
+ int32_t mComposerSequenceId;
#endif
- };
+
+ float mSaturation = 1.0f;
+ bool mForceNativeColorMode = false;
+};
}; // namespace android
#endif // ANDROID_SURFACE_FLINGER_H
diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.cpp b/services/surfaceflinger/SurfaceFlingerConsumer.cpp
index 9babeef..abc8fde 100644
--- a/services/surfaceflinger/SurfaceFlingerConsumer.cpp
+++ b/services/surfaceflinger/SurfaceFlingerConsumer.cpp
@@ -240,10 +240,15 @@
}
void SurfaceFlingerConsumer::onSidebandStreamChanged() {
+ FrameAvailableListener* unsafeFrameAvailableListener = nullptr;
+ {
+ Mutex::Autolock lock(mFrameAvailableMutex);
+ unsafeFrameAvailableListener = mFrameAvailableListener.unsafe_get();
+ }
sp<ContentsChangedListener> listener;
{ // scope for the lock
Mutex::Autolock lock(mMutex);
- ALOG_ASSERT(mFrameAvailableListener.unsafe_get() == mContentsChangedListener.unsafe_get());
+ ALOG_ASSERT(unsafeFrameAvailableListener == mContentsChangedListener.unsafe_get());
listener = mContentsChangedListener.promote();
}
diff --git a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
index 43cf998..ccadd44 100644
--- a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
+++ b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
@@ -41,6 +41,7 @@
#include <gui/BufferQueue.h>
#include <gui/GuiConfig.h>
#include <gui/IDisplayEventConnection.h>
+#include <gui/LayerDebugInfo.h>
#include <gui/Surface.h>
#include <ui/GraphicBufferAllocator.h>
@@ -69,8 +70,9 @@
#include "EventControlThread.h"
#include "EventThread.h"
#include "Layer.h"
+#include "BufferLayer.h"
#include "LayerVector.h"
-#include "LayerDim.h"
+#include "ColorLayer.h"
#include "MonitoredProducer.h"
#include "SurfaceFlinger.h"
@@ -86,6 +88,8 @@
#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
#include <configstore/Utils.h>
+#include <layerproto/LayerProtoParser.h>
+
#define DISPLAY_COUNT 1
/*
@@ -94,7 +98,7 @@
*/
#define DEBUG_SCREENSHOTS false
-EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name);
+extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name);
namespace android {
// ---------------------------------------------------------------------------
@@ -178,6 +182,8 @@
maxFrameBufferAcquiredBuffers = getInt64< ISurfaceFlingerConfigs,
&ISurfaceFlingerConfigs::maxFrameBufferAcquiredBuffers>(2);
+ mPrimaryDispSync.init(hasSyncFramework, dispSyncPresentTimeOffset);
+
char value[PROPERTY_VALUE_MAX];
property_get("ro.bq.gpu_to_cpu_unsupported", value, "0");
@@ -320,8 +326,8 @@
void SurfaceFlinger::bootFinished()
{
- if (mStartBootAnimThread->join() != NO_ERROR) {
- ALOGE("Join StartBootAnimThread failed!");
+ if (mStartPropertySetThread->join() != NO_ERROR) {
+ ALOGE("Join StartPropertySetThread failed!");
}
const nsecs_t now = systemTime();
const nsecs_t duration = now - mBootTime;
@@ -501,6 +507,8 @@
sp<VSyncSource::Callback> mCallback;
};
+// Do not call property_set on main thread which will be blocked by init
+// Use StartPropertySetThread instead.
void SurfaceFlinger::init() {
ALOGI( "SurfaceFlinger's main thread ready to run. "
"Initializing graphics H/W...");
@@ -532,8 +540,8 @@
// Initialize the H/W composer object. There may or may not be an
// actual hardware composer underneath.
- mHwc = new HWComposer(this,
- *static_cast<HWComposer::EventHandler *>(this));
+ mHwc.reset(new HWComposer(this,
+ *static_cast<HWComposer::EventHandler *>(this)));
// get a RenderEngine for the given display / config (can't fail)
mRenderEngine = RenderEngine::create(mEGLDisplay,
@@ -545,9 +553,6 @@
LOG_ALWAYS_FATAL_IF(mEGLContext == EGL_NO_CONTEXT,
"couldn't create EGLContext");
- // Inform native graphics APIs that the present timestamp is NOT supported:
- property_set(kTimestampProperty, "0");
-
// initialize our non-virtual displays
for (size_t i=0 ; i<DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES ; i++) {
DisplayDevice::DisplayType type((DisplayDevice::DisplayType)i);
@@ -600,9 +605,10 @@
mRenderEngine->primeCache();
- mStartBootAnimThread = new StartBootAnimThread();
- if (mStartBootAnimThread->Start() != NO_ERROR) {
- ALOGE("Run StartBootAnimThread failed!");
+ // Inform native graphics APIs that the present timestamp is NOT supported:
+ mStartPropertySetThread = new StartPropertySetThread(false);
+ if (mStartPropertySetThread->Start() != NO_ERROR) {
+ ALOGE("Run StartPropertySetThread failed!");
}
ALOGV("Done initializing");
@@ -616,10 +622,10 @@
void SurfaceFlinger::startBootAnim() {
// Start boot animation service by setting a property mailbox
// if property setting thread is already running, Start() will be just a NOP
- mStartBootAnimThread->Start();
+ mStartPropertySetThread->Start();
// Wait until property was set
- if (mStartBootAnimThread->join() != NO_ERROR) {
- ALOGE("Join StartBootAnimThread failed!");
+ if (mStartPropertySetThread->join() != NO_ERROR) {
+ ALOGE("Join StartPropertySetThread failed!");
}
}
@@ -931,10 +937,43 @@
return NO_ERROR;
}
+status_t SurfaceFlinger::getLayerDebugInfo(std::vector<LayerDebugInfo>* outLayers) const {
+ IPCThreadState* ipc = IPCThreadState::self();
+ const int pid = ipc->getCallingPid();
+ const int uid = ipc->getCallingUid();
+ if ((uid != AID_SHELL) &&
+ !PermissionCache::checkPermission(sDump, pid, uid)) {
+ ALOGE("Layer debug info permission denied for pid=%d, uid=%d", pid, uid);
+ return PERMISSION_DENIED;
+ }
+
+ // Try to acquire a lock for 1s, fail gracefully
+ status_t err = mStateLock.timedLock(s2ns(1));
+ bool locked = (err == NO_ERROR);
+ if (!locked) {
+ ALOGE("LayerDebugInfo: SurfaceFlinger unresponsive (%s [%d]) - exit", strerror(-err), err);
+ return TIMED_OUT;
+ }
+
+ outLayers->clear();
+ mCurrentState.traverseInZOrder([&](Layer* layer) {
+ outLayers->push_back(layer->getLayerDebugInfo());
+ });
+
+ mStateLock.unlock();
+
+ return NO_ERROR;
+}
+
// ----------------------------------------------------------------------------
-sp<IDisplayEventConnection> SurfaceFlinger::createDisplayEventConnection() {
- return mEventThread->createEventConnection();
+sp<IDisplayEventConnection> SurfaceFlinger::createDisplayEventConnection(
+ ISurfaceComposer::VsyncSource vsyncSource) {
+ if (vsyncSource == eVsyncSourceSurfaceFlinger) {
+ return mSFEventThread->createEventConnection();
+ } else {
+ return mEventThread->createEventConnection();
+ }
}
// ----------------------------------------------------------------------------
@@ -1252,6 +1291,7 @@
const HWComposer& hwc = getHwComposer();
const sp<const DisplayDevice> hw(getDefaultDisplayDevice());
+ mGlCompositionDoneTimeline.updateSignalTimes();
std::shared_ptr<FenceTime> glCompositionDoneFenceTime;
if (getHwComposer().hasGlesComposition(hw->getHwcDisplayId())) {
glCompositionDoneFenceTime =
@@ -1260,12 +1300,11 @@
} else {
glCompositionDoneFenceTime = FenceTime::NO_FENCE;
}
- mGlCompositionDoneTimeline.updateSignalTimes();
+ mDisplayTimeline.updateSignalTimes();
sp<Fence> retireFence = mHwc->getDisplayFence(HWC_DISPLAY_PRIMARY);
auto retireFenceTime = std::make_shared<FenceTime>(retireFence);
mDisplayTimeline.push(retireFenceTime);
- mDisplayTimeline.updateSignalTimes();
nsecs_t vsyncPhase = mPrimaryDispSync.computeNextRefresh(0);
nsecs_t vsyncInterval = mPrimaryDispSync.getPeriod();
@@ -1293,7 +1332,7 @@
});
if (retireFence->isValid()) {
- if (mPrimaryDispSync.addPresentFence(retireFence)) {
+ if (mPrimaryDispSync.addPresentFence(retireFenceTime)) {
enableHardwareVsync();
} else {
disableHardwareVsync(false);
@@ -1356,8 +1395,7 @@
const Transform& tr(hw->getTransform());
const Rect bounds(hw->getBounds());
if (hw->isDisplayOn()) {
- computeVisibleRegions(hw->getLayerStack(), dirtyRegion,
- opaqueRegion);
+ computeVisibleRegions(hw, dirtyRegion, opaqueRegion);
mDrawingState.traverseInZOrder([&](Layer* layer) {
if (layer->getLayerStack() == hw->getLayerStack()) {
@@ -1858,7 +1896,7 @@
// TODO: we could cache the transformed region
Region visibleReg;
visibleReg.set(layer->computeScreenBounds());
- invalidateLayerStack(layer->getLayerStack(), visibleReg);
+ invalidateLayerStack(layer, visibleReg);
}
});
}
@@ -1919,7 +1957,7 @@
mTransactionCV.broadcast();
}
-void SurfaceFlinger::computeVisibleRegions(uint32_t layerStack,
+void SurfaceFlinger::computeVisibleRegions(const sp<const DisplayDevice>& displayDevice,
Region& outDirtyRegion, Region& outOpaqueRegion)
{
ATRACE_CALL();
@@ -1935,7 +1973,7 @@
const Layer::State& s(layer->getDrawingState());
// only consider the layers on the given layer stack
- if (layer->getLayerStack() != layerStack)
+ if (layer->getLayerStack() != displayDevice->getLayerStack())
return;
/*
@@ -1989,7 +2027,7 @@
// compute the opaque region
const int32_t layerOrientation = tr.getOrientation();
- if (s.alpha==255 && !translucent &&
+ if (layer->getAlpha()==1.0f && !translucent &&
((layerOrientation & Transform::ROT_INVALID) == false)) {
// the opaque region is the layer's footprint
opaqueRegion = visibleRegion;
@@ -2050,8 +2088,8 @@
outOpaqueRegion = aboveOpaqueLayers;
}
-void SurfaceFlinger::invalidateLayerStack(uint32_t layerStack,
- const Region& dirty) {
+void SurfaceFlinger::invalidateLayerStack(const sp<const Layer>& layer, const Region& dirty) {
+ uint32_t layerStack = layer->getLayerStack();
for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
const sp<DisplayDevice>& hw(mDisplays[dpy]);
if (hw->getLayerStack() == layerStack) {
@@ -2094,7 +2132,7 @@
Layer* layer = layersWithQueuedFrames[i];
const Region dirty(layer->latchBuffer(visibleRegions, latchTime));
layer->useSurfaceDamage();
- invalidateLayerStack(layer->getLayerStack(), dirty);
+ invalidateLayerStack(layer, dirty);
}
mVisibleRegionsDirty |= visibleRegions;
@@ -2175,6 +2213,8 @@
bool SurfaceFlinger::doComposeSurfaces(const sp<const DisplayDevice>& hw, const Region& dirty)
{
+ DisplayRenderArea renderArea(hw);
+
RenderEngine& engine(getRenderEngine());
const int32_t id = hw->getHwcDisplayId();
HWComposer& hwc(getHwComposer());
@@ -2262,16 +2302,16 @@
const Layer::State& state(layer->getDrawingState());
if ((cur->getHints() & HWC_HINT_CLEAR_FB)
&& i
- && layer->isOpaque(state) && (state.alpha == 0xFF)
+ && layer->isOpaque(state) && (state.color.a == 1.0f)
&& hasGlesComposition) {
// never clear the very first layer since we're
// guaranteed the FB is already cleared
- layer->clearWithOpenGL(hw);
+ layer->clearWithOpenGL(renderArea);
}
break;
}
case HWC_FRAMEBUFFER: {
- layer->draw(hw, clip);
+ layer->draw(renderArea, clip);
break;
}
case HWC_FRAMEBUFFER_TARGET: {
@@ -2291,7 +2331,7 @@
const Region clip(dirty.intersect(
tr.transform(layer->visibleRegion)));
if (!clip.isEmpty()) {
- layer->draw(hw, clip);
+ layer->draw(renderArea, clip);
}
}
}
@@ -2322,8 +2362,13 @@
if (parent == nullptr) {
mCurrentState.layersSortedByZ.add(lbc);
} else {
+ if (mCurrentState.layersSortedByZ.indexOf(parent) < 0) {
+ ALOGE("addClientLayer called with a removed parent");
+ return NAME_NOT_FOUND;
+ }
parent->addChild(lbc);
}
+
mGraphicBufferProducerList.add(IInterface::asBinder(gbc));
mLayersAdded = true;
mNumLayers++;
@@ -2335,12 +2380,29 @@
return NO_ERROR;
}
-status_t SurfaceFlinger::removeLayer(const sp<Layer>& layer) {
+status_t SurfaceFlinger::removeLayer(const sp<Layer>& layer, bool topLevelOnly) {
Mutex::Autolock _l(mStateLock);
const auto& p = layer->getParent();
- const ssize_t index = (p != nullptr) ? p->removeChild(layer) :
- mCurrentState.layersSortedByZ.remove(layer);
+ ssize_t index;
+ if (p != nullptr) {
+ if (topLevelOnly) {
+ return NO_ERROR;
+ }
+
+ sp<Layer> ancestor = p;
+ while (ancestor->getParent() != nullptr) {
+ ancestor = ancestor->getParent();
+ }
+ if (mCurrentState.layersSortedByZ.indexOf(ancestor) < 0) {
+ ALOGE("removeLayer called with a layer whose parent has been removed");
+ return NAME_NOT_FOUND;
+ }
+
+ index = p->removeChild(layer);
+ } else {
+ index = mCurrentState.layersSortedByZ.remove(layer);
+ }
// As a matter of normal operation, the LayerCleaner will produce a second
// attempt to remove the surface. The Layer will be kept alive in mDrawingState
@@ -2356,9 +2418,10 @@
return NO_ERROR;
}
+ layer->onRemovedFromCurrentState();
mLayersPendingRemoval.add(layer);
mLayersRemoved = true;
- mNumLayers--;
+ mNumLayers -= 1 + layer->getChildrenCount();
setTransactionFlags(eTransactionNeeded);
return NO_ERROR;
}
@@ -2550,15 +2613,28 @@
}
}
}
+ if (what & layer_state_t::eRelativeLayerChanged) {
+ ssize_t idx = mCurrentState.layersSortedByZ.indexOf(layer);
+ if (layer->setRelativeLayer(s.relativeLayerHandle, s.z)) {
+ mCurrentState.layersSortedByZ.removeAt(idx);
+ mCurrentState.layersSortedByZ.add(layer);
+ flags |= eTransactionNeeded|eTraversalNeeded;
+ }
+ }
if (what & layer_state_t::eSizeChanged) {
if (layer->setSize(s.w, s.h)) {
flags |= eTraversalNeeded;
}
}
if (what & layer_state_t::eAlphaChanged) {
- if (layer->setAlpha(uint8_t(255.0f*s.alpha+0.5f)))
+ if (layer->setAlpha(s.alpha))
flags |= eTraversalNeeded;
}
+ if (what & layer_state_t::eColorChanged) {
+ if (layer->setColor(s.color)) {
+ flags |= eTraversalNeeded;
+ }
+ }
if (what & layer_state_t::eMatrixChanged) {
if (layer->setMatrix(s.matrix))
flags |= eTraversalNeeded;
@@ -2615,6 +2691,11 @@
// We don't trigger a traversal here because if no other state is
// changed, we don't want this to cause any more work
}
+ if (what & layer_state_t::eReparent) {
+ if (layer->reparent(s.parentHandleForChild)) {
+ flags |= eTransactionNeeded|eTraversalNeeded;
+ }
+ }
if (what & layer_state_t::eReparentChildren) {
if (layer->reparentChildren(s.reparentHandle)) {
flags |= eTransactionNeeded|eTraversalNeeded;
@@ -2653,14 +2734,14 @@
switch (flags & ISurfaceComposerClient::eFXSurfaceMask) {
case ISurfaceComposerClient::eFXSurfaceNormal:
- result = createNormalLayer(client,
+ result = createBufferLayer(client,
uniqueName, w, h, flags, format,
handle, gbp, &layer);
break;
- case ISurfaceComposerClient::eFXSurfaceDim:
- result = createDimLayer(client,
+ case ISurfaceComposerClient::eFXSurfaceColor:
+ result = createColorLayer(client,
uniqueName, w, h, flags,
- handle, gbp, &layer);
+ handle, &layer);
break;
default:
result = BAD_VALUE;
@@ -2707,7 +2788,7 @@
return uniqueName;
}
-status_t SurfaceFlinger::createNormalLayer(const sp<Client>& client,
+status_t SurfaceFlinger::createBufferLayer(const sp<Client>& client,
const String8& name, uint32_t w, uint32_t h, uint32_t flags, PixelFormat& format,
sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp, sp<Layer>* outLayer)
{
@@ -2722,24 +2803,24 @@
break;
}
- *outLayer = new Layer(this, client, name, w, h, flags);
- status_t err = (*outLayer)->setBuffers(w, h, format, flags);
+ sp<BufferLayer> layer = new BufferLayer(this, client, name, w, h, flags);
+ status_t err = layer->setBuffers(w, h, format, flags);
if (err == NO_ERROR) {
- *handle = (*outLayer)->getHandle();
- *gbp = (*outLayer)->getProducer();
+ *handle = layer->getHandle();
+ *gbp = layer->getProducer();
+ *outLayer = layer;
}
- ALOGE_IF(err, "createNormalLayer() failed (%s)", strerror(-err));
+ ALOGE_IF(err, "createBufferLayer() failed (%s)", strerror(-err));
return err;
}
-status_t SurfaceFlinger::createDimLayer(const sp<Client>& client,
+status_t SurfaceFlinger::createColorLayer(const sp<Client>& client,
const String8& name, uint32_t w, uint32_t h, uint32_t flags,
- sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp, sp<Layer>* outLayer)
+ sp<IBinder>* handle, sp<Layer>* outLayer)
{
- *outLayer = new LayerDim(this, client, name, w, h, flags);
+ *outLayer = new ColorLayer(this, client, name, w, h, flags);
*handle = (*outLayer)->getHandle();
- *gbp = (*outLayer)->getProducer();
return NO_ERROR;
}
@@ -2765,11 +2846,9 @@
if (l == nullptr) {
// The layer has already been removed, carry on
return NO_ERROR;
- } if (l->getParent() != nullptr) {
- // If we have a parent, then we can continue to live as long as it does.
- return NO_ERROR;
}
- return removeLayer(l);
+ // If we have a parent, then we can continue to live as long as it does.
+ return removeLayer(l, true);
}
// ---------------------------------------------------------------------------
@@ -2933,13 +3012,18 @@
// ---------------------------------------------------------------------------
-status_t SurfaceFlinger::dump(int fd, const Vector<String16>& args)
-{
+status_t SurfaceFlinger::doDump(int fd, const Vector<String16>& args, bool asProto) {
String8 result;
IPCThreadState* ipc = IPCThreadState::self();
const int pid = ipc->getCallingPid();
const int uid = ipc->getCallingUid();
+
+ if (asProto) {
+ // Return early as SurfaceFlinger does not support dumping sections in proto format
+ return OK;
+ }
+
if ((uid != AID_SHELL) &&
!PermissionCache::checkPermission(sDump, pid, uid)) {
result.appendFormat("Permission Denial: "
@@ -3001,6 +3085,13 @@
dumpFrameEventsLocked(result);
dumpAll = false;
}
+
+ if ((index < numArgs) && (args[index] == String16("--proto"))) {
+ index++;
+ LayersProto layersProto = dumpProtoInfo();
+ result.append(layersProto.SerializeAsString().c_str(), layersProto.ByteSize());
+ dumpAll = false;
+ }
}
if (dumpAll) {
@@ -3171,6 +3262,16 @@
result.append("\n");
}
+LayersProto SurfaceFlinger::dumpProtoInfo() const {
+ LayersProto layersProto;
+ mCurrentState.traverseInZOrder([&](Layer* layer) {
+ LayerProto* layerProto = layersProto.add_layers();
+ layer->writeToProto(layerProto, LayerVector::StateSet::Current);
+ });
+
+ return layersProto;
+}
+
void SurfaceFlinger::dumpAllLocked(const Vector<String16>& args, size_t& index,
String8& result) const
{
@@ -3230,9 +3331,10 @@
colorizer.bold(result);
result.appendFormat("Visible layers (count = %zu)\n", mNumLayers);
colorizer.reset(result);
- mCurrentState.traverseInZOrder([&](Layer* layer) {
- layer->dump(result, colorizer);
- });
+
+ LayersProto layersProto = dumpProtoInfo();
+ auto layerTree = LayerProtoParser::generateLayerTree(layersProto);
+ result.append(LayerProtoParser::layersToString(layerTree).c_str());
/*
* Dump Display state
@@ -3401,6 +3503,18 @@
}
break;
}
+ case CAPTURE_LAYERS:
+ {
+ IPCThreadState* ipc = IPCThreadState::self();
+ const int pid = ipc->getCallingPid();
+ const int uid = ipc->getCallingUid();
+ if ((uid != AID_GRAPHICS) &&
+ !PermissionCache::checkPermission(sReadFramebuffer, pid, uid)) {
+ ALOGE("Permission Denial: can't read framebuffer pid=%d, uid=%d", pid, uid);
+ return PERMISSION_DENIED;
+ }
+ break;
+ }
}
status_t err = BnSurfaceComposer::onTransact(code, data, reply, flags);
@@ -3674,16 +3788,72 @@
}
};
-
status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
- const sp<IGraphicBufferProducer>& producer,
- Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
- int32_t minLayerZ, int32_t maxLayerZ,
- bool useIdentityTransform, ISurfaceComposer::Rotation rotation) {
-
+ const sp<IGraphicBufferProducer>& producer,
+ Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
+ int32_t minLayerZ, int32_t maxLayerZ,
+ bool useIdentityTransform, ISurfaceComposer::Rotation rotation) {
+ ATRACE_CALL();
if (CC_UNLIKELY(display == 0))
return BAD_VALUE;
+ const sp<const DisplayDevice> device(getDisplayDeviceLocked(display));
+ DisplayRenderArea renderArea(device, sourceCrop, reqHeight, reqWidth, rotation);
+
+ auto traverseLayers = std::bind(std::mem_fn(&SurfaceFlinger::traverseLayersInDisplay), this,
+ device, minLayerZ, maxLayerZ, std::placeholders::_1);
+ return captureScreenCommon(renderArea, traverseLayers, producer, useIdentityTransform);
+}
+
+status_t SurfaceFlinger::captureLayers(const sp<IBinder>& layerHandleBinder,
+ const sp<IGraphicBufferProducer>& producer,
+ ISurfaceComposer::Rotation rotation) {
+ 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) {}
+ 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
+ return *new Transform(mLayer->getTransform().inverse());
+ }
+ Rect getBounds() const override {
+ const Layer::State& layerState(mLayer->getDrawingState());
+ return Rect(layerState.active.w, layerState.active.h);
+ }
+ int getHeight() const override { return mLayer->getDrawingState().active.h; }
+ int getWidth() const override { return mLayer->getDrawingState().active.w; }
+ bool isSecure() const override { return false; }
+ bool needsFiltering() const override { return false; }
+
+ Rect getSourceCrop() const override { return getBounds(); }
+
+ private:
+ const sp<Layer>& mLayer;
+ };
+
+ auto layerHandle = reinterpret_cast<Layer::Handle*>(layerHandleBinder.get());
+ auto parent = layerHandle->owner.promote();
+
+ LayerRenderArea renderArea(parent, rotation);
+ auto traverseLayers = [parent](const LayerVector::Visitor& visitor) {
+ parent->traverseChildrenInZOrder(LayerVector::StateSet::Drawing, [&](Layer* layer) {
+ if (!layer->isVisible()) {
+ return;
+ }
+ visitor(layer);
+ });
+ };
+ return captureScreenCommon(renderArea, traverseLayers, producer, false);
+}
+
+status_t SurfaceFlinger::captureScreenCommon(RenderArea& renderArea,
+ TraverseLayersFunction traverseLayers,
+ const sp<IGraphicBufferProducer>& producer,
+ bool useIdentityTransform) {
if (CC_UNLIKELY(producer == 0))
return BAD_VALUE;
@@ -3692,64 +3862,33 @@
// ourselves).
bool isLocalScreenshot = IInterface::asBinder(producer)->localBinder();
- // Convert to surfaceflinger's internal rotation type.
- Transform::orientation_flags rotationFlags;
- switch (rotation) {
- case ISurfaceComposer::eRotateNone:
- rotationFlags = Transform::ROT_0;
- break;
- case ISurfaceComposer::eRotate90:
- rotationFlags = Transform::ROT_90;
- break;
- case ISurfaceComposer::eRotate180:
- rotationFlags = Transform::ROT_180;
- break;
- case ISurfaceComposer::eRotate270:
- rotationFlags = Transform::ROT_270;
- break;
- default:
- rotationFlags = Transform::ROT_0;
- ALOGE("Invalid rotation passed to captureScreen(): %d\n", rotation);
- break;
- }
-
class MessageCaptureScreen : public MessageBase {
SurfaceFlinger* flinger;
- sp<IBinder> display;
+ const RenderArea* renderArea;
+ TraverseLayersFunction traverseLayers;
sp<IGraphicBufferProducer> producer;
- Rect sourceCrop;
- uint32_t reqWidth, reqHeight;
- int32_t minLayerZ,maxLayerZ;
bool useIdentityTransform;
- Transform::orientation_flags rotation;
status_t result;
bool isLocalScreenshot;
public:
- MessageCaptureScreen(SurfaceFlinger* flinger,
- const sp<IBinder>& display,
- const sp<IGraphicBufferProducer>& producer,
- Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
- int32_t minLayerZ, int32_t maxLayerZ,
- bool useIdentityTransform,
- Transform::orientation_flags rotation,
- bool isLocalScreenshot)
- : flinger(flinger), display(display), producer(producer),
- sourceCrop(sourceCrop), reqWidth(reqWidth), reqHeight(reqHeight),
- minLayerZ(minLayerZ), maxLayerZ(maxLayerZ),
- useIdentityTransform(useIdentityTransform),
- rotation(rotation), result(PERMISSION_DENIED),
- isLocalScreenshot(isLocalScreenshot)
- {
- }
+ MessageCaptureScreen(SurfaceFlinger* flinger, const RenderArea* renderArea,
+ TraverseLayersFunction traverseLayers,
+ const sp<IGraphicBufferProducer>& producer, bool useIdentityTransform,
+ bool isLocalScreenshot)
+ : flinger(flinger),
+ renderArea(renderArea),
+ traverseLayers(traverseLayers),
+ producer(producer),
+ useIdentityTransform(useIdentityTransform),
+ result(PERMISSION_DENIED),
+ isLocalScreenshot(isLocalScreenshot) {}
status_t getResult() const {
return result;
}
virtual bool handler() {
Mutex::Autolock _l(flinger->mStateLock);
- sp<const DisplayDevice> hw(flinger->getDisplayDeviceLocked(display));
- result = flinger->captureScreenImplLocked(hw, producer,
- sourceCrop, reqWidth, reqHeight, minLayerZ, maxLayerZ,
- useIdentityTransform, rotation, isLocalScreenshot);
+ result = flinger->captureScreenImplLocked(*renderArea, traverseLayers, producer,
+ useIdentityTransform, isLocalScreenshot);
static_cast<GraphicProducerWrapper*>(IInterface::asBinder(producer).get())->exit(result);
return true;
}
@@ -3763,9 +3902,8 @@
// the asInterface() call below creates our "fake" BpGraphicBufferProducer
// which does the marshaling work forwards to our "fake remote" above.
sp<MessageBase> msg = new MessageCaptureScreen(this,
- display, IGraphicBufferProducer::asInterface( wrapper ),
- sourceCrop, reqWidth, reqHeight, minLayerZ, maxLayerZ,
- useIdentityTransform, rotationFlags, isLocalScreenshot);
+ &renderArea, traverseLayers, IGraphicBufferProducer::asInterface( wrapper ),
+ useIdentityTransform, isLocalScreenshot);
status_t res = postMessageAsync(msg);
if (res == NO_ERROR) {
@@ -3774,41 +3912,42 @@
return res;
}
-
-void SurfaceFlinger::renderScreenImplLocked(
- const sp<const DisplayDevice>& hw,
- Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
- int32_t minLayerZ, int32_t maxLayerZ,
- bool yswap, bool useIdentityTransform, Transform::orientation_flags rotation)
+void SurfaceFlinger::renderScreenImplLocked(const RenderArea& renderArea, TraverseLayersFunction traverseLayers,
+ bool yswap, bool useIdentityTransform)
{
ATRACE_CALL();
RenderEngine& engine(getRenderEngine());
// get screen geometry
- const int32_t hw_w = hw->getWidth();
- const int32_t hw_h = hw->getHeight();
- const bool filtering = static_cast<int32_t>(reqWidth) != hw_w ||
- static_cast<int32_t>(reqHeight) != hw_h;
+ const auto raWidth = renderArea.getWidth();
+ const auto raHeight = renderArea.getHeight();
+
+ const auto reqWidth = renderArea.getReqWidth();
+ const auto reqHeight = renderArea.getReqHeight();
+ Rect sourceCrop = renderArea.getSourceCrop();
+
+ const bool filtering = static_cast<int32_t>(reqWidth) != raWidth ||
+ static_cast<int32_t>(reqHeight) != raHeight;
// if a default or invalid sourceCrop is passed in, set reasonable values
if (sourceCrop.width() == 0 || sourceCrop.height() == 0 ||
!sourceCrop.isValid()) {
sourceCrop.setLeftTop(Point(0, 0));
- sourceCrop.setRightBottom(Point(hw_w, hw_h));
+ sourceCrop.setRightBottom(Point(raWidth, raHeight));
}
// ensure that sourceCrop is inside screen
if (sourceCrop.left < 0) {
ALOGE("Invalid crop rect: l = %d (< 0)", sourceCrop.left);
}
- if (sourceCrop.right > hw_w) {
- ALOGE("Invalid crop rect: r = %d (> %d)", sourceCrop.right, hw_w);
+ if (sourceCrop.right > raWidth) {
+ ALOGE("Invalid crop rect: r = %d (> %d)", sourceCrop.right, raWidth);
}
if (sourceCrop.top < 0) {
ALOGE("Invalid crop rect: t = %d (< 0)", sourceCrop.top);
}
- if (sourceCrop.bottom > hw_h) {
- ALOGE("Invalid crop rect: b = %d (> %d)", sourceCrop.bottom, hw_h);
+ if (sourceCrop.bottom > raHeight) {
+ ALOGE("Invalid crop rect: b = %d (> %d)", sourceCrop.bottom, raHeight);
}
// make sure to clear all GL error flags
@@ -3816,77 +3955,35 @@
// set-up our viewport
engine.setViewportAndProjection(
- reqWidth, reqHeight, sourceCrop, hw_h, yswap, rotation);
+ reqWidth, reqHeight, sourceCrop, raHeight, yswap, renderArea.getRotationFlags());
engine.disableTexturing();
// redraw the screen entirely...
engine.clearWithColor(0, 0, 0, 1);
- // We loop through the first level of layers without traversing,
- // as we need to interpret min/max layer Z in the top level Z space.
- for (const auto& layer : mDrawingState.layersSortedByZ) {
- if (layer->getLayerStack() != hw->getLayerStack()) {
- continue;
- }
- const Layer::State& state(layer->getDrawingState());
- if (state.z < minLayerZ || state.z > maxLayerZ) {
- continue;
- }
- layer->traverseInZOrder(LayerVector::StateSet::Drawing, [&](Layer* layer) {
- if (!layer->isVisible()) {
- return;
- }
- if (filtering) layer->setFiltering(true);
- layer->draw(hw, useIdentityTransform);
- if (filtering) layer->setFiltering(false);
- });
- }
+ traverseLayers([&](Layer* layer) {
+ if (filtering) layer->setFiltering(true);
+ layer->draw(renderArea, useIdentityTransform);
+ if (filtering) layer->setFiltering(false);
+ });
// compositionComplete is needed for older driver
- hw->compositionComplete();
- hw->setViewportAndProjection();
+// hw->compositionComplete();
+// hw->setViewportAndProjection();
}
-
-status_t SurfaceFlinger::captureScreenImplLocked(
- const sp<const DisplayDevice>& hw,
- const sp<IGraphicBufferProducer>& producer,
- Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
- int32_t minLayerZ, int32_t maxLayerZ,
- bool useIdentityTransform, Transform::orientation_flags rotation,
- bool isLocalScreenshot)
-{
+status_t SurfaceFlinger::captureScreenImplLocked(const RenderArea& renderArea,
+ TraverseLayersFunction traverseLayers,
+ const sp<IGraphicBufferProducer>& producer,
+ bool useIdentityTransform,
+ bool isLocalScreenshot) {
ATRACE_CALL();
- // get screen geometry
- uint32_t hw_w = hw->getWidth();
- uint32_t hw_h = hw->getHeight();
-
- if (rotation & Transform::ROT_90) {
- std::swap(hw_w, hw_h);
- }
-
- if ((reqWidth > hw_w) || (reqHeight > hw_h)) {
- ALOGE("size mismatch (%d, %d) > (%d, %d)",
- reqWidth, reqHeight, hw_w, hw_h);
- return BAD_VALUE;
- }
-
- reqWidth = (!reqWidth) ? hw_w : reqWidth;
- reqHeight = (!reqHeight) ? hw_h : reqHeight;
-
bool secureLayerIsVisible = false;
- for (const auto& layer : mDrawingState.layersSortedByZ) {
- const Layer::State& state(layer->getDrawingState());
- if ((layer->getLayerStack() != hw->getLayerStack()) ||
- (state.z < minLayerZ || state.z > maxLayerZ)) {
- continue;
- }
- layer->traverseInZOrder(LayerVector::StateSet::Drawing, [&](Layer *layer) {
- secureLayerIsVisible = secureLayerIsVisible || (layer->isVisible() &&
- layer->isSecure());
- });
- }
+ traverseLayers([&](Layer *layer) {
+ secureLayerIsVisible = secureLayerIsVisible || (layer->isVisible() &&
+ layer->isSecure());
+ });
if (!isLocalScreenshot && secureLayerIsVisible) {
ALOGW("FB is protected: PERMISSION_DENIED");
@@ -3904,7 +4001,8 @@
GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE;
int err = 0;
- err = native_window_set_buffers_dimensions(window, reqWidth, reqHeight);
+ err = native_window_set_buffers_dimensions(window, renderArea.getReqWidth(),
+ renderArea.getReqHeight());
err |= native_window_set_scaling_mode(window, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
err |= native_window_set_buffers_format(window, HAL_PIXEL_FORMAT_RGBA_8888);
err |= native_window_set_usage(window, usage);
@@ -3930,9 +4028,7 @@
// via an FBO, which means we didn't have to create
// an EGLSurface and therefore we're not
// dependent on the context's EGLConfig.
- renderScreenImplLocked(
- hw, sourceCrop, reqWidth, reqHeight, minLayerZ, maxLayerZ, true,
- useIdentityTransform, rotation);
+ 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
@@ -3972,10 +4068,12 @@
}
}
if (DEBUG_SCREENSHOTS) {
- uint32_t* pixels = new uint32_t[reqWidth*reqHeight];
- getRenderEngine().readPixels(0, 0, reqWidth, reqHeight, pixels);
- checkScreenshot(reqWidth, reqHeight, reqWidth, pixels,
- hw, minLayerZ, maxLayerZ);
+ uint32_t* pixels = new uint32_t[renderArea.getReqWidth() *
+ renderArea.getReqHeight()];
+ getRenderEngine().readPixels(0, 0, renderArea.getReqWidth(),
+ renderArea.getReqHeight(), pixels);
+ checkScreenshot(renderArea.getReqWidth(), renderArea.getReqHeight(),
+ renderArea.getReqWidth(), pixels, traverseLayers);
delete [] pixels;
}
@@ -4005,7 +4103,7 @@
}
void SurfaceFlinger::checkScreenshot(size_t w, size_t s, size_t h, void const* vaddr,
- const sp<const DisplayDevice>& hw, int32_t minLayerZ, int32_t maxLayerZ) {
+ TraverseLayersFunction traverseLayers) {
if (DEBUG_SCREENSHOTS) {
for (size_t y=0 ; y<h ; y++) {
uint32_t const * p = (uint32_t const *)vaddr + y*s;
@@ -4013,23 +4111,17 @@
if (p[x] != 0xFF000000) return;
}
}
- ALOGE("*** we just took a black screenshot ***\n"
- "requested minz=%d, maxz=%d, layerStack=%d",
- minLayerZ, maxLayerZ, hw->getLayerStack());
+ ALOGE("*** we just took a black screenshot ***");
+
size_t i = 0;
- for (const auto& layer : mDrawingState.layersSortedByZ) {
+ traverseLayers([&](Layer* layer) {
const Layer::State& state(layer->getDrawingState());
- if (layer->getLayerStack() == hw->getLayerStack() && state.z >= minLayerZ &&
- state.z <= maxLayerZ) {
- layer->traverseInZOrder(LayerVector::StateSet::Drawing, [&](Layer* layer) {
- ALOGE("%c index=%zu, name=%s, layerStack=%d, z=%d, visible=%d, flags=%x, alpha=%x",
- layer->isVisible() ? '+' : '-',
- i, layer->getName().string(), layer->getLayerStack(), state.z,
- layer->isVisible(), state.flags, state.alpha);
- i++;
- });
- }
- }
+ ALOGE("%c index=%zu, name=%s, layerStack=%d, z=%d, visible=%d, flags=%x, alpha=%.3f",
+ layer->isVisible() ? '+' : '-',
+ i, layer->getName().string(), layer->getLayerStack(), state.z,
+ layer->isVisible(), state.flags, static_cast<float>(state.color.a));
+ i++;
+ });
}
}
@@ -4043,6 +4135,28 @@
layersSortedByZ.traverseInReverseZOrder(stateSet, visitor);
}
+void SurfaceFlinger::traverseLayersInDisplay(const sp<const DisplayDevice>& hw,
+ int32_t minLayerZ, int32_t maxLayerZ, const LayerVector::Visitor& visitor) {
+
+ // We loop through the first level of layers without traversing,
+ // as we need to interpret min/max layer Z in the top level Z space.
+ for (const auto& layer : mDrawingState.layersSortedByZ) {
+ if (!layer->belongsToDisplay(hw->getLayerStack(), false)) {
+ continue;
+ }
+ const Layer::State& state(layer->getDrawingState());
+ if (state.z < minLayerZ || state.z > maxLayerZ) {
+ continue;
+ }
+ layer->traverseInZOrder(LayerVector::StateSet::Drawing, [&](Layer* layer) {
+ if (!layer->isVisible()) {
+ return;
+ }
+ visitor(layer);
+ });
+ }
+}
+
}; // namespace android
diff --git a/services/surfaceflinger/SurfaceInterceptor.cpp b/services/surfaceflinger/SurfaceInterceptor.cpp
index db489b2..eeb4929 100644
--- a/services/surfaceflinger/SurfaceInterceptor.cpp
+++ b/services/surfaceflinger/SurfaceInterceptor.cpp
@@ -98,7 +98,7 @@
addPositionLocked(transaction, layerId, layer->mCurrentState.active.transform.tx(),
layer->mCurrentState.active.transform.ty());
addDepthLocked(transaction, layerId, layer->mCurrentState.z);
- addAlphaLocked(transaction, layerId, layer->mCurrentState.alpha);
+ addAlphaLocked(transaction, layerId, layer->mCurrentState.color.a);
addTransparentRegionLocked(transaction, layerId, layer->mCurrentState.activeTransparentRegion);
addLayerStackLocked(transaction, layerId, layer->mCurrentState.layerStack);
addCropLocked(transaction, layerId, layer->mCurrentState.crop);
diff --git a/services/surfaceflinger/SurfaceTracing.cpp b/services/surfaceflinger/SurfaceTracing.cpp
new file mode 100644
index 0000000..f8c466e
--- /dev/null
+++ b/services/surfaceflinger/SurfaceTracing.cpp
@@ -0,0 +1,85 @@
+/*
+ * 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.
+ */
+#undef LOG_TAG
+#define LOG_TAG "SurfaceTracing"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+#include "SurfaceTracing.h"
+
+#include <android-base/file.h>
+#include <log/log.h>
+#include <utils/SystemClock.h>
+#include <utils/Trace.h>
+
+namespace android {
+
+void SurfaceTracing::enable() {
+ if (mEnabled) {
+ return;
+ }
+ ATRACE_CALL();
+ mEnabled = true;
+ std::lock_guard<std::mutex> protoGuard(mTraceMutex);
+
+ mTrace.set_magic_number(uint64_t(LayersTraceFileProto_MagicNumber_MAGIC_NUMBER_H) << 32 |
+ LayersTraceFileProto_MagicNumber_MAGIC_NUMBER_L);
+}
+
+status_t SurfaceTracing::disable() {
+ if (!mEnabled) {
+ return NO_ERROR;
+ }
+ ATRACE_CALL();
+ std::lock_guard<std::mutex> protoGuard(mTraceMutex);
+ mEnabled = false;
+ status_t err(writeProtoFileLocked());
+ ALOGE_IF(err == PERMISSION_DENIED, "Could not save the proto file! Permission denied");
+ ALOGE_IF(err == NOT_ENOUGH_DATA, "Could not save the proto file! There are missing fields");
+ mTrace.Clear();
+ return err;
+}
+
+bool SurfaceTracing::isEnabled() {
+ return mEnabled;
+}
+
+void SurfaceTracing::traceLayers(const char* where, LayersProto layers) {
+ std::lock_guard<std::mutex> protoGuard(mTraceMutex);
+
+ LayersTraceProto* entry = mTrace.add_entry();
+ entry->set_elapsed_realtime_nanos(elapsedRealtimeNano());
+ entry->set_where(where);
+ entry->mutable_layers()->Swap(&layers);
+}
+
+status_t SurfaceTracing::writeProtoFileLocked() {
+ ATRACE_CALL();
+
+ if (!mTrace.IsInitialized()) {
+ return NOT_ENOUGH_DATA;
+ }
+ std::string output;
+ if (!mTrace.SerializeToString(&output)) {
+ return PERMISSION_DENIED;
+ }
+ if (!android::base::WriteStringToFile(output, mOutputFileName, true)) {
+ return PERMISSION_DENIED;
+ }
+
+ return NO_ERROR;
+}
+
+} // namespace android
diff --git a/services/surfaceflinger/SurfaceTracing.h b/services/surfaceflinger/SurfaceTracing.h
new file mode 100644
index 0000000..9b21989
--- /dev/null
+++ b/services/surfaceflinger/SurfaceTracing.h
@@ -0,0 +1,50 @@
+/*
+ * 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 <layerproto/LayerProtoHeader.h>
+#include <utils/Errors.h>
+
+#include <mutex>
+
+using namespace android::surfaceflinger;
+
+namespace android {
+
+/*
+ * SurfaceTracing records layer states during surface flinging.
+ */
+class SurfaceTracing {
+public:
+ void enable();
+ status_t disable();
+ bool isEnabled();
+
+ void traceLayers(const char* where, LayersProto);
+
+private:
+ static constexpr auto DEFAULT_FILENAME = "/data/misc/trace/layerstrace.pb";
+
+ status_t writeProtoFileLocked();
+
+ bool mEnabled = false;
+ std::string mOutputFileName = DEFAULT_FILENAME;
+ std::mutex mTraceMutex;
+ LayersTraceFileProto mTrace;
+};
+
+} // namespace android
diff --git a/services/surfaceflinger/Transform.cpp b/services/surfaceflinger/Transform.cpp
index 6be9ae2..37925a1 100644
--- a/services/surfaceflinger/Transform.cpp
+++ b/services/surfaceflinger/Transform.cpp
@@ -20,8 +20,8 @@
#include <utils/String8.h>
#include <ui/Region.h>
-#include "clz.h"
#include "Transform.h"
+#include "clz.h"
// ---------------------------------------------------------------------------
@@ -388,6 +388,23 @@
ALOGD("%.4f %.4f %.4f", m[0][2], m[1][2], m[2][2]);
}
+Transform::orientation_flags Transform::fromRotation(ISurfaceComposer::Rotation rotation) {
+ // Convert to surfaceflinger's internal rotation type.
+ switch (rotation) {
+ case ISurfaceComposer::eRotateNone:
+ return Transform::ROT_0;
+ case ISurfaceComposer::eRotate90:
+ return Transform::ROT_90;
+ case ISurfaceComposer::eRotate180:
+ return Transform::ROT_180;
+ case ISurfaceComposer::eRotate270:
+ return Transform::ROT_270;
+ default:
+ ALOGE("Invalid rotation passed to captureScreen(): %d\n", rotation);
+ return Transform::ROT_0;
+ }
+}
+
// ---------------------------------------------------------------------------
}; // namespace android
diff --git a/services/surfaceflinger/Transform.h b/services/surfaceflinger/Transform.h
index 6640a13..bfc66ec 100644
--- a/services/surfaceflinger/Transform.h
+++ b/services/surfaceflinger/Transform.h
@@ -25,6 +25,8 @@
#include <math/vec2.h>
#include <math/vec3.h>
+#include <gui/ISurfaceComposer.h>
+
#include <hardware/hardware.h>
namespace android {
@@ -51,6 +53,8 @@
ROT_INVALID = 0x80
};
+ static orientation_flags fromRotation(ISurfaceComposer::Rotation rotation);
+
enum type_mask {
IDENTITY = 0,
TRANSLATE = 0x1,
diff --git a/services/surfaceflinger/layerproto/Android.bp b/services/surfaceflinger/layerproto/Android.bp
new file mode 100644
index 0000000..8eb218c
--- /dev/null
+++ b/services/surfaceflinger/layerproto/Android.bp
@@ -0,0 +1,36 @@
+cc_library_shared {
+ name: "liblayers_proto",
+ vendor_available: true,
+ export_include_dirs: ["include"],
+
+ srcs: [
+ "LayerProtoParser.cpp",
+ "layers.proto",
+ "layerstrace.proto",
+ ],
+
+ shared_libs: [
+ "libui",
+ "libprotobuf-cpp-lite",
+ "libbase",
+ ],
+
+ proto: {
+ export_proto_headers: true,
+ },
+
+ cppflags: [
+ "-Werror",
+ "-Wno-unused-parameter",
+ "-Wno-format",
+ "-Wno-c++98-compat-pedantic",
+ "-Wno-float-conversion",
+ "-Wno-disabled-macro-expansion",
+ "-Wno-float-equal",
+ "-Wno-sign-conversion",
+ "-Wno-padded",
+ "-Wno-old-style-cast",
+ "-Wno-undef",
+ ],
+
+}
\ No newline at end of file
diff --git a/services/surfaceflinger/layerproto/LayerProtoParser.cpp b/services/surfaceflinger/layerproto/LayerProtoParser.cpp
new file mode 100644
index 0000000..e6f2ce7
--- /dev/null
+++ b/services/surfaceflinger/layerproto/LayerProtoParser.cpp
@@ -0,0 +1,286 @@
+/*
+ * Copyright (C) 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 <android-base/stringprintf.h>
+#include <layerproto/LayerProtoParser.h>
+#include <ui/DebugUtils.h>
+
+using android::base::StringAppendF;
+using android::base::StringPrintf;
+
+namespace android {
+namespace surfaceflinger {
+
+bool sortLayers(const LayerProtoParser::Layer* lhs, const LayerProtoParser::Layer* rhs) {
+ uint32_t ls = lhs->layerStack;
+ uint32_t rs = rhs->layerStack;
+ if (ls != rs) return ls < rs;
+
+ uint32_t lz = lhs->z;
+ uint32_t rz = rhs->z;
+ if (lz != rz) return lz < rz;
+
+ return lhs->id < rhs->id;
+}
+
+std::vector<const LayerProtoParser::Layer*> LayerProtoParser::generateLayerTree(
+ const LayersProto& layersProto) {
+ auto layerMap = generateMap(layersProto);
+
+ std::vector<const Layer*> layers;
+ std::for_each(layerMap.begin(), layerMap.end(),
+ [&](const std::pair<const int32_t, Layer*>& ref) {
+ if (ref.second->parent == nullptr) {
+ // only save top level layers
+ layers.push_back(ref.second);
+ }
+ });
+
+ std::sort(layers.begin(), layers.end(), sortLayers);
+ return layers;
+}
+
+std::unordered_map<int32_t, LayerProtoParser::Layer*> LayerProtoParser::generateMap(
+ const LayersProto& layersProto) {
+ std::unordered_map<int32_t, Layer*> layerMap;
+
+ for (int i = 0; i < layersProto.layers_size(); i++) {
+ const LayerProto& layerProto = layersProto.layers(i);
+ layerMap[layerProto.id()] = generateLayer(layerProto);
+ }
+
+ for (int i = 0; i < layersProto.layers_size(); i++) {
+ const LayerProto& layerProto = layersProto.layers(i);
+ updateChildrenAndRelative(layerProto, layerMap);
+ }
+
+ return layerMap;
+}
+
+LayerProtoParser::Layer* LayerProtoParser::generateLayer(const LayerProto& layerProto) {
+ Layer* layer = new Layer();
+ layer->id = layerProto.id();
+ layer->name = layerProto.name();
+ layer->type = layerProto.type();
+ layer->transparentRegion = generateRegion(layerProto.transparent_region());
+ layer->visibleRegion = generateRegion(layerProto.visible_region());
+ layer->damageRegion = generateRegion(layerProto.damage_region());
+ layer->layerStack = layerProto.layer_stack();
+ layer->z = layerProto.z();
+ layer->position = {layerProto.position().x(), layerProto.position().y()};
+ layer->requestedPosition = {layerProto.requested_position().x(),
+ layerProto.requested_position().y()};
+ layer->size = {layerProto.size().w(), layerProto.size().h()};
+ layer->crop = generateRect(layerProto.crop());
+ layer->finalCrop = generateRect(layerProto.final_crop());
+ layer->isOpaque = layerProto.is_opaque();
+ layer->invalidate = layerProto.invalidate();
+ layer->dataspace = layerProto.dataspace();
+ layer->pixelFormat = layerProto.pixel_format();
+ layer->color = {layerProto.color().r(), layerProto.color().g(), layerProto.color().b(),
+ layerProto.color().a()};
+ layer->requestedColor = {layerProto.requested_color().r(), layerProto.requested_color().g(),
+ layerProto.requested_color().b(), layerProto.requested_color().a()};
+ layer->flags = layerProto.flags();
+ layer->transform = generateTransform(layerProto.transform());
+ layer->requestedTransform = generateTransform(layerProto.requested_transform());
+ layer->activeBuffer = generateActiveBuffer(layerProto.active_buffer());
+ layer->queuedFrames = layerProto.queued_frames();
+ layer->refreshPending = layerProto.refresh_pending();
+
+ return layer;
+}
+
+LayerProtoParser::Region LayerProtoParser::generateRegion(const RegionProto& regionProto) {
+ LayerProtoParser::Region region;
+ region.id = regionProto.id();
+ for (int i = 0; i < regionProto.rect_size(); i++) {
+ const RectProto& rectProto = regionProto.rect(i);
+ region.rects.push_back(generateRect(rectProto));
+ }
+
+ return region;
+}
+
+LayerProtoParser::Rect LayerProtoParser::generateRect(const RectProto& rectProto) {
+ LayerProtoParser::Rect rect;
+ rect.left = rectProto.left();
+ rect.top = rectProto.top();
+ rect.right = rectProto.right();
+ rect.bottom = rectProto.bottom();
+
+ return rect;
+}
+
+LayerProtoParser::Transform LayerProtoParser::generateTransform(
+ const TransformProto& transformProto) {
+ LayerProtoParser::Transform transform;
+ transform.dsdx = transformProto.dsdx();
+ transform.dtdx = transformProto.dtdx();
+ transform.dsdy = transformProto.dsdy();
+ transform.dtdy = transformProto.dtdy();
+
+ return transform;
+}
+
+LayerProtoParser::ActiveBuffer LayerProtoParser::generateActiveBuffer(
+ const ActiveBufferProto& activeBufferProto) {
+ LayerProtoParser::ActiveBuffer activeBuffer;
+ activeBuffer.width = activeBufferProto.width();
+ activeBuffer.height = activeBufferProto.height();
+ activeBuffer.stride = activeBufferProto.stride();
+ activeBuffer.format = activeBufferProto.format();
+
+ return activeBuffer;
+}
+
+void LayerProtoParser::updateChildrenAndRelative(const LayerProto& layerProto,
+ std::unordered_map<int32_t, Layer*>& layerMap) {
+ auto currLayer = layerMap[layerProto.id()];
+
+ for (int i = 0; i < layerProto.children_size(); i++) {
+ if (layerMap.count(layerProto.children(i)) > 0) {
+ auto childLayer = layerMap[layerProto.children(i)];
+ currLayer->children.push_back(childLayer);
+ }
+ }
+
+ for (int i = 0; i < layerProto.relatives_size(); i++) {
+ if (layerMap.count(layerProto.relatives(i)) > 0) {
+ auto relativeLayer = layerMap[layerProto.relatives(i)];
+ currLayer->relatives.push_back(relativeLayer);
+ }
+ }
+
+ if (layerProto.has_parent()) {
+ if (layerMap.count(layerProto.parent()) > 0) {
+ auto parentLayer = layerMap[layerProto.parent()];
+ currLayer->parent = parentLayer;
+ }
+ }
+
+ if (layerProto.has_z_order_relative_of()) {
+ if (layerMap.count(layerProto.z_order_relative_of()) > 0) {
+ auto relativeLayer = layerMap[layerProto.z_order_relative_of()];
+ currLayer->zOrderRelativeOf = relativeLayer;
+ }
+ }
+}
+
+std::string LayerProtoParser::layersToString(
+ const std::vector<const LayerProtoParser::Layer*> layers) {
+ std::string result;
+ for (const LayerProtoParser::Layer* layer : layers) {
+ if (layer->zOrderRelativeOf != nullptr) {
+ continue;
+ }
+ result.append(layerToString(layer).c_str());
+ }
+
+ return result;
+}
+
+std::string LayerProtoParser::layerToString(const LayerProtoParser::Layer* layer) {
+ std::string result;
+
+ std::vector<const Layer*> traverse(layer->relatives);
+ for (const LayerProtoParser::Layer* child : layer->children) {
+ if (child->zOrderRelativeOf != nullptr) {
+ continue;
+ }
+
+ traverse.push_back(child);
+ }
+
+ std::sort(traverse.begin(), traverse.end(), sortLayers);
+
+ size_t i = 0;
+ for (; i < traverse.size(); i++) {
+ const auto& relative = traverse[i];
+ if (relative->z >= 0) {
+ break;
+ }
+ result.append(layerToString(relative).c_str());
+ }
+ result.append(layer->to_string().c_str());
+ result.append("\n");
+ for (; i < traverse.size(); i++) {
+ const auto& relative = traverse[i];
+ result.append(layerToString(relative).c_str());
+ }
+
+ return result;
+}
+
+std::string LayerProtoParser::ActiveBuffer::to_string() const {
+ return StringPrintf("[%4ux%4u:%4u,%s]", width, height, stride,
+ decodePixelFormat(format).c_str());
+}
+
+std::string LayerProtoParser::Transform::to_string() const {
+ return StringPrintf("[%.2f, %.2f][%.2f, %.2f]", static_cast<double>(dsdx),
+ static_cast<double>(dtdx), static_cast<double>(dsdy),
+ static_cast<double>(dtdy));
+}
+
+std::string LayerProtoParser::Rect::to_string() const {
+ return StringPrintf("[%3d, %3d, %3d, %3d]", left, top, right, bottom);
+}
+
+std::string LayerProtoParser::Region::to_string(const char* what) const {
+ std::string result =
+ StringPrintf(" Region %s (this=%lx count=%d)\n", what, static_cast<unsigned long>(id),
+ static_cast<int>(rects.size()));
+
+ for (auto& rect : rects) {
+ StringAppendF(&result, " %s\n", rect.to_string().c_str());
+ }
+
+ return result;
+}
+
+std::string LayerProtoParser::Layer::to_string() const {
+ std::string result;
+ StringAppendF(&result, "+ %s (%s)\n", type.c_str(), name.c_str());
+ result.append(transparentRegion.to_string("TransparentRegion").c_str());
+ result.append(visibleRegion.to_string("VisibleRegion").c_str());
+ result.append(damageRegion.to_string("SurfaceDamageRegion").c_str());
+
+ StringAppendF(&result, " layerStack=%4d, z=%9d, pos=(%g,%g), size=(%4d,%4d), ", layerStack,
+ z, static_cast<double>(position.x), static_cast<double>(position.y), size.x,
+ size.y);
+
+ StringAppendF(&result, "crop=%s, finalCrop=%s, ", crop.to_string().c_str(),
+ finalCrop.to_string().c_str());
+ StringAppendF(&result, "isOpaque=%1d, invalidate=%1d, ", isOpaque, invalidate);
+ StringAppendF(&result, "dataspace=%s, ", dataspace.c_str());
+ StringAppendF(&result, "pixelformat=%s, ", pixelFormat.c_str());
+ StringAppendF(&result, "color=(%.3f,%.3f,%.3f,%.3f), flags=0x%08x, ",
+ static_cast<double>(color.r), static_cast<double>(color.g),
+ static_cast<double>(color.b), static_cast<double>(color.a), flags);
+ StringAppendF(&result, "tr=%s", transform.to_string().c_str());
+ result.append("\n");
+ StringAppendF(&result, " parent=%s\n", parent == nullptr ? "none" : parent->name.c_str());
+ StringAppendF(&result, " zOrderRelativeOf=%s\n",
+ zOrderRelativeOf == nullptr ? "none" : zOrderRelativeOf->name.c_str());
+ StringAppendF(&result, " activeBuffer=%s,", activeBuffer.to_string().c_str());
+ StringAppendF(&result, " queued-frames=%d, mRefreshPending=%d", queuedFrames, refreshPending);
+
+ return result;
+}
+
+} // namespace surfaceflinger
+} // namespace android
diff --git a/services/surfaceflinger/layerproto/include/layerproto/LayerProtoHeader.h b/services/surfaceflinger/layerproto/include/layerproto/LayerProtoHeader.h
new file mode 100644
index 0000000..f560562
--- /dev/null
+++ b/services/surfaceflinger/layerproto/include/layerproto/LayerProtoHeader.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Projectlayerproto/LayerProtoHeader.h
+ *
+ * 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 is used here to disable the warnings emitted from the protobuf
+// headers. By adding #pragma before including layer.pb.h, it supresses
+// protobuf warnings, but allows the rest of the files to continuing using
+// the current flags.
+// This file should be included instead of directly including layer.b.h
+#pragma GCC system_header
+#include <layers.pb.h>
+#include <layerstrace.pb.h>
diff --git a/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h b/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h
new file mode 100644
index 0000000..78c6cd1
--- /dev/null
+++ b/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 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 <layerproto/LayerProtoHeader.h>
+
+#include <math/vec4.h>
+
+#include <unordered_map>
+#include <vector>
+
+namespace android {
+namespace surfaceflinger {
+
+class LayerProtoParser {
+public:
+ class ActiveBuffer {
+ public:
+ uint32_t width;
+ uint32_t height;
+ uint32_t stride;
+ int32_t format;
+
+ std::string to_string() const;
+ };
+
+ class Transform {
+ public:
+ float dsdx;
+ float dtdx;
+ float dsdy;
+ float dtdy;
+
+ std::string to_string() const;
+ };
+
+ class Rect {
+ public:
+ int32_t left;
+ int32_t top;
+ int32_t right;
+ int32_t bottom;
+
+ std::string to_string() const;
+ };
+
+ class Region {
+ public:
+ uint64_t id;
+ std::vector<Rect> rects;
+
+ std::string to_string(const char* what) const;
+ };
+
+ class Layer {
+ public:
+ int32_t id;
+ std::string name;
+ std::vector<const Layer*> children;
+ std::vector<const Layer*> relatives;
+ std::string type;
+ LayerProtoParser::Region transparentRegion;
+ LayerProtoParser::Region visibleRegion;
+ LayerProtoParser::Region damageRegion;
+ uint32_t layerStack;
+ int32_t z;
+ float2 position;
+ float2 requestedPosition;
+ int2 size;
+ LayerProtoParser::Rect crop;
+ LayerProtoParser::Rect finalCrop;
+ bool isOpaque;
+ bool invalidate;
+ std::string dataspace;
+ std::string pixelFormat;
+ half4 color;
+ half4 requestedColor;
+ uint32_t flags;
+ Transform transform;
+ Transform requestedTransform;
+ Layer* parent = 0;
+ Layer* zOrderRelativeOf = 0;
+ LayerProtoParser::ActiveBuffer activeBuffer;
+ int32_t queuedFrames;
+ bool refreshPending;
+
+ std::string to_string() const;
+ };
+
+ static std::vector<const Layer*> generateLayerTree(const LayersProto& layersProto);
+ static std::string layersToString(const std::vector<const LayerProtoParser::Layer*> layers);
+
+private:
+ static std::unordered_map<int32_t, Layer*> generateMap(const LayersProto& layersProto);
+ static LayerProtoParser::Layer* generateLayer(const LayerProto& layerProto);
+ static LayerProtoParser::Region generateRegion(const RegionProto& regionProto);
+ static LayerProtoParser::Rect generateRect(const RectProto& rectProto);
+ static LayerProtoParser::Transform generateTransform(const TransformProto& transformProto);
+ static LayerProtoParser::ActiveBuffer generateActiveBuffer(
+ const ActiveBufferProto& activeBufferProto);
+ static void updateChildrenAndRelative(const LayerProto& layerProto,
+ std::unordered_map<int32_t, Layer*>& layerMap);
+
+ static std::string layerToString(const LayerProtoParser::Layer* layer);
+};
+
+} // namespace surfaceflinger
+} // namespace android
diff --git a/services/surfaceflinger/layerproto/layers.proto b/services/surfaceflinger/layerproto/layers.proto
new file mode 100644
index 0000000..d27dc9b
--- /dev/null
+++ b/services/surfaceflinger/layerproto/layers.proto
@@ -0,0 +1,110 @@
+// Definitions for SurfaceFlinger layers.
+
+syntax = "proto2";
+option optimize_for = LITE_RUNTIME;
+package android.surfaceflinger;
+
+// Contains a list of all layers.
+message LayersProto {
+ repeated LayerProto layers = 1;
+}
+
+// Information about each layer.
+message LayerProto {
+ // unique id per layer.
+ optional int32 id = 1;
+ // unique name per layer.
+ optional string name = 2;
+ // list of children this layer may have. May be empty.
+ repeated int32 children = 3;
+ // list of layers that are z order relative to this layer.
+ repeated int32 relatives = 4;
+ // The type of layer, ex Color, Layer
+ optional string type = 5;
+ optional RegionProto transparent_region = 6;
+ optional RegionProto visible_region = 7;
+ optional RegionProto damage_region = 8;
+ optional uint32 layer_stack = 9;
+ // The layer's z order. Can be z order in layer stack, relative to parent,
+ // or relative to another layer specified in zOrderRelative.
+ optional int32 z = 10;
+ // The layer's position on the display.
+ optional PositionProto position = 11;
+ // The layer's requested position.
+ optional PositionProto requested_position = 12;
+ // The layer's size.
+ optional SizeProto size = 13;
+ // The layer's crop in it's own bounds.
+ optional RectProto crop = 14;
+ // The layer's crop in it's parent's bounds.
+ optional RectProto final_crop = 15;
+ optional bool is_opaque = 16;
+ optional bool invalidate = 17;
+ optional string dataspace = 18;
+ optional string pixel_format = 19;
+ // The layer's actual color.
+ optional ColorProto color = 20;
+ // The layer's requested color.
+ optional ColorProto requested_color = 21;
+ // Can be any combination of
+ // hidden = 0x01
+ // opaque = 0x02,
+ // secure = 0x80,
+ optional uint32 flags = 22;
+ // The layer's actual transform
+ optional TransformProto transform = 23;
+ // The layer's requested transform.
+ optional TransformProto requested_transform = 24;
+ // The parent layer. This value can be null if there is no parent.
+ optional int32 parent = 25 [default = -1];
+ // The layer that this layer has a z order relative to. This value can be null.
+ optional int32 z_order_relative_of = 26 [default = -1];
+ // This value can be null if there's nothing to draw.
+ optional ActiveBufferProto active_buffer = 27;
+ // The number of frames available.
+ optional int32 queued_frames = 28;
+ optional bool refresh_pending = 29;
+}
+
+message PositionProto {
+ optional float x = 1;
+ optional float y = 2;
+}
+
+message SizeProto {
+ optional int32 w = 1;
+ optional int32 h = 2;
+}
+
+message TransformProto {
+ optional float dsdx = 1;
+ optional float dtdx = 2;
+ optional float dsdy = 3;
+ optional float dtdy = 4;
+}
+
+message RegionProto {
+ optional uint64 id = 1;
+ repeated RectProto rect = 2;
+}
+
+message RectProto {
+ optional int32 left = 1;
+ optional int32 top = 2;
+ optional int32 right = 3;
+ optional int32 bottom = 4;
+}
+
+message ActiveBufferProto {
+ optional uint32 width = 1;
+ optional uint32 height = 2;
+ optional uint32 stride = 3;
+ optional int32 format = 4;
+}
+
+message ColorProto {
+ optional float r = 1;
+ optional float g = 2;
+ optional float b = 3;
+ optional float a = 4;
+}
\ No newline at end of file
diff --git a/services/surfaceflinger/layerproto/layerstrace.proto b/services/surfaceflinger/layerproto/layerstrace.proto
new file mode 100644
index 0000000..bee17d2
--- /dev/null
+++ b/services/surfaceflinger/layerproto/layerstrace.proto
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 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.
+ */
+
+syntax = "proto2";
+option optimize_for = LITE_RUNTIME;
+
+import "frameworks/native/services/surfaceflinger/layerproto/layers.proto";
+
+package android.surfaceflinger;
+
+/* represents a file full of surface flinger trace entries.
+ Encoded, it should start with 0x4c 0x59 0x52 0x54 0x52 0x41 0x43 0x45 (.LYRTRACE), such
+ that they can be easily identified. */
+message LayersTraceFileProto {
+
+ /* constant; MAGIC_NUMBER = (long) MAGIC_NUMBER_H << 32 | MagicNumber.MAGIC_NUMBER_L
+ (this is needed because enums have to be 32 bits and there's no nice way to put 64bit
+ constants into .proto files. */
+ enum MagicNumber {
+ INVALID = 0;
+ MAGIC_NUMBER_L = 0x5452594c; /* LYRT (little-endian ASCII) */
+ MAGIC_NUMBER_H = 0x45434152; /* RACE (little-endian ASCII) */
+ }
+
+ optional fixed64 magic_number = 1; /* Must be the first field, set to value in MagicNumber */
+ repeated LayersTraceProto entry = 2;
+}
+
+/* one window manager trace entry. */
+message LayersTraceProto {
+ /* required: elapsed realtime in nanos since boot of when this entry was logged */
+ optional fixed64 elapsed_realtime_nanos = 1;
+
+ /* where the trace originated */
+ optional string where = 2;
+
+ optional LayersProto layers = 3;
+}
diff --git a/services/surfaceflinger/main_surfaceflinger.cpp b/services/surfaceflinger/main_surfaceflinger.cpp
index e50f3ce..2a924ae 100644
--- a/services/surfaceflinger/main_surfaceflinger.cpp
+++ b/services/surfaceflinger/main_surfaceflinger.cpp
@@ -105,7 +105,8 @@
// publish surface flinger
sp<IServiceManager> sm(defaultServiceManager());
- sm->addService(String16(SurfaceFlinger::getServiceName()), flinger, false);
+ sm->addService(String16(SurfaceFlinger::getServiceName()), flinger, false,
+ IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL);
// publish GpuService
sp<GpuService> gpuservice = new GpuService();
diff --git a/services/surfaceflinger/tests/SurfaceFlinger_test.filter b/services/surfaceflinger/tests/SurfaceFlinger_test.filter
index 915b5cd..5c188dc 100644
--- a/services/surfaceflinger/tests/SurfaceFlinger_test.filter
+++ b/services/surfaceflinger/tests/SurfaceFlinger_test.filter
@@ -1,5 +1,5 @@
{
"presubmit": {
- "filter": "LayerUpdateTest.*:ChildLayerTest.*:SurfaceFlingerStress.*"
+ "filter": "LayerUpdateTest.*:ChildLayerTest.*:SurfaceFlingerStress.*:CropLatchingTest.*:GeometryLatchingTest.*:LayerColorTest.*"
}
}
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
index 0cc763c..ed806b8 100644
--- a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
+++ b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
@@ -22,10 +22,11 @@
#include <android/native_window.h>
#include <gui/ISurfaceComposer.h>
+#include <gui/LayerState.h>
#include <gui/Surface.h>
#include <gui/SurfaceComposerClient.h>
+
#include <private/gui/ComposerService.h>
-#include <private/gui/LayerState.h>
#include <ui/DisplayInfo.h>
#include <fstream>
@@ -34,6 +35,8 @@
namespace android {
+using Transaction = SurfaceComposerClient::Transaction;
+
constexpr int32_t SCALING_UPDATE = 1;
constexpr uint32_t BUFFER_UPDATES = 18;
constexpr uint32_t LAYER_UPDATE = INT_MAX - 2;
@@ -149,11 +152,11 @@
ASSERT_TRUE(mBGSurfaceControl->isValid());
mBGLayerId = getSurfaceId("BG Interceptor Test Surface");
- SurfaceComposerClient::openGlobalTransaction();
- mComposerClient->setDisplayLayerStack(display, 0);
- ASSERT_EQ(NO_ERROR, mBGSurfaceControl->setLayer(INT_MAX-3));
- ASSERT_EQ(NO_ERROR, mBGSurfaceControl->show());
- SurfaceComposerClient::closeGlobalTransaction(true);
+ Transaction t;
+ t.setDisplayLayerStack(display, 0);
+ ASSERT_EQ(NO_ERROR, t.setLayer(mBGSurfaceControl, INT_MAX-3)
+ .show(mBGSurfaceControl)
+ .apply());
}
virtual void TearDown() {
@@ -169,13 +172,14 @@
int32_t mTargetId;
public:
- void captureTest(void (SurfaceInterceptorTest::* action)(void),
+ void captureTest(void (SurfaceInterceptorTest::* action)(Transaction&),
bool (SurfaceInterceptorTest::* verification)(Trace *));
- void captureTest(void (SurfaceInterceptorTest::* action)(void),
+ void captureTest(void (SurfaceInterceptorTest::* action)(Transaction&),
SurfaceChange::SurfaceChangeCase changeCase);
- void captureTest(void (SurfaceInterceptorTest::* action)(void),
+ void captureTest(void (SurfaceInterceptorTest::* action)(Transaction&),
Increment::IncrementCase incrementCase);
- void runInTransaction(void (SurfaceInterceptorTest::* action)(void), bool intercepted = false);
+ void runInTransaction(void (SurfaceInterceptorTest::* action)(Transaction&),
+ bool intercepted = false);
// Verification of changes to a surface
bool positionUpdateFound(const SurfaceChange& change, bool foundPosition);
@@ -206,28 +210,29 @@
bool bufferUpdatesFound(Trace* trace);
// Perform each of the possible changes to a surface
- void positionUpdate();
- void sizeUpdate();
- void alphaUpdate();
- void layerUpdate();
- void cropUpdate();
- void finalCropUpdate();
- void matrixUpdate();
- void overrideScalingModeUpdate();
- void transparentRegionHintUpdate();
- void layerStackUpdate();
- void hiddenFlagUpdate();
- void opaqueFlagUpdate();
- void secureFlagUpdate();
- void deferredTransactionUpdate();
- void runAllUpdates();
- void surfaceCreation();
+ void positionUpdate(Transaction&);
+ void sizeUpdate(Transaction&);
+ void alphaUpdate(Transaction&);
+ void layerUpdate(Transaction&);
+ void cropUpdate(Transaction&);
+ void finalCropUpdate(Transaction&);
+ void matrixUpdate(Transaction&);
+ void overrideScalingModeUpdate(Transaction&);
+ void transparentRegionHintUpdate(Transaction&);
+ void layerStackUpdate(Transaction&);
+ void hiddenFlagUpdate(Transaction&);
+ void opaqueFlagUpdate(Transaction&);
+ void secureFlagUpdate(Transaction&);
+ void deferredTransactionUpdate(Transaction&);
+ void surfaceCreation(Transaction&);
+ void displayCreation(Transaction&);
+ void displayDeletion(Transaction&);
+
void nBufferUpdates();
- void displayCreation();
- void displayDeletion();
+ void runAllUpdates();
};
-void SurfaceInterceptorTest::captureTest(void (SurfaceInterceptorTest::* action)(void),
+void SurfaceInterceptorTest::captureTest(void (SurfaceInterceptorTest::* action)(Transaction&),
bool (SurfaceInterceptorTest::* verification)(Trace *))
{
runInTransaction(action, true);
@@ -236,7 +241,7 @@
ASSERT_TRUE((this->*verification)(&capturedTrace));
}
-void SurfaceInterceptorTest::captureTest(void (SurfaceInterceptorTest::* action)(void),
+void SurfaceInterceptorTest::captureTest(void (SurfaceInterceptorTest::* action)(Transaction&),
Increment::IncrementCase incrementCase)
{
runInTransaction(action, true);
@@ -245,7 +250,7 @@
ASSERT_TRUE(singleIncrementFound(&capturedTrace, incrementCase));
}
-void SurfaceInterceptorTest::captureTest(void (SurfaceInterceptorTest::* action)(void),
+void SurfaceInterceptorTest::captureTest(void (SurfaceInterceptorTest::* action)(Transaction&),
SurfaceChange::SurfaceChangeCase changeCase)
{
runInTransaction(action, true);
@@ -254,83 +259,84 @@
ASSERT_TRUE(surfaceUpdateFound(&capturedTrace, changeCase));
}
-void SurfaceInterceptorTest::runInTransaction(void (SurfaceInterceptorTest::* action)(void),
+void SurfaceInterceptorTest::runInTransaction(void (SurfaceInterceptorTest::* action)(Transaction&),
bool intercepted)
{
if (intercepted) {
enableInterceptor();
}
- SurfaceComposerClient::openGlobalTransaction();
- (this->*action)();
- SurfaceComposerClient::closeGlobalTransaction(true);
+ Transaction t;
+ (this->*action)(t);
+ t.apply(true);
+
if (intercepted) {
disableInterceptor();
}
}
-void SurfaceInterceptorTest::positionUpdate() {
- mBGSurfaceControl->setPosition(POSITION_UPDATE, POSITION_UPDATE);
+void SurfaceInterceptorTest::positionUpdate(Transaction& t) {
+ t.setPosition(mBGSurfaceControl, POSITION_UPDATE, POSITION_UPDATE);
}
-void SurfaceInterceptorTest::sizeUpdate() {
- mBGSurfaceControl->setSize(SIZE_UPDATE, SIZE_UPDATE);
+void SurfaceInterceptorTest::sizeUpdate(Transaction& t) {
+ t.setSize(mBGSurfaceControl, SIZE_UPDATE, SIZE_UPDATE);
}
-void SurfaceInterceptorTest::alphaUpdate() {
- mBGSurfaceControl->setAlpha(ALPHA_UPDATE);
+void SurfaceInterceptorTest::alphaUpdate(Transaction& t) {
+ t.setAlpha(mBGSurfaceControl, ALPHA_UPDATE);
}
-void SurfaceInterceptorTest::layerUpdate() {
- mBGSurfaceControl->setLayer(LAYER_UPDATE);
+void SurfaceInterceptorTest::layerUpdate(Transaction& t) {
+ t.setLayer(mBGSurfaceControl, LAYER_UPDATE);
}
-void SurfaceInterceptorTest::cropUpdate() {
- mBGSurfaceControl->setCrop(CROP_UPDATE);
+void SurfaceInterceptorTest::cropUpdate(Transaction& t) {
+ t.setCrop(mBGSurfaceControl, CROP_UPDATE);
}
-void SurfaceInterceptorTest::finalCropUpdate() {
- mBGSurfaceControl->setFinalCrop(CROP_UPDATE);
+void SurfaceInterceptorTest::finalCropUpdate(Transaction& t) {
+ t.setFinalCrop(mBGSurfaceControl, CROP_UPDATE);
}
-void SurfaceInterceptorTest::matrixUpdate() {
- mBGSurfaceControl->setMatrix(M_SQRT1_2, M_SQRT1_2, -M_SQRT1_2, M_SQRT1_2);
+void SurfaceInterceptorTest::matrixUpdate(Transaction& t) {
+ t.setMatrix(mBGSurfaceControl, M_SQRT1_2, M_SQRT1_2, -M_SQRT1_2, M_SQRT1_2);
}
-void SurfaceInterceptorTest::overrideScalingModeUpdate() {
- mBGSurfaceControl->setOverrideScalingMode(SCALING_UPDATE);
+void SurfaceInterceptorTest::overrideScalingModeUpdate(Transaction& t) {
+ t.setOverrideScalingMode(mBGSurfaceControl, SCALING_UPDATE);
}
-void SurfaceInterceptorTest::transparentRegionHintUpdate() {
+void SurfaceInterceptorTest::transparentRegionHintUpdate(Transaction& t) {
Region region(CROP_UPDATE);
- mBGSurfaceControl->setTransparentRegionHint(region);
+ t.setTransparentRegionHint(mBGSurfaceControl, region);
}
-void SurfaceInterceptorTest::layerStackUpdate() {
- mBGSurfaceControl->setLayerStack(STACK_UPDATE);
+void SurfaceInterceptorTest::layerStackUpdate(Transaction& t) {
+ t.setLayerStack(mBGSurfaceControl, STACK_UPDATE);
}
-void SurfaceInterceptorTest::hiddenFlagUpdate() {
- mBGSurfaceControl->setFlags(layer_state_t::eLayerHidden, layer_state_t::eLayerHidden);
+void SurfaceInterceptorTest::hiddenFlagUpdate(Transaction& t) {
+ t.setFlags(mBGSurfaceControl, layer_state_t::eLayerHidden, layer_state_t::eLayerHidden);
}
-void SurfaceInterceptorTest::opaqueFlagUpdate() {
- mBGSurfaceControl->setFlags(layer_state_t::eLayerOpaque, layer_state_t::eLayerOpaque);
+void SurfaceInterceptorTest::opaqueFlagUpdate(Transaction& t) {
+ t.setFlags(mBGSurfaceControl, layer_state_t::eLayerOpaque, layer_state_t::eLayerOpaque);
}
-void SurfaceInterceptorTest::secureFlagUpdate() {
- mBGSurfaceControl->setFlags(layer_state_t::eLayerSecure, layer_state_t::eLayerSecure);
+void SurfaceInterceptorTest::secureFlagUpdate(Transaction& t) {
+ t.setFlags(mBGSurfaceControl, layer_state_t::eLayerSecure, layer_state_t::eLayerSecure);
}
-void SurfaceInterceptorTest::deferredTransactionUpdate() {
- mBGSurfaceControl->deferTransactionUntil(mBGSurfaceControl->getHandle(), DEFERRED_UPDATE);
+void SurfaceInterceptorTest::deferredTransactionUpdate(Transaction& t) {
+ t.deferTransactionUntil(mBGSurfaceControl, mBGSurfaceControl->getHandle(), DEFERRED_UPDATE);
}
-void SurfaceInterceptorTest::displayCreation() {
+void SurfaceInterceptorTest::displayCreation(Transaction&) {
sp<IBinder> testDisplay = SurfaceComposerClient::createDisplay(DISPLAY_NAME, true);
SurfaceComposerClient::destroyDisplay(testDisplay);
}
-void SurfaceInterceptorTest::displayDeletion() {
+void SurfaceInterceptorTest::displayDeletion(Transaction&) {
sp<IBinder> testDisplay = SurfaceComposerClient::createDisplay(DISPLAY_NAME, false);
mTargetId = getDisplayId(DISPLAY_NAME.string());
SurfaceComposerClient::destroyDisplay(testDisplay);
@@ -353,7 +359,7 @@
runInTransaction(&SurfaceInterceptorTest::deferredTransactionUpdate);
}
-void SurfaceInterceptorTest::surfaceCreation() {
+void SurfaceInterceptorTest::surfaceCreation(Transaction&) {
mComposerClient->createSurface(String8(LAYER_NAME), SIZE_UPDATE, SIZE_UPDATE,
PIXEL_FORMAT_RGBA_8888, 0);
}
@@ -825,8 +831,10 @@
}
TEST_F(SurfaceInterceptorTest, InterceptBufferUpdateWorks) {
- captureTest(&SurfaceInterceptorTest::nBufferUpdates,
- &SurfaceInterceptorTest::bufferUpdatesFound);
+ nBufferUpdates();
+ Trace capturedTrace;
+ ASSERT_EQ(NO_ERROR, readProtoFile(&capturedTrace));
+ ASSERT_TRUE(bufferUpdatesFound(&capturedTrace));
}
// If the interceptor is enabled while buffer updates are being pushed, the interceptor should
diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp
index 68519a1..16a16a5 100644
--- a/services/surfaceflinger/tests/Transaction_test.cpp
+++ b/services/surfaceflinger/tests/Transaction_test.cpp
@@ -19,18 +19,24 @@
#include <android/native_window.h>
#include <gui/ISurfaceComposer.h>
+#include <gui/LayerState.h>
+
#include <gui/Surface.h>
#include <gui/SurfaceComposerClient.h>
#include <private/gui/ComposerService.h>
-#include <private/gui/LayerState.h>
#include <utils/String8.h>
#include <ui/DisplayInfo.h>
#include <math.h>
+#include <math/vec3.h>
+
+#include <functional>
namespace android {
+using Transaction = SurfaceComposerClient::Transaction;
+
// Fill an RGBA_8888 formatted surface with a single color.
static void fillSurfaceRGBA8(const sp<SurfaceControl>& sc,
uint8_t r, uint8_t g, uint8_t b, bool unlock=true) {
@@ -65,8 +71,8 @@
sp<ISurfaceComposer> sf(ComposerService::getComposerService());
sp<IBinder> display(sf->getBuiltInDisplay(
ISurfaceComposer::eDisplayIdMain));
- SurfaceComposerClient::openGlobalTransaction();
- SurfaceComposerClient::closeGlobalTransaction(true);
+ SurfaceComposerClient::Transaction().apply(true);
+
ASSERT_EQ(NO_ERROR, sf->captureScreen(display, producer, Rect(), 0, 0,
0, INT_MAX, false));
*sc = new ScreenCapture(cpuConsumer);
@@ -110,6 +116,60 @@
CpuConsumer::LockedBuffer mBuf;
};
+class CaptureLayer {
+public:
+ static void captureScreen(std::unique_ptr<CaptureLayer>* sc, sp<IBinder>& parentHandle) {
+ 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));
+ *sc = std::make_unique<CaptureLayer>(cpuConsumer);
+ }
+
+ void checkPixel(uint32_t x, uint32_t y, uint8_t r, uint8_t g, uint8_t b) {
+ ASSERT_EQ(HAL_PIXEL_FORMAT_RGBA_8888, mBuffer.format);
+ const uint8_t* img = static_cast<const uint8_t*>(mBuffer.data);
+ const uint8_t* pixel = img + (4 * (y * mBuffer.stride + x));
+ if (r != pixel[0] || g != pixel[1] || b != pixel[2]) {
+ String8 err(String8::format("pixel @ (%3d, %3d): "
+ "expected [%3d, %3d, %3d], got [%3d, %3d, %3d]",
+ x, y, r, g, b, pixel[0], pixel[1], pixel[2]));
+ EXPECT_EQ(String8(), err) << err.string();
+ }
+ }
+
+ void expectFGColor(uint32_t x, uint32_t y) {
+ checkPixel(x, y, 195, 63, 63);
+ }
+
+ void expectBGColor(uint32_t x, uint32_t y) {
+ checkPixel(x, y, 63, 63, 195);
+ }
+
+ void expectChildColor(uint32_t x, uint32_t y) {
+ checkPixel(x, y, 200, 200, 200);
+ }
+
+ CaptureLayer(const sp<CpuConsumer>& cc) :
+ mCC(cc) {
+ EXPECT_EQ(NO_ERROR, mCC->lockNextBuffer(&mBuffer));
+ }
+
+ ~CaptureLayer() {
+ mCC->unlockBuffer(mBuffer);
+ }
+
+private:
+ sp<CpuConsumer> mCC;
+ CpuConsumer::LockedBuffer mBuffer;
+};
+
+
class LayerUpdateTest : public ::testing::Test {
protected:
virtual void SetUp() {
@@ -148,23 +208,21 @@
fillSurfaceRGBA8(mSyncSurfaceControl, 31, 31, 31);
- SurfaceComposerClient::openGlobalTransaction();
+ asTransaction([&](Transaction& t) {
+ t.setDisplayLayerStack(display, 0);
- mComposerClient->setDisplayLayerStack(display, 0);
+ t.setLayer(mBGSurfaceControl, INT32_MAX-2)
+ .show(mBGSurfaceControl);
- ASSERT_EQ(NO_ERROR, mBGSurfaceControl->setLayer(INT32_MAX-2));
- ASSERT_EQ(NO_ERROR, mBGSurfaceControl->show());
+ t.setLayer(mFGSurfaceControl, INT32_MAX-1)
+ .setPosition(mFGSurfaceControl, 64, 64)
+ .show(mFGSurfaceControl);
- ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setLayer(INT32_MAX-1));
- ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setPosition(64, 64));
- ASSERT_EQ(NO_ERROR, mFGSurfaceControl->show());
-
- ASSERT_EQ(NO_ERROR, mSyncSurfaceControl->setLayer(INT32_MAX-1));
- ASSERT_EQ(NO_ERROR, mSyncSurfaceControl->setPosition(displayWidth-2,
- displayHeight-2));
- ASSERT_EQ(NO_ERROR, mSyncSurfaceControl->show());
-
- SurfaceComposerClient::closeGlobalTransaction(true);
+ t.setLayer(mSyncSurfaceControl, INT32_MAX-1)
+ .setPosition(mSyncSurfaceControl, displayWidth-2,
+ displayHeight-2)
+ .show(mSyncSurfaceControl);
+ });
}
virtual void TearDown() {
@@ -185,6 +243,12 @@
fillSurfaceRGBA8(mSyncSurfaceControl, 31, 31, 31);
}
+ void asTransaction(const std::function<void(Transaction&)>& exec) {
+ Transaction t;
+ exec(t);
+ t.apply(true);
+ }
+
sp<SurfaceComposerClient> mComposerClient;
sp<SurfaceControl> mBGSurfaceControl;
sp<SurfaceControl> mFGSurfaceControl;
@@ -204,9 +268,10 @@
sc->expectBGColor(145, 145);
}
- SurfaceComposerClient::openGlobalTransaction();
- ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setPosition(128, 128));
- SurfaceComposerClient::closeGlobalTransaction(true);
+ asTransaction([&](Transaction& t) {
+ t.setPosition(mFGSurfaceControl, 128, 128);
+ });
+
{
// This should reflect the new position, but not the new color.
SCOPED_TRACE("after move, before redraw");
@@ -239,9 +304,9 @@
}
ALOGD("resizing");
- SurfaceComposerClient::openGlobalTransaction();
- ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setSize(128, 128));
- SurfaceComposerClient::closeGlobalTransaction(true);
+ asTransaction([&](Transaction& t) {
+ t.setSize(mFGSurfaceControl, 128, 128);
+ });
ALOGD("resized");
{
// This should not reflect the new size or color because SurfaceFlinger
@@ -277,10 +342,10 @@
sc->expectBGColor(145, 145);
}
- SurfaceComposerClient::openGlobalTransaction();
- Rect cropRect(16, 16, 32, 32);
- ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setCrop(cropRect));
- SurfaceComposerClient::closeGlobalTransaction(true);
+ asTransaction([&](Transaction& t) {
+ Rect cropRect(16, 16, 32, 32);
+ t.setCrop(mFGSurfaceControl, cropRect);
+ });
{
// This should crop the foreground surface.
SCOPED_TRACE("after crop");
@@ -302,10 +367,10 @@
sc->expectFGColor(75, 75);
sc->expectBGColor(145, 145);
}
- SurfaceComposerClient::openGlobalTransaction();
- Rect cropRect(16, 16, 32, 32);
- ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setFinalCrop(cropRect));
- SurfaceComposerClient::closeGlobalTransaction(true);
+ asTransaction([&](Transaction& t) {
+ Rect cropRect(16, 16, 32, 32);
+ t.setFinalCrop(mFGSurfaceControl, cropRect);
+ });
{
// This should crop the foreground surface.
SCOPED_TRACE("after crop");
@@ -328,9 +393,10 @@
sc->expectBGColor(145, 145);
}
- SurfaceComposerClient::openGlobalTransaction();
- ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setLayer(INT_MAX - 3));
- SurfaceComposerClient::closeGlobalTransaction(true);
+ asTransaction([&](Transaction& t) {
+ t.setLayer(mFGSurfaceControl, INT_MAX - 3);
+ });
+
{
// This should hide the foreground surface beneath the background.
SCOPED_TRACE("after setLayer");
@@ -351,9 +417,10 @@
sc->expectBGColor(145, 145);
}
- SurfaceComposerClient::openGlobalTransaction();
- ASSERT_EQ(NO_ERROR, mFGSurfaceControl->hide());
- SurfaceComposerClient::closeGlobalTransaction(true);
+ asTransaction([&](Transaction& t) {
+ t.hide(mFGSurfaceControl);
+ });
+
{
// This should hide the foreground surface.
SCOPED_TRACE("after hide, before show");
@@ -363,9 +430,10 @@
sc->expectBGColor(145, 145);
}
- SurfaceComposerClient::openGlobalTransaction();
- ASSERT_EQ(NO_ERROR, mFGSurfaceControl->show());
- SurfaceComposerClient::closeGlobalTransaction(true);
+ asTransaction([&](Transaction& t) {
+ t.show(mFGSurfaceControl);
+ });
+
{
// This should show the foreground surface.
SCOPED_TRACE("after show");
@@ -386,9 +454,10 @@
sc->expectBGColor(145, 145);
}
- SurfaceComposerClient::openGlobalTransaction();
- ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setAlpha(0.75f));
- SurfaceComposerClient::closeGlobalTransaction(true);
+ asTransaction([&](Transaction& t) {
+ t.setAlpha(mFGSurfaceControl, 0.75f);
+ });
+
{
// This should set foreground to be 75% opaque.
SCOPED_TRACE("after setAlpha");
@@ -409,9 +478,9 @@
sc->expectBGColor(145, 145);
}
- SurfaceComposerClient::openGlobalTransaction();
- ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setLayerStack(1));
- SurfaceComposerClient::closeGlobalTransaction(true);
+ asTransaction([&](Transaction& t) {
+ t.setLayerStack(mFGSurfaceControl, 1);
+ });
{
// This should hide the foreground surface since it goes to a different
// layer stack.
@@ -433,10 +502,10 @@
sc->expectBGColor(145, 145);
}
- SurfaceComposerClient::openGlobalTransaction();
- ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setFlags(
- layer_state_t::eLayerHidden, layer_state_t::eLayerHidden));
- SurfaceComposerClient::closeGlobalTransaction(true);
+ asTransaction([&](Transaction& t) {
+ t.setFlags(mFGSurfaceControl,
+ layer_state_t::eLayerHidden, layer_state_t::eLayerHidden);
+ });
{
// This should hide the foreground surface
SCOPED_TRACE("after setFlags");
@@ -458,10 +527,11 @@
sc->expectBGColor(145, 145);
}
- SurfaceComposerClient::openGlobalTransaction();
- ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setMatrix(M_SQRT1_2, M_SQRT1_2,
- -M_SQRT1_2, M_SQRT1_2));
- SurfaceComposerClient::closeGlobalTransaction(true);
+ asTransaction([&](Transaction& t) {
+ t.setMatrix(mFGSurfaceControl,
+ M_SQRT1_2, M_SQRT1_2,
+ -M_SQRT1_2, M_SQRT1_2);
+ });
{
SCOPED_TRACE("after setMatrix");
ScreenCapture::captureScreen(&sc);
@@ -497,12 +567,12 @@
waitForPostedBuffers();
}
void restoreInitialState() {
- SurfaceComposerClient::openGlobalTransaction();
- mFGSurfaceControl->setSize(64, 64);
- mFGSurfaceControl->setPosition(64, 64);
- mFGSurfaceControl->setCrop(Rect(0, 0, 64, 64));
- mFGSurfaceControl->setFinalCrop(Rect(0, 0, -1, -1));
- SurfaceComposerClient::closeGlobalTransaction(true);
+ asTransaction([&](Transaction& t) {
+ t.setSize(mFGSurfaceControl, 64, 64);
+ t.setPosition(mFGSurfaceControl, 64, 64);
+ t.setCrop(mFGSurfaceControl, Rect(0, 0, 64, 64));
+ t.setFinalCrop(mFGSurfaceControl, Rect(0, 0, -1, -1));
+ });
EXPECT_INITIAL_STATE("After restoring initial state");
}
@@ -514,10 +584,10 @@
// By default position can be updated even while
// a resize is pending.
- SurfaceComposerClient::openGlobalTransaction();
- mFGSurfaceControl->setSize(32, 32);
- mFGSurfaceControl->setPosition(100, 100);
- SurfaceComposerClient::closeGlobalTransaction(true);
+ asTransaction([&](Transaction& t) {
+ t.setSize(mFGSurfaceControl, 32, 32);
+ t.setPosition(mFGSurfaceControl, 100, 100);
+ });
{
SCOPED_TRACE("After moving surface");
@@ -531,11 +601,11 @@
// Now we repeat with setGeometryAppliesWithResize
// and verify the position DOESN'T latch.
- SurfaceComposerClient::openGlobalTransaction();
- mFGSurfaceControl->setGeometryAppliesWithResize();
- mFGSurfaceControl->setSize(32, 32);
- mFGSurfaceControl->setPosition(100, 100);
- SurfaceComposerClient::closeGlobalTransaction(true);
+ asTransaction([&](Transaction& t) {
+ t.setGeometryAppliesWithResize(mFGSurfaceControl);
+ t.setSize(mFGSurfaceControl, 32, 32);
+ t.setPosition(mFGSurfaceControl, 100, 100);
+ });
{
SCOPED_TRACE("While resize is pending");
@@ -566,25 +636,34 @@
sc->expectBGColor(127, 127);
sc->expectBGColor(128, 128);
}
+
+ void EXPECT_RESIZE_STATE(const char* trace) {
+ SCOPED_TRACE(trace);
+ ScreenCapture::captureScreen(&sc);
+ // The FG is now resized too 128,128 at 64,64
+ sc->expectFGColor(64, 64);
+ sc->expectFGColor(191, 191);
+ sc->expectBGColor(192, 192);
+ }
};
TEST_F(CropLatchingTest, CropLatching) {
EXPECT_INITIAL_STATE("before anything");
// Normally the crop applies immediately even while a resize is pending.
- SurfaceComposerClient::openGlobalTransaction();
- mFGSurfaceControl->setSize(128, 128);
- mFGSurfaceControl->setCrop(Rect(0, 0, 63, 63));
- SurfaceComposerClient::closeGlobalTransaction(true);
+ asTransaction([&](Transaction& t) {
+ t.setSize(mFGSurfaceControl, 128, 128);
+ t.setCrop(mFGSurfaceControl, Rect(0, 0, 63, 63));
+ });
EXPECT_CROPPED_STATE("after setting crop (without geometryAppliesWithResize)");
restoreInitialState();
- SurfaceComposerClient::openGlobalTransaction();
- mFGSurfaceControl->setSize(128, 128);
- mFGSurfaceControl->setGeometryAppliesWithResize();
- mFGSurfaceControl->setCrop(Rect(0, 0, 63, 63));
- SurfaceComposerClient::closeGlobalTransaction(true);
+ asTransaction([&](Transaction& t) {
+ t.setSize(mFGSurfaceControl, 128, 128);
+ t.setGeometryAppliesWithResize(mFGSurfaceControl);
+ t.setCrop(mFGSurfaceControl, Rect(0, 0, 63, 63));
+ });
EXPECT_INITIAL_STATE("after setting crop (with geometryAppliesWithResize)");
@@ -596,20 +675,20 @@
TEST_F(CropLatchingTest, FinalCropLatching) {
EXPECT_INITIAL_STATE("before anything");
// Normally the crop applies immediately even while a resize is pending.
- SurfaceComposerClient::openGlobalTransaction();
- mFGSurfaceControl->setSize(128, 128);
- mFGSurfaceControl->setFinalCrop(Rect(64, 64, 127, 127));
- SurfaceComposerClient::closeGlobalTransaction(true);
+ asTransaction([&](Transaction& t) {
+ t.setSize(mFGSurfaceControl, 128, 128);
+ t.setFinalCrop(mFGSurfaceControl, Rect(64, 64, 127, 127));
+ });
EXPECT_CROPPED_STATE("after setting crop (without geometryAppliesWithResize)");
restoreInitialState();
- SurfaceComposerClient::openGlobalTransaction();
- mFGSurfaceControl->setSize(128, 128);
- mFGSurfaceControl->setGeometryAppliesWithResize();
- mFGSurfaceControl->setFinalCrop(Rect(64, 64, 127, 127));
- SurfaceComposerClient::closeGlobalTransaction(true);
+ asTransaction([&](Transaction& t) {
+ t.setSize(mFGSurfaceControl, 128, 128);
+ t.setGeometryAppliesWithResize(mFGSurfaceControl);
+ t.setFinalCrop(mFGSurfaceControl, Rect(64, 64, 127, 127));
+ });
EXPECT_INITIAL_STATE("after setting crop (with geometryAppliesWithResize)");
@@ -623,10 +702,10 @@
TEST_F(CropLatchingTest, FinalCropLatchingBufferOldSize) {
EXPECT_INITIAL_STATE("before anything");
// Normally the crop applies immediately even while a resize is pending.
- SurfaceComposerClient::openGlobalTransaction();
- mFGSurfaceControl->setSize(128, 128);
- mFGSurfaceControl->setFinalCrop(Rect(64, 64, 127, 127));
- SurfaceComposerClient::closeGlobalTransaction(true);
+ asTransaction([&](Transaction& t) {
+ t.setSize(mFGSurfaceControl, 128, 128);
+ t.setFinalCrop(mFGSurfaceControl, Rect(64, 64, 127, 127));
+ });
EXPECT_CROPPED_STATE("after setting crop (without geometryAppliesWithResize)");
@@ -636,11 +715,11 @@
// initiating the resize.
lockAndFillFGBuffer();
- SurfaceComposerClient::openGlobalTransaction();
- mFGSurfaceControl->setSize(128, 128);
- mFGSurfaceControl->setGeometryAppliesWithResize();
- mFGSurfaceControl->setFinalCrop(Rect(64, 64, 127, 127));
- SurfaceComposerClient::closeGlobalTransaction(true);
+ asTransaction([&](Transaction& t) {
+ t.setSize(mFGSurfaceControl, 128, 128);
+ t.setGeometryAppliesWithResize(mFGSurfaceControl);
+ t.setFinalCrop(mFGSurfaceControl, Rect(64, 64, 127, 127));
+ });
EXPECT_INITIAL_STATE("after setting crop (with geometryAppliesWithResize)");
@@ -660,21 +739,23 @@
// In this scenario, we attempt to set the final crop a second time while the resize
// is still pending, and ensure we are successful. Success meaning the second crop
// is the one which eventually latches and not the first.
- SurfaceComposerClient::openGlobalTransaction();
- mFGSurfaceControl->setSize(128, 128);
- mFGSurfaceControl->setGeometryAppliesWithResize();
- mFGSurfaceControl->setFinalCrop(Rect(64, 64, 127, 127));
- SurfaceComposerClient::closeGlobalTransaction(true);
-
- SurfaceComposerClient::openGlobalTransaction();
- mFGSurfaceControl->setFinalCrop(Rect(0, 0, -1, -1));
- SurfaceComposerClient::closeGlobalTransaction(true);
+ asTransaction([&](Transaction& t) {
+ t.setSize(mFGSurfaceControl, 128, 128);
+ t.setGeometryAppliesWithResize(mFGSurfaceControl);
+ t.setFinalCrop(mFGSurfaceControl, Rect(64, 64, 127, 127));
+ });
EXPECT_INITIAL_STATE("after setting crops with geometryAppliesWithResize");
+ asTransaction([&](Transaction& t) {
+ t.setFinalCrop(mFGSurfaceControl, Rect(0, 0, -1, -1));
+ });
+
+ EXPECT_INITIAL_STATE("after setting another crop");
+
completeFGResize();
- EXPECT_INITIAL_STATE("after the resize finishes");
+ EXPECT_RESIZE_STATE("after the resize finishes");
}
TEST_F(LayerUpdateTest, DeferredTransactionTest) {
@@ -688,17 +769,17 @@
}
// set up two deferred transactions on different frames
- SurfaceComposerClient::openGlobalTransaction();
- ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setAlpha(0.75));
- mFGSurfaceControl->deferTransactionUntil(mSyncSurfaceControl->getHandle(),
- mSyncSurfaceControl->getSurface()->getNextFrameNumber());
- SurfaceComposerClient::closeGlobalTransaction(true);
+ asTransaction([&](Transaction& t) {
+ t.setAlpha(mFGSurfaceControl, 0.75);
+ t.deferTransactionUntil(mFGSurfaceControl, mSyncSurfaceControl->getHandle(),
+ mSyncSurfaceControl->getSurface()->getNextFrameNumber());
+ });
- SurfaceComposerClient::openGlobalTransaction();
- ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setPosition(128,128));
- mFGSurfaceControl->deferTransactionUntil(mSyncSurfaceControl->getHandle(),
- mSyncSurfaceControl->getSurface()->getNextFrameNumber() + 1);
- SurfaceComposerClient::closeGlobalTransaction(true);
+ asTransaction([&](Transaction& t) {
+ t.setPosition(mFGSurfaceControl, 128,128);
+ t.deferTransactionUntil(mFGSurfaceControl, mSyncSurfaceControl->getHandle(),
+ mSyncSurfaceControl->getSurface()->getNextFrameNumber() + 1);
+ });
{
SCOPED_TRACE("before any trigger");
@@ -719,9 +800,9 @@
}
// should show up immediately since it's not deferred
- SurfaceComposerClient::openGlobalTransaction();
- ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setAlpha(1.0));
- SurfaceComposerClient::closeGlobalTransaction(true);
+ asTransaction([&](Transaction& t) {
+ t.setAlpha(mFGSurfaceControl, 1.0);
+ });
// trigger the second deferred transaction
fillSurfaceRGBA8(mSyncSurfaceControl, 31, 31, 31);
@@ -750,12 +831,11 @@
waitForPostedBuffers();
// Now we stack the surface above the foreground surface and make sure it is visible.
- SurfaceComposerClient::openGlobalTransaction();
- relativeSurfaceControl->setPosition(64, 64);
- relativeSurfaceControl->show();
- relativeSurfaceControl->setRelativeLayer(mFGSurfaceControl->getHandle(), 1);
- SurfaceComposerClient::closeGlobalTransaction(true);
-
+ asTransaction([&](Transaction& t) {
+ t.setPosition(relativeSurfaceControl, 64, 64);
+ t.show(relativeSurfaceControl);
+ t.setRelativeLayer(relativeSurfaceControl, mFGSurfaceControl->getHandle(), 1);
+ });
{
SCOPED_TRACE("after adding relative surface");
@@ -765,9 +845,9 @@
}
// A call to setLayer will override a call to setRelativeLayer
- SurfaceComposerClient::openGlobalTransaction();
- relativeSurfaceControl->setLayer(0);
- SurfaceComposerClient::closeGlobalTransaction();
+ asTransaction([&](Transaction& t) {
+ t.setLayer(relativeSurfaceControl, 0);
+ });
{
SCOPED_TRACE("after set layer");
@@ -777,6 +857,64 @@
}
}
+TEST_F(LayerUpdateTest, LayerWithNoBuffersResizesImmediately) {
+ sp<ScreenCapture> sc;
+
+ sp<SurfaceControl> childNoBuffer =
+ mComposerClient->createSurface(String8("Bufferless child"),
+ 10, 10, PIXEL_FORMAT_RGBA_8888,
+ 0, mFGSurfaceControl.get());
+ sp<SurfaceControl> childBuffer = mComposerClient->createSurface(
+ String8("Buffered child"), 20, 20,
+ PIXEL_FORMAT_RGBA_8888, 0, childNoBuffer.get());
+ fillSurfaceRGBA8(childBuffer, 200, 200, 200);
+
+ SurfaceComposerClient::Transaction{}
+ .show(childNoBuffer)
+ .show(childBuffer)
+ .apply(true);
+
+ {
+ ScreenCapture::captureScreen(&sc);
+ sc->expectChildColor(73, 73);
+ sc->expectFGColor(74, 74);
+ }
+
+ SurfaceComposerClient::Transaction{}
+ .setSize(childNoBuffer, 20, 20)
+ .apply(true);
+
+ {
+ ScreenCapture::captureScreen(&sc);
+ sc->expectChildColor(73, 73);
+ sc->expectChildColor(74, 74);
+ }
+}
+
+TEST_F(LayerUpdateTest, MergingTransactions) {
+ sp<ScreenCapture> sc;
+ {
+ SCOPED_TRACE("before move");
+ ScreenCapture::captureScreen(&sc);
+ sc->expectBGColor(0, 12);
+ sc->expectFGColor(75, 75);
+ sc->expectBGColor(145, 145);
+ }
+
+ Transaction t1, t2;
+ t1.setPosition(mFGSurfaceControl, 128, 128);
+ t2.setPosition(mFGSurfaceControl, 0, 0);
+ // We expect that the position update from t2 now
+ // overwrites the position update from t1.
+ t1.merge(std::move(t2));
+ t1.apply();
+
+ {
+ ScreenCapture::captureScreen(&sc);
+ sc->expectFGColor(1, 1);
+ }
+}
+
class ChildLayerTest : public LayerUpdateTest {
protected:
void SetUp() override {
@@ -803,11 +941,11 @@
};
TEST_F(ChildLayerTest, ChildLayerPositioning) {
- SurfaceComposerClient::openGlobalTransaction();
- mChild->show();
- mChild->setPosition(10, 10);
- mFGSurfaceControl->setPosition(64, 64);
- SurfaceComposerClient::closeGlobalTransaction(true);
+ asTransaction([&](Transaction& t) {
+ t.show(mChild);
+ t.setPosition(mChild, 10, 10);
+ t.setPosition(mFGSurfaceControl, 64, 64);
+ });
{
ScreenCapture::captureScreen(&mCapture);
@@ -819,9 +957,9 @@
mCapture->expectFGColor(84, 84);
}
- SurfaceComposerClient::openGlobalTransaction();
- ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setPosition(0, 0));
- SurfaceComposerClient::closeGlobalTransaction(true);
+ asTransaction([&](Transaction& t) {
+ t.setPosition(mFGSurfaceControl, 0, 0);
+ });
{
ScreenCapture::captureScreen(&mCapture);
@@ -834,12 +972,44 @@
}
}
+TEST_F(ChildLayerTest, ChildLayerCropping) {
+ asTransaction([&](Transaction& t) {
+ t.show(mChild);
+ t.setPosition(mChild, 0, 0);
+ t.setPosition(mFGSurfaceControl, 0, 0);
+ t.setCrop(mFGSurfaceControl, Rect(0, 0, 5, 5));
+ });
+
+ {
+ ScreenCapture::captureScreen(&mCapture);
+ mCapture->expectChildColor(0, 0);
+ mCapture->expectChildColor(4, 4);
+ mCapture->expectBGColor(5, 5);
+ }
+}
+
+TEST_F(ChildLayerTest, ChildLayerFinalCropping) {
+ asTransaction([&](Transaction& t) {
+ t.show(mChild);
+ t.setPosition(mChild, 0, 0);
+ t.setPosition(mFGSurfaceControl, 0, 0);
+ t.setFinalCrop(mFGSurfaceControl, Rect(0, 0, 5, 5));
+ });
+
+ {
+ ScreenCapture::captureScreen(&mCapture);
+ mCapture->expectChildColor(0, 0);
+ mCapture->expectChildColor(4, 4);
+ mCapture->expectBGColor(5, 5);
+ }
+}
+
TEST_F(ChildLayerTest, ChildLayerConstraints) {
- SurfaceComposerClient::openGlobalTransaction();
- mChild->show();
- mFGSurfaceControl->setPosition(0, 0);
- mChild->setPosition(63, 63);
- SurfaceComposerClient::closeGlobalTransaction(true);
+ asTransaction([&](Transaction& t) {
+ t.show(mChild);
+ t.setPosition(mFGSurfaceControl, 0, 0);
+ t.setPosition(mChild, 63, 63);
+ });
{
ScreenCapture::captureScreen(&mCapture);
@@ -853,9 +1023,9 @@
}
TEST_F(ChildLayerTest, ChildLayerScaling) {
- SurfaceComposerClient::openGlobalTransaction();
- mFGSurfaceControl->setPosition(0, 0);
- SurfaceComposerClient::closeGlobalTransaction(true);
+ asTransaction([&](Transaction& t) {
+ t.setPosition(mFGSurfaceControl, 0, 0);
+ });
// Find the boundary between the parent and child
{
@@ -864,9 +1034,9 @@
mCapture->expectFGColor(10, 10);
}
- SurfaceComposerClient::openGlobalTransaction();
- mFGSurfaceControl->setMatrix(2.0, 0, 0, 2.0);
- SurfaceComposerClient::closeGlobalTransaction(true);
+ asTransaction([&](Transaction& t) {
+ t.setMatrix(mFGSurfaceControl, 2.0, 0, 0, 2.0);
+ });
// The boundary should be twice as far from the origin now.
// The pixels from the last test should all be child now
@@ -885,11 +1055,11 @@
fillSurfaceRGBA8(mChild, 0, 254, 0);
waitForPostedBuffers();
- SurfaceComposerClient::openGlobalTransaction();
- mChild->show();
- mChild->setPosition(0, 0);
- mFGSurfaceControl->setPosition(0, 0);
- SurfaceComposerClient::closeGlobalTransaction(true);
+ asTransaction([&](Transaction& t) {
+ t.show(mChild);
+ t.setPosition(mChild, 0, 0);
+ t.setPosition(mFGSurfaceControl, 0, 0);
+ });
{
ScreenCapture::captureScreen(&mCapture);
@@ -897,9 +1067,9 @@
mCapture->checkPixel(0, 0, 0, 254, 0);
}
- SurfaceComposerClient::openGlobalTransaction();
- ASSERT_EQ(NO_ERROR, mChild->setAlpha(0.5));
- SurfaceComposerClient::closeGlobalTransaction(true);
+ asTransaction([&](Transaction& t) {
+ t.setAlpha(mChild, 0.5);
+ });
{
ScreenCapture::captureScreen(&mCapture);
@@ -907,9 +1077,9 @@
mCapture->checkPixel(0, 0, 127, 127, 0);
}
- SurfaceComposerClient::openGlobalTransaction();
- ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setAlpha(0.5));
- SurfaceComposerClient::closeGlobalTransaction(true);
+ asTransaction([&](Transaction& t) {
+ t.setAlpha(mFGSurfaceControl, 0.5);
+ });
{
ScreenCapture::captureScreen(&mCapture);
@@ -919,11 +1089,11 @@
}
TEST_F(ChildLayerTest, ReparentChildren) {
- SurfaceComposerClient::openGlobalTransaction();
- mChild->show();
- mChild->setPosition(10, 10);
- mFGSurfaceControl->setPosition(64, 64);
- SurfaceComposerClient::closeGlobalTransaction(true);
+ asTransaction([&](Transaction& t) {
+ t.show(mChild);
+ t.setPosition(mChild, 10, 10);
+ t.setPosition(mFGSurfaceControl, 64, 64);
+ });
{
ScreenCapture::captureScreen(&mCapture);
@@ -934,7 +1104,11 @@
// And 10 more pixels we should be back to the foreground surface
mCapture->expectFGColor(84, 84);
}
- mFGSurfaceControl->reparentChildren(mBGSurfaceControl->getHandle());
+
+ asTransaction([&](Transaction& t) {
+ t.reparentChildren(mFGSurfaceControl, mBGSurfaceControl->getHandle());
+ });
+
{
ScreenCapture::captureScreen(&mCapture);
mCapture->expectFGColor(64, 64);
@@ -947,12 +1121,12 @@
}
}
-TEST_F(ChildLayerTest, DetachChildren) {
- SurfaceComposerClient::openGlobalTransaction();
- mChild->show();
- mChild->setPosition(10, 10);
- mFGSurfaceControl->setPosition(64, 64);
- SurfaceComposerClient::closeGlobalTransaction(true);
+TEST_F(ChildLayerTest, DetachChildrenSameClient) {
+ asTransaction([&](Transaction& t) {
+ t.show(mChild);
+ t.setPosition(mChild, 10, 10);
+ t.setPosition(mFGSurfaceControl, 64, 64);
+ });
{
ScreenCapture::captureScreen(&mCapture);
@@ -964,13 +1138,59 @@
mCapture->expectFGColor(84, 84);
}
- SurfaceComposerClient::openGlobalTransaction();
- mFGSurfaceControl->detachChildren();
- SurfaceComposerClient::closeGlobalTransaction(true);
+ asTransaction([&](Transaction& t) {
+ t.detachChildren(mFGSurfaceControl);
+ });
- SurfaceComposerClient::openGlobalTransaction();
- mChild->hide();
- SurfaceComposerClient::closeGlobalTransaction(true);
+ asTransaction([&](Transaction& t) {
+ t.hide(mChild);
+ });
+
+ // Since the child has the same client as the parent, it will not get
+ // detached and will be hidden.
+ {
+ ScreenCapture::captureScreen(&mCapture);
+ mCapture->expectFGColor(64, 64);
+ mCapture->expectFGColor(74, 74);
+ mCapture->expectFGColor(84, 84);
+ }
+}
+
+TEST_F(ChildLayerTest, DetachChildrenDifferentClient) {
+ sp<SurfaceComposerClient> mNewComposerClient = new SurfaceComposerClient;
+ sp<SurfaceControl> mChildNewClient = mNewComposerClient->createSurface(
+ String8("New Child Test Surface"), 10, 10, PIXEL_FORMAT_RGBA_8888,
+ 0, mFGSurfaceControl.get());
+
+ ASSERT_TRUE(mChildNewClient != NULL);
+ ASSERT_TRUE(mChildNewClient->isValid());
+
+ fillSurfaceRGBA8(mChildNewClient, 200, 200, 200);
+
+ asTransaction([&](Transaction& t) {
+ t.hide(mChild);
+ t.show(mChildNewClient);
+ t.setPosition(mChildNewClient, 10, 10);
+ t.setPosition(mFGSurfaceControl, 64, 64);
+ });
+
+ {
+ ScreenCapture::captureScreen(&mCapture);
+ // Top left of foreground must now be visible
+ mCapture->expectFGColor(64, 64);
+ // But 10 pixels in we should see the child surface
+ mCapture->expectChildColor(74, 74);
+ // And 10 more pixels we should be back to the foreground surface
+ mCapture->expectFGColor(84, 84);
+ }
+
+ asTransaction([&](Transaction& t) {
+ t.detachChildren(mFGSurfaceControl);
+ });
+
+ asTransaction([&](Transaction& t) {
+ t.hide(mChildNewClient);
+ });
// Nothing should have changed.
{
@@ -982,11 +1202,11 @@
}
TEST_F(ChildLayerTest, ChildrenInheritNonTransformScalingFromParent) {
- SurfaceComposerClient::openGlobalTransaction();
- mChild->show();
- mChild->setPosition(0, 0);
- mFGSurfaceControl->setPosition(0, 0);
- SurfaceComposerClient::closeGlobalTransaction(true);
+ asTransaction([&](Transaction& t) {
+ t.show(mChild);
+ t.setPosition(mChild, 0, 0);
+ t.setPosition(mFGSurfaceControl, 0, 0);
+ });
{
ScreenCapture::captureScreen(&mCapture);
@@ -996,11 +1216,11 @@
mCapture->expectFGColor(10, 10);
}
- SurfaceComposerClient::openGlobalTransaction();
- mFGSurfaceControl->setOverrideScalingMode(NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
- // We cause scaling by 2.
- mFGSurfaceControl->setSize(128, 128);
- SurfaceComposerClient::closeGlobalTransaction();
+ asTransaction([&](Transaction& t) {
+ t.setOverrideScalingMode(mFGSurfaceControl, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
+ // We cause scaling by 2.
+ t.setSize(mFGSurfaceControl, 128, 128);
+ });
{
ScreenCapture::captureScreen(&mCapture);
@@ -1015,11 +1235,11 @@
// Regression test for b/37673612
TEST_F(ChildLayerTest, ChildrenWithParentBufferTransform) {
- SurfaceComposerClient::openGlobalTransaction();
- mChild->show();
- mChild->setPosition(0, 0);
- mFGSurfaceControl->setPosition(0, 0);
- SurfaceComposerClient::closeGlobalTransaction(true);
+ asTransaction([&](Transaction& t) {
+ t.show(mChild);
+ t.setPosition(mChild, 0, 0);
+ t.setPosition(mFGSurfaceControl, 0, 0);
+ });
{
ScreenCapture::captureScreen(&mCapture);
@@ -1028,11 +1248,11 @@
// But it's only 10x10.
mCapture->expectFGColor(10, 10);
}
-
-
// We set things up as in b/37673612 so that there is a mismatch between the buffer size and
// the WM specified state size.
- mFGSurfaceControl->setSize(128, 64);
+ asTransaction([&](Transaction& t) {
+ t.setSize(mFGSurfaceControl, 128, 64);
+ });
sp<Surface> s = mFGSurfaceControl->getSurface();
auto anw = static_cast<ANativeWindow*>(s.get());
native_window_set_buffers_transform(anw, NATIVE_WINDOW_TRANSFORM_ROT_90);
@@ -1059,11 +1279,11 @@
mFGSurfaceControl.get());
// Show the child layer in a deferred transaction
- SurfaceComposerClient::openGlobalTransaction();
- mChild->deferTransactionUntil(mFGSurfaceControl->getHandle(),
- mFGSurfaceControl->getSurface()->getNextFrameNumber());
- mChild->show();
- SurfaceComposerClient::closeGlobalTransaction(true);
+ asTransaction([&](Transaction& t) {
+ t.deferTransactionUntil(mChild, mFGSurfaceControl->getHandle(),
+ mFGSurfaceControl->getSurface()->getNextFrameNumber());
+ t.show(mChild);
+ });
// Render the foreground surface a few times
//
@@ -1080,4 +1300,318 @@
fillSurfaceRGBA8(mFGSurfaceControl, 0, 255, 0);
}
+TEST_F(ChildLayerTest, Reparent) {
+ asTransaction([&](Transaction& t) {
+ t.show(mChild);
+ t.setPosition(mChild, 10, 10);
+ t.setPosition(mFGSurfaceControl, 64, 64);
+ });
+
+ {
+ ScreenCapture::captureScreen(&mCapture);
+ // Top left of foreground must now be visible
+ mCapture->expectFGColor(64, 64);
+ // But 10 pixels in we should see the child surface
+ mCapture->expectChildColor(74, 74);
+ // And 10 more pixels we should be back to the foreground surface
+ mCapture->expectFGColor(84, 84);
+ }
+
+ asTransaction([&](Transaction& t) {
+ t.reparent(mChild, mBGSurfaceControl->getHandle());
+ });
+
+ {
+ ScreenCapture::captureScreen(&mCapture);
+ mCapture->expectFGColor(64, 64);
+ // In reparenting we should have exposed the entire foreground surface.
+ mCapture->expectFGColor(74, 74);
+ // And the child layer should now begin at 10, 10 (since the BG
+ // layer is at (0, 0)).
+ mCapture->expectBGColor(9, 9);
+ mCapture->expectChildColor(10, 10);
+ }
+}
+
+TEST_F(ChildLayerTest, ReparentToNoParent) {
+ asTransaction([&](Transaction& t) {
+ t.show(mChild);
+ t.setPosition(mChild, 10, 10);
+ t.setPosition(mFGSurfaceControl, 64, 64);
+ });
+
+ {
+ ScreenCapture::captureScreen(&mCapture);
+ // Top left of foreground must now be visible
+ mCapture->expectFGColor(64, 64);
+ // But 10 pixels in we should see the child surface
+ mCapture->expectChildColor(74, 74);
+ // And 10 more pixels we should be back to the foreground surface
+ mCapture->expectFGColor(84, 84);
+ }
+ asTransaction([&](Transaction& t) {
+ t.reparent(mChild, nullptr);
+ });
+ {
+ ScreenCapture::captureScreen(&mCapture);
+ // Nothing should have changed.
+ mCapture->expectFGColor(64, 64);
+ mCapture->expectChildColor(74, 74);
+ mCapture->expectFGColor(84, 84);
+ }
+}
+
+TEST_F(ChildLayerTest, ReparentFromNoParent) {
+ sp<SurfaceControl> newSurface = mComposerClient->createSurface(
+ String8("New Surface"), 10, 10, PIXEL_FORMAT_RGBA_8888, 0);
+ ASSERT_TRUE(newSurface != NULL);
+ ASSERT_TRUE(newSurface->isValid());
+
+ fillSurfaceRGBA8(newSurface, 63, 195, 63);
+ asTransaction([&](Transaction& t) {
+ t.hide(mChild);
+ t.show(newSurface);
+ t.setPosition(newSurface, 10, 10);
+ t.setLayer(newSurface, INT32_MAX-2);
+ t.setPosition(mFGSurfaceControl, 64, 64);
+ });
+
+ {
+ ScreenCapture::captureScreen(&mCapture);
+ // Top left of foreground must now be visible
+ mCapture->expectFGColor(64, 64);
+ // At 10, 10 we should see the new surface
+ mCapture->checkPixel(10, 10, 63, 195, 63);
+ }
+
+ asTransaction([&](Transaction& t) {
+ t.reparent(newSurface, mFGSurfaceControl->getHandle());
+ });
+
+ {
+ ScreenCapture::captureScreen(&mCapture);
+ // newSurface will now be a child of mFGSurface so it will be 10, 10 offset from
+ // mFGSurface, putting it at 74, 74.
+ mCapture->expectFGColor(64, 64);
+ mCapture->checkPixel(74, 74, 63, 195, 63);
+ mCapture->expectFGColor(84, 84);
+ }
+}
+
+TEST_F(ChildLayerTest, NestedChildren) {
+ sp<SurfaceControl> grandchild = mComposerClient->createSurface(
+ String8("Grandchild surface"),
+ 10, 10, PIXEL_FORMAT_RGBA_8888,
+ 0, mChild.get());
+ fillSurfaceRGBA8(grandchild, 50, 50, 50);
+
+ {
+ ScreenCapture::captureScreen(&mCapture);
+ // Expect the grandchild to begin at 64, 64 because it's a child of mChild layer
+ // which begins at 64, 64
+ mCapture->checkPixel(64, 64, 50, 50, 50);
+ }
+}
+
+class LayerColorTest : public LayerUpdateTest {
+ protected:
+ void SetUp() override {
+ LayerUpdateTest::SetUp();
+
+ mLayerColorControl = mComposerClient->createSurface(
+ String8("Layer color surface"),
+ 128, 128, PIXEL_FORMAT_RGBA_8888,
+ ISurfaceComposerClient::eFXSurfaceColor);
+
+ ASSERT_TRUE(mLayerColorControl != NULL);
+ ASSERT_TRUE(mLayerColorControl->isValid());
+
+ asTransaction([&](Transaction& t) {
+ t.setLayer(mLayerColorControl, INT32_MAX-1);
+ t.setPosition(mLayerColorControl, 140, 140);
+ t.hide(mLayerColorControl);
+ t.hide(mFGSurfaceControl);
+ });
+ }
+
+ void TearDown() override {
+ LayerUpdateTest::TearDown();
+ mLayerColorControl = 0;
+ }
+
+ sp<SurfaceControl> mLayerColorControl;
+};
+
+TEST_F(LayerColorTest, ColorLayerNoAlpha) {
+ sp<ScreenCapture> sc;
+
+ {
+ SCOPED_TRACE("before setColor");
+ ScreenCapture::captureScreen(&sc);
+ sc->expectBGColor(145, 145);
+ }
+
+ asTransaction([&](Transaction& t) {
+ half3 color(43.0f/255.0f, 207.0f/255.0f, 131.0f/255.0f);
+ t.setColor(mLayerColorControl, color);
+ t.show(mLayerColorControl);
+ });
+
+ {
+ // There should now be a color
+ SCOPED_TRACE("after setColor");
+
+ ScreenCapture::captureScreen(&sc);
+ sc->checkPixel(145, 145, 43, 207, 131);
+ }
+}
+
+TEST_F(LayerColorTest, ColorLayerWithAlpha) {
+ sp<ScreenCapture> sc;
+ {
+ SCOPED_TRACE("before setColor");
+ ScreenCapture::captureScreen(&sc);
+ sc->expectBGColor(145, 145);
+ }
+
+ asTransaction([&](Transaction& t) {
+ half3 color(43.0f/255.0f, 207.0f/255.0f, 131.0f/255.0f);
+ t.setColor(mLayerColorControl, color);
+ t.setAlpha(mLayerColorControl, .75f);
+ t.show(mLayerColorControl);
+ });
+
+ {
+ // There should now be a color with .75 alpha
+ SCOPED_TRACE("after setColor");
+ ScreenCapture::captureScreen(&sc);
+ sc->checkPixel(145, 145, 48, 171, 147);
+ }
+}
+
+TEST_F(LayerColorTest, ColorLayerWithNoColor) {
+ sp<ScreenCapture> sc;
+ {
+ SCOPED_TRACE("before setColor");
+ ScreenCapture::captureScreen(&sc);
+ sc->expectBGColor(145, 145);
+ }
+
+ asTransaction([&](Transaction& t) {
+ t.show(mLayerColorControl);
+ });
+
+ {
+ // There should now be set to 0,0,0 (black) as default.
+ SCOPED_TRACE("after setColor");
+ ScreenCapture::captureScreen(&sc);
+ sc->checkPixel(145, 145, 0, 0, 0);
+ }
+}
+
+class ScreenCaptureTest : public LayerUpdateTest {
+protected:
+ std::unique_ptr<CaptureLayer> mCapture;
+};
+
+TEST_F(ScreenCaptureTest, CaptureSingleLayer) {
+ auto bgHandle = mBGSurfaceControl->getHandle();
+ CaptureLayer::captureScreen(&mCapture, bgHandle);
+ mCapture->expectBGColor(0, 0);
+ // Doesn't capture FG layer which is at 64, 64
+ mCapture->expectBGColor(64, 64);
+}
+
+TEST_F(ScreenCaptureTest, CaptureLayerWithChild) {
+ auto fgHandle = mFGSurfaceControl->getHandle();
+
+ sp<SurfaceControl> child = mComposerClient->createSurface(
+ String8("Child surface"),
+ 10, 10, PIXEL_FORMAT_RGBA_8888,
+ 0, mFGSurfaceControl.get());
+ fillSurfaceRGBA8(child, 200, 200, 200);
+
+ SurfaceComposerClient::Transaction()
+ .show(child)
+ .apply(true);
+
+ // Captures mFGSurfaceControl layer and its child.
+ CaptureLayer::captureScreen(&mCapture, fgHandle);
+ mCapture->expectFGColor(10, 10);
+ mCapture->expectChildColor(0, 0);
+}
+
+TEST_F(ScreenCaptureTest, CaptureLayerWithGrandchild) {
+ auto fgHandle = mFGSurfaceControl->getHandle();
+
+ sp<SurfaceControl> child = mComposerClient->createSurface(
+ String8("Child surface"),
+ 10, 10, PIXEL_FORMAT_RGBA_8888,
+ 0, mFGSurfaceControl.get());
+ fillSurfaceRGBA8(child, 200, 200, 200);
+
+ sp<SurfaceControl> grandchild = mComposerClient->createSurface(
+ String8("Grandchild surface"), 5, 5,
+ PIXEL_FORMAT_RGBA_8888, 0, child.get());
+
+ fillSurfaceRGBA8(grandchild, 50, 50, 50);
+ SurfaceComposerClient::Transaction()
+ .show(child)
+ .setPosition(grandchild, 5, 5)
+ .show(grandchild)
+ .apply(true);
+
+ // Captures mFGSurfaceControl, its child, and the grandchild.
+ CaptureLayer::captureScreen(&mCapture, fgHandle);
+ mCapture->expectFGColor(10, 10);
+ mCapture->expectChildColor(0, 0);
+ mCapture->checkPixel(5, 5, 50, 50, 50);
+}
+
+TEST_F(ScreenCaptureTest, CaptureChildOnly) {
+ sp<SurfaceControl> child = mComposerClient->createSurface(
+ String8("Child surface"),
+ 10, 10, PIXEL_FORMAT_RGBA_8888,
+ 0, mFGSurfaceControl.get());
+ fillSurfaceRGBA8(child, 200, 200, 200);
+ auto childHandle = child->getHandle();
+
+ SurfaceComposerClient::Transaction()
+ .setPosition(child, 5, 5)
+ .show(child)
+ .apply(true);
+
+ // Captures only the child layer, and not the parent.
+ CaptureLayer::captureScreen(&mCapture, childHandle);
+ mCapture->expectChildColor(0, 0);
+ mCapture->expectChildColor(9, 9);
+}
+
+TEST_F(ScreenCaptureTest, CaptureGrandchildOnly) {
+ sp<SurfaceControl> child = mComposerClient->createSurface(
+ String8("Child surface"),
+ 10, 10, PIXEL_FORMAT_RGBA_8888,
+ 0, mFGSurfaceControl.get());
+ fillSurfaceRGBA8(child, 200, 200, 200);
+ auto childHandle = child->getHandle();
+
+ sp<SurfaceControl> grandchild = mComposerClient->createSurface(
+ String8("Grandchild surface"), 5, 5,
+ PIXEL_FORMAT_RGBA_8888, 0, child.get());
+ fillSurfaceRGBA8(grandchild, 50, 50, 50);
+
+ SurfaceComposerClient::Transaction()
+ .show(child)
+ .setPosition(grandchild, 5, 5)
+ .show(grandchild)
+ .apply(true);
+
+ auto grandchildHandle = grandchild->getHandle();
+
+ // Captures only the grandchild.
+ CaptureLayer::captureScreen(&mCapture, grandchildHandle);
+ mCapture->checkPixel(0, 0, 50, 50, 50);
+ mCapture->checkPixel(4, 4, 50, 50, 50);
+}
+
}
diff --git a/services/surfaceflinger/tests/fakehwc/Android.bp b/services/surfaceflinger/tests/fakehwc/Android.bp
new file mode 100644
index 0000000..212b9e7
--- /dev/null
+++ b/services/surfaceflinger/tests/fakehwc/Android.bp
@@ -0,0 +1,36 @@
+cc_test {
+ name: "sffakehwc_test",
+ srcs: [
+ "FakeComposerClient.cpp",
+ "FakeComposerService.cpp",
+ "FakeComposerUtils.cpp",
+ "SFFakeHwc_test.cpp"
+ ],
+ shared_libs: [
+ "libcutils",
+ "libutils",
+ "libbinder",
+ "libui",
+ "libgui",
+ "liblog",
+ "libnativewindow",
+ "android.hardware.graphics.composer@2.1",
+ "android.hardware.graphics.mapper@2.0",
+ "libhwbinder",
+ "libhardware",
+ "libhidlbase",
+ "libsync",
+ "libfmq",
+ "libbase",
+ "libhidltransport",
+ "liblayers_proto"
+ ],
+ static_libs: [
+ "libhwcomposer-client",
+ "libsurfaceflingerincludes",
+ "libtrace_proto",
+ "libgmock"
+ ],
+ tags: ["tests"],
+ test_suites: ["device-tests"]
+}
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/fakehwc/FakeComposerClient.cpp b/services/surfaceflinger/tests/fakehwc/FakeComposerClient.cpp
new file mode 100644
index 0000000..d97ffa3
--- /dev/null
+++ b/services/surfaceflinger/tests/fakehwc/FakeComposerClient.cpp
@@ -0,0 +1,612 @@
+/*
+ * Copyright (C) 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.
+ */
+
+//#define LOG_NDEBUG 0
+#undef LOG_TAG
+#define LOG_TAG "FakeComposer"
+
+#include "FakeComposerClient.h"
+
+#include <gui/SurfaceComposerClient.h>
+
+#include <log/log.h>
+
+#include <gtest/gtest.h>
+
+#include <inttypes.h>
+#include <time.h>
+#include <algorithm>
+#include <condition_variable>
+#include <iostream>
+#include <mutex>
+#include <set>
+#include <thread>
+
+constexpr Config NULL_DISPLAY_CONFIG = static_cast<Config>(0);
+
+using namespace sftest;
+
+using android::Condition;
+using android::Mutex;
+
+using Clock = std::chrono::steady_clock;
+using TimePoint = std::chrono::time_point<Clock>;
+
+namespace {
+
+// Internal state of a layer in the HWC API.
+class LayerImpl {
+public:
+ LayerImpl() = default;
+
+ bool mValid = true;
+ RenderState mRenderState;
+ uint32_t mZ = 0;
+};
+
+// Struct for storing per frame rectangle state. Contains the render
+// state shared to the test case. Basically a snapshot and a subset of
+// LayerImpl sufficient to re-create the pixels of a layer for the
+// frame.
+struct FrameRect {
+public:
+ FrameRect(Layer layer_, const RenderState& state, uint32_t z_)
+ : layer(layer_), renderState(state), z(z_) {}
+
+ const Layer layer;
+ const RenderState renderState;
+ const uint32_t z;
+};
+
+// Collection of FrameRects forming one rendered frame. Could store
+// related fences and other data in the future.
+class Frame {
+public:
+ Frame() = default;
+ std::vector<std::unique_ptr<FrameRect>> rectangles;
+};
+
+class DelayedEventGenerator {
+public:
+ DelayedEventGenerator(std::function<void()> onTimerExpired)
+ : mOnTimerExpired(onTimerExpired), mThread([this]() { loop(); }) {}
+
+ ~DelayedEventGenerator() {
+ ALOGI("DelayedEventGenerator exiting.");
+ {
+ std::unique_lock<std::mutex> lock(mMutex);
+ mRunning = false;
+ mWakeups.clear();
+ mCondition.notify_one();
+ }
+ mThread.join();
+ ALOGI("DelayedEventGenerator exited.");
+ }
+
+ void wakeAfter(std::chrono::nanoseconds waitTime) {
+ std::unique_lock<std::mutex> lock(mMutex);
+ mWakeups.insert(Clock::now() + waitTime);
+ mCondition.notify_one();
+ }
+
+private:
+ void loop() {
+ while (true) {
+ // Lock scope
+ {
+ std::unique_lock<std::mutex> lock(mMutex);
+ mCondition.wait(lock, [this]() { return !mRunning || !mWakeups.empty(); });
+ if (!mRunning && mWakeups.empty()) {
+ // This thread should only exit once the destructor has been called and all
+ // wakeups have been processed
+ return;
+ }
+
+ // At this point, mWakeups will not be empty
+
+ TimePoint target = *(mWakeups.begin());
+ auto status = mCondition.wait_until(lock, target);
+ while (status == std::cv_status::no_timeout) {
+ // This was either a spurious wakeup or another wakeup was added, so grab the
+ // oldest point and wait again
+ target = *(mWakeups.begin());
+ status = mCondition.wait_until(lock, target);
+ }
+
+ // status must have been timeout, so we can finally clear this point
+ mWakeups.erase(target);
+ }
+ // Callback *without* locks!
+ mOnTimerExpired();
+ }
+ }
+
+ std::function<void()> mOnTimerExpired;
+ std::thread mThread;
+ std::mutex mMutex;
+ std::condition_variable mCondition;
+ bool mRunning = true;
+ std::set<TimePoint> mWakeups;
+};
+
+} // namespace
+
+FakeComposerClient::FakeComposerClient()
+ : mCallbacksOn(false),
+ mClient(nullptr),
+ mCurrentConfig(NULL_DISPLAY_CONFIG),
+ mVsyncEnabled(false),
+ mLayers(),
+ mDelayedEventGenerator(
+ std::make_unique<DelayedEventGenerator>([this]() { this->requestVSync(); })),
+ mSurfaceComposer(nullptr) {}
+
+FakeComposerClient::~FakeComposerClient() {}
+
+void FakeComposerClient::removeClient() {
+ ALOGV("removeClient");
+ // TODO: Ahooga! Only thing current lifetime management choices in
+ // APIs make possible. Sad.
+ delete this;
+}
+
+void FakeComposerClient::enableCallback(bool enable) {
+ ALOGV("enableCallback");
+ mCallbacksOn = enable;
+ if (mCallbacksOn) {
+ mClient->onHotplug(PRIMARY_DISPLAY, IComposerCallback::Connection::CONNECTED);
+ }
+}
+
+void FakeComposerClient::hotplugDisplay(Display display, IComposerCallback::Connection state) {
+ if (mCallbacksOn) {
+ mClient->onHotplug(display, state);
+ }
+}
+
+uint32_t FakeComposerClient::getMaxVirtualDisplayCount() {
+ ALOGV("getMaxVirtualDisplayCount");
+ return 1;
+}
+
+Error FakeComposerClient::createVirtualDisplay(uint32_t /*width*/, uint32_t /*height*/,
+ PixelFormat* /*format*/, Display* /*outDisplay*/) {
+ ALOGV("createVirtualDisplay");
+ return Error::NONE;
+}
+
+Error FakeComposerClient::destroyVirtualDisplay(Display /*display*/) {
+ ALOGV("destroyVirtualDisplay");
+ return Error::NONE;
+}
+
+Error FakeComposerClient::createLayer(Display /*display*/, Layer* outLayer) {
+ ALOGV("createLayer");
+ *outLayer = mLayers.size();
+ auto newLayer = std::make_unique<LayerImpl>();
+ mLayers.push_back(std::move(newLayer));
+ return Error::NONE;
+}
+
+Error FakeComposerClient::destroyLayer(Display /*display*/, Layer layer) {
+ ALOGV("destroyLayer");
+ mLayers[layer]->mValid = false;
+ return Error::NONE;
+}
+
+Error FakeComposerClient::getActiveConfig(Display /*display*/, Config* outConfig) {
+ ALOGV("getActiveConfig");
+
+ // TODO Assert outConfig != nullptr
+
+ // TODO This is my reading of the
+ // IComposerClient::getActiveConfig, but returning BAD_CONFIG
+ // seems to not fit SurfaceFlinger plans. See version 2 below.
+ // if (mCurrentConfig == NULL_DISPLAY_CONFIG) {
+ // return Error::BAD_CONFIG;
+ // }
+ //*outConfig = mCurrentConfig;
+ *outConfig = 1; // Very special config for you my friend
+ return Error::NONE;
+}
+
+Error FakeComposerClient::getClientTargetSupport(Display /*display*/, uint32_t /*width*/,
+ uint32_t /*height*/, PixelFormat /*format*/,
+ Dataspace /*dataspace*/) {
+ ALOGV("getClientTargetSupport");
+ return Error::NONE;
+}
+
+Error FakeComposerClient::getColorModes(Display /*display*/, hidl_vec<ColorMode>* /*outModes*/) {
+ ALOGV("getColorModes");
+ return Error::NONE;
+}
+
+Error FakeComposerClient::getDisplayAttribute(Display display, Config config,
+ IComposerClient::Attribute attribute,
+ int32_t* outValue) {
+ ALOGV("getDisplayAttribute (%d, %d, %d, %p)", static_cast<int>(display),
+ static_cast<int>(config), static_cast<int>(attribute), outValue);
+
+ // TODO: SOOO much fun to be had with these alone
+ switch (attribute) {
+ case IComposerClient::Attribute::WIDTH:
+ *outValue = 1920;
+ break;
+ case IComposerClient::Attribute::HEIGHT:
+ *outValue = 1080;
+ break;
+ case IComposerClient::Attribute::VSYNC_PERIOD:
+ *outValue = 1666666666;
+ break; // TOOD: Tests break down if lowered to 16ms?
+ case IComposerClient::Attribute::DPI_X:
+ *outValue = 240;
+ break;
+ case IComposerClient::Attribute::DPI_Y:
+ *outValue = 240;
+ break;
+ default:
+ LOG_ALWAYS_FATAL("Say what!?! New attribute");
+ }
+
+ return Error::NONE;
+}
+
+Error FakeComposerClient::getDisplayConfigs(Display /*display*/, hidl_vec<Config>* outConfigs) {
+ ALOGV("getDisplayConfigs");
+ // TODO assert display == 1, outConfigs != nullptr
+
+ outConfigs->resize(1);
+ (*outConfigs)[0] = 1;
+
+ return Error::NONE;
+}
+
+Error FakeComposerClient::getDisplayName(Display /*display*/, hidl_string* /*outName*/) {
+ ALOGV("getDisplayName");
+ return Error::NONE;
+}
+
+Error FakeComposerClient::getDisplayType(Display /*display*/,
+ IComposerClient::DisplayType* outType) {
+ ALOGV("getDisplayType");
+ // TODO: This setting nothing on the output had no effect on initial trials. Is first display
+ // assumed to be physical?
+ *outType = static_cast<IComposerClient::DisplayType>(HWC2_DISPLAY_TYPE_PHYSICAL);
+ return Error::NONE;
+}
+
+Error FakeComposerClient::getDozeSupport(Display /*display*/, bool* /*outSupport*/) {
+ ALOGV("getDozeSupport");
+ return Error::NONE;
+}
+
+Error FakeComposerClient::getHdrCapabilities(Display /*display*/, hidl_vec<Hdr>* /*outTypes*/,
+ float* /*outMaxLuminance*/,
+ float* /*outMaxAverageLuminance*/,
+ float* /*outMinLuminance*/) {
+ ALOGV("getHdrCapabilities");
+ return Error::NONE;
+}
+
+Error FakeComposerClient::setActiveConfig(Display /*display*/, Config config) {
+ ALOGV("setActiveConfig");
+ mCurrentConfig = config;
+ return Error::NONE;
+}
+
+Error FakeComposerClient::setColorMode(Display /*display*/, ColorMode /*mode*/) {
+ ALOGV("setColorMode");
+ return Error::NONE;
+}
+
+Error FakeComposerClient::setPowerMode(Display /*display*/, IComposerClient::PowerMode /*mode*/) {
+ ALOGV("setPowerMode");
+ return Error::NONE;
+}
+
+Error FakeComposerClient::setVsyncEnabled(Display /*display*/, IComposerClient::Vsync enabled) {
+ mVsyncEnabled = (enabled == IComposerClient::Vsync::ENABLE);
+ ALOGV("setVsyncEnabled(%s)", mVsyncEnabled ? "ENABLE" : "DISABLE");
+ return Error::NONE;
+}
+
+Error FakeComposerClient::setColorTransform(Display /*display*/, const float* /*matrix*/,
+ int32_t /*hint*/) {
+ ALOGV("setColorTransform");
+ return Error::NONE;
+}
+
+Error FakeComposerClient::setClientTarget(Display /*display*/, buffer_handle_t /*target*/,
+ int32_t /*acquireFence*/, int32_t /*dataspace*/,
+ const std::vector<hwc_rect_t>& /*damage*/) {
+ ALOGV("setClientTarget");
+ return Error::NONE;
+}
+
+Error FakeComposerClient::setOutputBuffer(Display /*display*/, buffer_handle_t /*buffer*/,
+ int32_t /*releaseFence*/) {
+ ALOGV("setOutputBuffer");
+ return Error::NONE;
+}
+
+Error FakeComposerClient::validateDisplay(
+ Display /*display*/, std::vector<Layer>* /*outChangedLayers*/,
+ std::vector<IComposerClient::Composition>* /*outCompositionTypes*/,
+ uint32_t* /*outDisplayRequestMask*/, std::vector<Layer>* /*outRequestedLayers*/,
+ std::vector<uint32_t>* /*outRequestMasks*/) {
+ ALOGV("validateDisplay");
+ // TODO: Assume touching nothing means All Korrekt!
+ return Error::NONE;
+}
+
+Error FakeComposerClient::acceptDisplayChanges(Display /*display*/) {
+ ALOGV("acceptDisplayChanges");
+ // Didn't ask for changes because software is omnipotent.
+ return Error::NONE;
+}
+
+bool layerZOrdering(const std::unique_ptr<FrameRect>& a, const std::unique_ptr<FrameRect>& b) {
+ return a->z <= b->z;
+}
+
+Error FakeComposerClient::presentDisplay(Display /*display*/, int32_t* /*outPresentFence*/,
+ std::vector<Layer>* /*outLayers*/,
+ std::vector<int32_t>* /*outReleaseFences*/) {
+ ALOGV("presentDisplay");
+ // TODO Leaving layers and their fences out for now. Doing so
+ // means that we've already processed everything. Important to
+ // test that the fences are respected, though. (How?)
+
+ std::unique_ptr<Frame> newFrame(new Frame);
+ for (uint64_t layer = 0; layer < mLayers.size(); layer++) {
+ const LayerImpl& layerImpl = *mLayers[layer];
+
+ if (!layerImpl.mValid) continue;
+
+ auto rect = std::make_unique<FrameRect>(layer, layerImpl.mRenderState, layerImpl.mZ);
+ newFrame->rectangles.push_back(std::move(rect));
+ }
+ std::sort(newFrame->rectangles.begin(), newFrame->rectangles.end(), layerZOrdering);
+ {
+ Mutex::Autolock _l(mStateMutex);
+ mFrames.push_back(std::move(newFrame));
+ mFramesAvailable.broadcast();
+ }
+ return Error::NONE;
+}
+
+Error FakeComposerClient::setLayerCursorPosition(Display /*display*/, Layer /*layer*/,
+ int32_t /*x*/, int32_t /*y*/) {
+ ALOGV("setLayerCursorPosition");
+ return Error::NONE;
+}
+
+Error FakeComposerClient::setLayerBuffer(Display /*display*/, Layer layer, buffer_handle_t buffer,
+ int32_t acquireFence) {
+ ALOGV("setLayerBuffer");
+ LayerImpl& l = getLayerImpl(layer);
+ if (buffer != l.mRenderState.mBuffer) {
+ l.mRenderState.mSwapCount++; // TODO: Is setting to same value a swap or not?
+ }
+ l.mRenderState.mBuffer = buffer;
+ l.mRenderState.mAcquireFence = acquireFence;
+
+ return Error::NONE;
+}
+
+Error FakeComposerClient::setLayerSurfaceDamage(Display /*display*/, Layer /*layer*/,
+ const std::vector<hwc_rect_t>& /*damage*/) {
+ ALOGV("setLayerSurfaceDamage");
+ return Error::NONE;
+}
+
+Error FakeComposerClient::setLayerBlendMode(Display /*display*/, Layer layer, int32_t mode) {
+ ALOGV("setLayerBlendMode");
+ getLayerImpl(layer).mRenderState.mBlendMode = static_cast<hwc2_blend_mode_t>(mode);
+ return Error::NONE;
+}
+
+Error FakeComposerClient::setLayerColor(Display /*display*/, Layer layer,
+ IComposerClient::Color color) {
+ ALOGV("setLayerColor");
+ getLayerImpl(layer).mRenderState.mLayerColor.r = color.r;
+ getLayerImpl(layer).mRenderState.mLayerColor.g = color.g;
+ getLayerImpl(layer).mRenderState.mLayerColor.b = color.b;
+ getLayerImpl(layer).mRenderState.mLayerColor.a = color.a;
+ return Error::NONE;
+}
+
+Error FakeComposerClient::setLayerCompositionType(Display /*display*/, Layer /*layer*/,
+ int32_t /*type*/) {
+ ALOGV("setLayerCompositionType");
+ return Error::NONE;
+}
+
+Error FakeComposerClient::setLayerDataspace(Display /*display*/, Layer /*layer*/,
+ int32_t /*dataspace*/) {
+ ALOGV("setLayerDataspace");
+ return Error::NONE;
+}
+
+Error FakeComposerClient::setLayerDisplayFrame(Display /*display*/, Layer layer,
+ const hwc_rect_t& frame) {
+ ALOGV("setLayerDisplayFrame (%d, %d, %d, %d)", frame.left, frame.top, frame.right,
+ frame.bottom);
+ getLayerImpl(layer).mRenderState.mDisplayFrame = frame;
+ return Error::NONE;
+}
+
+Error FakeComposerClient::setLayerPlaneAlpha(Display /*display*/, Layer layer, float alpha) {
+ ALOGV("setLayerPlaneAlpha");
+ getLayerImpl(layer).mRenderState.mPlaneAlpha = alpha;
+ return Error::NONE;
+}
+
+Error FakeComposerClient::setLayerSidebandStream(Display /*display*/, Layer /*layer*/,
+ buffer_handle_t /*stream*/) {
+ ALOGV("setLayerSidebandStream");
+ return Error::NONE;
+}
+
+Error FakeComposerClient::setLayerSourceCrop(Display /*display*/, Layer layer,
+ const hwc_frect_t& crop) {
+ ALOGV("setLayerSourceCrop");
+ getLayerImpl(layer).mRenderState.mSourceCrop = crop;
+ return Error::NONE;
+}
+
+Error FakeComposerClient::setLayerTransform(Display /*display*/, Layer layer, int32_t transform) {
+ ALOGV("setLayerTransform");
+ getLayerImpl(layer).mRenderState.mTransform = static_cast<hwc_transform_t>(transform);
+ return Error::NONE;
+}
+
+Error FakeComposerClient::setLayerVisibleRegion(Display /*display*/, Layer layer,
+ const std::vector<hwc_rect_t>& visible) {
+ ALOGV("setLayerVisibleRegion");
+ getLayerImpl(layer).mRenderState.mVisibleRegion = visible;
+ return Error::NONE;
+}
+
+Error FakeComposerClient::setLayerZOrder(Display /*display*/, Layer layer, uint32_t z) {
+ ALOGV("setLayerZOrder");
+ getLayerImpl(layer).mZ = z;
+ return Error::NONE;
+}
+
+//////////////////////////////////////////////////////////////////
+
+void FakeComposerClient::setClient(ComposerClient* client) {
+ mClient = client;
+}
+
+void FakeComposerClient::requestVSync(uint64_t vsyncTime) {
+ if (mCallbacksOn) {
+ uint64_t timestamp = vsyncTime;
+ ALOGV("Vsync");
+ if (timestamp == 0) {
+ struct timespec ts;
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+ timestamp = ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec;
+ }
+ if (mSurfaceComposer != nullptr) {
+ mSurfaceComposer->injectVSync(timestamp);
+ } else {
+ mClient->onVsync(PRIMARY_DISPLAY, timestamp);
+ }
+ }
+}
+
+void FakeComposerClient::runVSyncAfter(std::chrono::nanoseconds wait) {
+ mDelayedEventGenerator->wakeAfter(wait);
+}
+
+LayerImpl& FakeComposerClient::getLayerImpl(Layer handle) {
+ // TODO Change these to an internal state check that can be
+ // invoked from the gtest? GTest macros do not seem all that safe
+ // when used outside the test class
+ EXPECT_GE(handle, static_cast<Layer>(0));
+ EXPECT_LT(handle, mLayers.size());
+ return *(mLayers[handle]);
+}
+
+int FakeComposerClient::getFrameCount() const {
+ return mFrames.size();
+}
+
+static std::vector<RenderState> extractRenderState(
+ const std::vector<std::unique_ptr<FrameRect>>& internalRects) {
+ std::vector<RenderState> result;
+ result.reserve(internalRects.size());
+ for (const std::unique_ptr<FrameRect>& rect : internalRects) {
+ result.push_back(rect->renderState);
+ }
+ return result;
+}
+
+std::vector<RenderState> FakeComposerClient::getFrameRects(int frame) const {
+ Mutex::Autolock _l(mStateMutex);
+ return extractRenderState(mFrames[frame]->rectangles);
+}
+
+std::vector<RenderState> FakeComposerClient::getLatestFrame() const {
+ Mutex::Autolock _l(mStateMutex);
+ return extractRenderState(mFrames[mFrames.size() - 1]->rectangles);
+}
+
+void FakeComposerClient::runVSyncAndWait(std::chrono::nanoseconds maxWait) {
+ int currentFrame = 0;
+ {
+ Mutex::Autolock _l(mStateMutex); // I hope this is ok...
+ currentFrame = static_cast<int>(mFrames.size());
+ requestVSync();
+ }
+ waitUntilFrame(currentFrame + 1, maxWait);
+}
+
+void FakeComposerClient::waitUntilFrame(int targetFrame, std::chrono::nanoseconds maxWait) const {
+ Mutex::Autolock _l(mStateMutex);
+ while (mFrames.size() < static_cast<size_t>(targetFrame)) {
+ android::status_t result = mFramesAvailable.waitRelative(mStateMutex, maxWait.count());
+ if (result == android::TIMED_OUT) {
+ ALOGE("Waiting for frame %d (at frame %zu now) timed out after %lld ns", targetFrame,
+ mFrames.size(), maxWait.count());
+ return;
+ }
+ }
+}
+
+void FakeComposerClient::clearFrames() {
+ Mutex::Autolock _l(mStateMutex);
+ mFrames.clear();
+ for (const std::unique_ptr<LayerImpl>& layer : mLayers) {
+ if (layer->mValid) {
+ layer->mRenderState.mSwapCount = 0;
+ }
+ }
+}
+
+void FakeComposerClient::onSurfaceFlingerStart() {
+ mSurfaceComposer == nullptr;
+ do {
+ mSurfaceComposer = new android::SurfaceComposerClient;
+ android::status_t initResult = mSurfaceComposer->initCheck();
+ if (initResult != android::NO_ERROR) {
+ ALOGD("Init result: %d", initResult);
+ mSurfaceComposer = nullptr;
+ std::this_thread::sleep_for(10ms);
+ }
+ } while (mSurfaceComposer == nullptr);
+ ALOGD("SurfaceComposerClient created");
+ mSurfaceComposer->enableVSyncInjections(true);
+}
+
+void FakeComposerClient::onSurfaceFlingerStop() {
+ mSurfaceComposer->dispose();
+ mSurfaceComposer.clear();
+}
+
+// Includes destroyed layers, stored in order of creation.
+int FakeComposerClient::getLayerCount() const {
+ return mLayers.size();
+}
+
+Layer FakeComposerClient::getLayer(size_t index) const {
+ // NOTE: If/when passing calls through to actual implementation,
+ // this might get more involving.
+ return static_cast<Layer>(index);
+}
diff --git a/services/surfaceflinger/tests/fakehwc/FakeComposerClient.h b/services/surfaceflinger/tests/fakehwc/FakeComposerClient.h
new file mode 100644
index 0000000..2a5a8ad
--- /dev/null
+++ b/services/surfaceflinger/tests/fakehwc/FakeComposerClient.h
@@ -0,0 +1,156 @@
+/*
+ * 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 "ComposerClient.h"
+#include "RenderState.h"
+
+// Needed for display type/ID enums
+#include <hardware/hwcomposer_defs.h>
+
+#include <utils/Condition.h>
+
+#include <chrono>
+
+using namespace android::hardware::graphics::composer::V2_1;
+using namespace android::hardware::graphics::composer::V2_1::implementation;
+using namespace android::hardware;
+using namespace std::chrono_literals;
+
+namespace {
+class LayerImpl;
+class Frame;
+class DelayedEventGenerator;
+} // namespace
+
+namespace android {
+class SurfaceComposerClient;
+} // namespace android
+
+namespace sftest {
+
+// NOTE: The ID's need to be exactly these. VR composer and parts of
+// the SurfaceFlinger assume the display IDs to have these values
+// despite the enum being documented as a display type.
+// TODO: Reference to actual documentation
+constexpr Display PRIMARY_DISPLAY = static_cast<Display>(HWC_DISPLAY_PRIMARY);
+constexpr Display EXTERNAL_DISPLAY = static_cast<Display>(HWC_DISPLAY_EXTERNAL);
+
+class FakeComposerClient : public ComposerBase {
+public:
+ FakeComposerClient();
+ virtual ~FakeComposerClient();
+
+ void removeClient() override;
+ void enableCallback(bool enable) override;
+ uint32_t getMaxVirtualDisplayCount() override;
+ Error createVirtualDisplay(uint32_t width, uint32_t height, PixelFormat* format,
+ Display* outDisplay) override;
+ Error destroyVirtualDisplay(Display display) override;
+ Error createLayer(Display display, Layer* outLayer) override;
+ Error destroyLayer(Display display, Layer layer) override;
+
+ Error getActiveConfig(Display display, Config* outConfig) override;
+ Error getClientTargetSupport(Display display, uint32_t width, uint32_t height,
+ PixelFormat format, Dataspace dataspace) override;
+ Error getColorModes(Display display, hidl_vec<ColorMode>* outModes) override;
+ Error getDisplayAttribute(Display display, Config config, IComposerClient::Attribute attribute,
+ int32_t* outValue) override;
+ Error getDisplayConfigs(Display display, hidl_vec<Config>* outConfigs) override;
+ Error getDisplayName(Display display, hidl_string* outName) override;
+ Error getDisplayType(Display display, IComposerClient::DisplayType* outType) override;
+ Error getDozeSupport(Display display, bool* outSupport) override;
+ Error getHdrCapabilities(Display display, hidl_vec<Hdr>* outTypes, float* outMaxLuminance,
+ float* outMaxAverageLuminance, float* outMinLuminance) override;
+
+ Error setActiveConfig(Display display, Config config) override;
+ Error setColorMode(Display display, ColorMode mode) override;
+ Error setPowerMode(Display display, IComposerClient::PowerMode mode) override;
+ Error setVsyncEnabled(Display display, IComposerClient::Vsync enabled) override;
+
+ Error setColorTransform(Display display, const float* matrix, int32_t hint) override;
+ Error setClientTarget(Display display, buffer_handle_t target, int32_t acquireFence,
+ int32_t dataspace, const std::vector<hwc_rect_t>& damage) override;
+ Error setOutputBuffer(Display display, buffer_handle_t buffer, int32_t releaseFence) override;
+ Error validateDisplay(Display display, std::vector<Layer>* outChangedLayers,
+ std::vector<IComposerClient::Composition>* outCompositionTypes,
+ uint32_t* outDisplayRequestMask, std::vector<Layer>* outRequestedLayers,
+ std::vector<uint32_t>* outRequestMasks) override;
+ Error acceptDisplayChanges(Display display) override;
+ Error presentDisplay(Display display, int32_t* outPresentFence, std::vector<Layer>* outLayers,
+ std::vector<int32_t>* outReleaseFences) override;
+
+ Error setLayerCursorPosition(Display display, Layer layer, int32_t x, int32_t y) override;
+ Error setLayerBuffer(Display display, Layer layer, buffer_handle_t buffer,
+ int32_t acquireFence) override;
+ Error setLayerSurfaceDamage(Display display, Layer layer,
+ const std::vector<hwc_rect_t>& damage) override;
+ Error setLayerBlendMode(Display display, Layer layer, int32_t mode) override;
+ Error setLayerColor(Display display, Layer layer, IComposerClient::Color color) override;
+ Error setLayerCompositionType(Display display, Layer layer, int32_t type) override;
+ Error setLayerDataspace(Display display, Layer layer, int32_t dataspace) override;
+ Error setLayerDisplayFrame(Display display, Layer layer, const hwc_rect_t& frame) override;
+ Error setLayerPlaneAlpha(Display display, Layer layer, float alpha) override;
+ Error setLayerSidebandStream(Display display, Layer layer, buffer_handle_t stream) override;
+ Error setLayerSourceCrop(Display display, Layer layer, const hwc_frect_t& crop) override;
+ Error setLayerTransform(Display display, Layer layer, int32_t transform) override;
+ Error setLayerVisibleRegion(Display display, Layer layer,
+ const std::vector<hwc_rect_t>& visible) override;
+ Error setLayerZOrder(Display display, Layer layer, uint32_t z) override;
+
+ void setClient(ComposerClient* client);
+
+ void requestVSync(uint64_t vsyncTime = 0);
+ // We don't want tests hanging, so always use a timeout. Remember
+ // to always check the number of frames with test ASSERT_!
+ // Wait until next frame is rendered after requesting vsync.
+ void runVSyncAndWait(std::chrono::nanoseconds maxWait = 100ms);
+ void runVSyncAfter(std::chrono::nanoseconds wait);
+
+ int getFrameCount() const;
+ // We don't want tests hanging, so always use a timeout. Remember
+ // to always check the number of frames with test ASSERT_!
+ void waitUntilFrame(int targetFrame, std::chrono::nanoseconds maxWait = 100ms) const;
+ std::vector<RenderState> getFrameRects(int frame) const;
+ std::vector<RenderState> getLatestFrame() const;
+ void clearFrames();
+
+ void onSurfaceFlingerStart();
+ void onSurfaceFlingerStop();
+
+ int getLayerCount() const;
+ Layer getLayer(size_t index) const;
+
+ void hotplugDisplay(Display display, IComposerCallback::Connection state);
+
+private:
+ LayerImpl& getLayerImpl(Layer handle);
+
+ bool mCallbacksOn;
+ ComposerClient* mClient;
+ Config mCurrentConfig;
+ bool mVsyncEnabled;
+ std::vector<std::unique_ptr<LayerImpl>> mLayers;
+ std::vector<std::unique_ptr<Frame>> mFrames;
+ // Using a pointer to hide the implementation into the CPP file.
+ std::unique_ptr<DelayedEventGenerator> mDelayedEventGenerator;
+ android::sp<android::SurfaceComposerClient> mSurfaceComposer; // For VSync injections
+ mutable android::Mutex mStateMutex;
+ mutable android::Condition mFramesAvailable;
+};
+
+} // namespace sftest
diff --git a/services/surfaceflinger/tests/fakehwc/FakeComposerService.cpp b/services/surfaceflinger/tests/fakehwc/FakeComposerService.cpp
new file mode 100644
index 0000000..c411604
--- /dev/null
+++ b/services/surfaceflinger/tests/fakehwc/FakeComposerService.cpp
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#define LOG_NDEBUG 0
+#undef LOG_TAG
+#define LOG_TAG "FakeHwcService"
+#include <log/log.h>
+
+#include "FakeComposerService.h"
+
+using namespace android::hardware;
+
+namespace sftest {
+
+FakeComposerService::FakeComposerService(android::sp<ComposerClient>& client) : mClient(client) {}
+
+FakeComposerService::~FakeComposerService() {
+ ALOGI("Maybe killing client %p", mClient.get());
+ // Rely on sp to kill the client.
+}
+
+Return<void> FakeComposerService::getCapabilities(getCapabilities_cb hidl_cb) {
+ ALOGI("FakeComposerService::getCapabilities");
+ hidl_cb(hidl_vec<Capability>());
+ return Void();
+}
+
+Return<void> FakeComposerService::dumpDebugInfo(dumpDebugInfo_cb hidl_cb) {
+ ALOGI("FakeComposerService::dumpDebugInfo");
+ hidl_cb(hidl_string());
+ return Void();
+}
+
+Return<void> FakeComposerService::createClient(createClient_cb hidl_cb) {
+ ALOGI("FakeComposerService::createClient %p", mClient.get());
+ mClient->initialize();
+ hidl_cb(Error::NONE, mClient);
+ return Void();
+}
+
+} // namespace sftest
diff --git a/services/surfaceflinger/tests/fakehwc/FakeComposerService.h b/services/surfaceflinger/tests/fakehwc/FakeComposerService.h
new file mode 100644
index 0000000..5204084
--- /dev/null
+++ b/services/surfaceflinger/tests/fakehwc/FakeComposerService.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 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 "ComposerClient.h"
+
+using namespace android::hardware::graphics::composer::V2_1;
+using namespace android::hardware::graphics::composer::V2_1::implementation;
+using android::hardware::Return;
+
+namespace sftest {
+
+class FakeComposerService : public IComposer {
+public:
+ FakeComposerService(android::sp<ComposerClient>& client);
+ virtual ~FakeComposerService();
+
+ Return<void> getCapabilities(getCapabilities_cb hidl_cb) override;
+ Return<void> dumpDebugInfo(dumpDebugInfo_cb hidl_cb) override;
+ Return<void> createClient(createClient_cb hidl_cb) override;
+
+private:
+ android::sp<ComposerClient> mClient;
+};
+
+} // namespace sftest
diff --git a/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.cpp b/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.cpp
new file mode 100644
index 0000000..51956ec
--- /dev/null
+++ b/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.cpp
@@ -0,0 +1,183 @@
+/*
+ * 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.
+ */
+
+#define LOG_NDEBUG 0
+#undef LOG_TAG
+#define LOG_TAG "FakeHwcUtil"
+#include <log/log.h>
+
+#include "FakeComposerUtils.h"
+#include "RenderState.h"
+
+#include "SurfaceFlinger.h" // Get the name of the service...
+
+#include <binder/IServiceManager.h>
+
+#include <cutils/properties.h>
+
+#include <iomanip>
+#include <thread>
+
+using android::String16;
+using android::sp;
+using namespace std::chrono_literals;
+using namespace sftest;
+using std::setw;
+
+namespace sftest {
+
+// clang-format off
+inline void printSourceRectAligned(::std::ostream& os, const hwc_frect_t& sourceRect, int align) {
+ os << std::fixed << std::setprecision(1) << "("
+ << setw(align) << sourceRect.left << setw(0) << ","
+ << setw(align) << sourceRect.top << setw(0) << ","
+ << setw(align) << sourceRect.right << setw(0) << ","
+ << setw(align) << sourceRect.bottom << setw(0) << ")";
+}
+
+inline void printDisplayRectAligned(::std::ostream& os, const hwc_rect_t& displayRect, int align) {
+ os << "("
+ << setw(align) << displayRect.left << setw(0) << ","
+ << setw(align) << displayRect.top << setw(0) << ","
+ << setw(align) << displayRect.right << setw(0) << ","
+ << setw(align) << displayRect.bottom << setw(0) << ")";
+}
+// clang-format on
+
+inline ::std::ostream& operator<<(::std::ostream& os, const sftest::RenderState& state) {
+ printSourceRectAligned(os, state.mSourceCrop, 7);
+ os << "->";
+ printDisplayRectAligned(os, state.mDisplayFrame, 5);
+ return os << " Swaps:" << state.mSwapCount << " Alpha:" << std::setprecision(3)
+ << state.mPlaneAlpha << " Xform:" << state.mTransform;
+}
+
+// Helper for verifying the parts of the RenderState
+template <typename T>
+bool valuesMatch(::testing::AssertionResult& message, const T& ref, const T& val,
+ const char* name) {
+ if (ref != val) {
+ message = message << "Expected " << name << ":" << ref << ", got:" << val << ".";
+ return false;
+ }
+ return true;
+}
+
+::testing::AssertionResult rectsAreSame(const RenderState& ref, const RenderState& val) {
+ // TODO: Message could start as success and be assigned as failure.
+ // Only problem is that utility assumes it to be failure and just adds stuff. Would
+ // need still special case the initial failure in the utility?
+ // TODO: ... or would it be possible to break this back to gtest primitives?
+ ::testing::AssertionResult message = ::testing::AssertionFailure();
+ bool passes = true;
+
+ // The work here is mostly about providing good log strings for differences
+ passes &= valuesMatch(message, ref.mDisplayFrame, val.mDisplayFrame, "display frame");
+ passes &= valuesMatch(message, ref.mPlaneAlpha, val.mPlaneAlpha, "alpha");
+ passes &= valuesMatch(message, ref.mSwapCount, val.mSwapCount, "swap count");
+ passes &= valuesMatch(message, ref.mSourceCrop, val.mSourceCrop, "source crop");
+ // ... add more
+ if (passes) {
+ return ::testing::AssertionSuccess();
+ }
+ return message;
+}
+
+::testing::AssertionResult framesAreSame(const std::vector<RenderState>& ref,
+ const std::vector<RenderState>& val) {
+ ::testing::AssertionResult message = ::testing::AssertionFailure();
+ bool passed = true;
+ if (ref.size() != val.size()) {
+ message << "Expected " << ref.size() << " rects, got " << val.size() << ".";
+ passed = false;
+ }
+ for (size_t rectIndex = 0; rectIndex < std::min(ref.size(), val.size()); rectIndex++) {
+ ::testing::AssertionResult rectResult = rectsAreSame(ref[rectIndex], val[rectIndex]);
+ if (rectResult == false) {
+ message << "First different rect at " << rectIndex << ": " << rectResult.message();
+ passed = false;
+ break;
+ }
+ }
+
+ if (passed) {
+ return ::testing::AssertionSuccess();
+ } else {
+ message << "\nReference:";
+ for (auto state = ref.begin(); state != ref.end(); ++state) {
+ message << "\n" << *state;
+ }
+ message << "\nActual:";
+ for (auto state = val.begin(); state != val.end(); ++state) {
+ message << "\n" << *state;
+ }
+ }
+ return message;
+}
+
+void startSurfaceFlinger() {
+ ALOGI("Start SurfaceFlinger");
+ system("start surfaceflinger");
+
+ sp<android::IServiceManager> sm(android::defaultServiceManager());
+ sp<android::IBinder> sf;
+ while (sf == nullptr) {
+ std::this_thread::sleep_for(10ms);
+ sf = sm->checkService(String16(android::SurfaceFlinger::getServiceName()));
+ }
+ ALOGV("SurfaceFlinger running");
+}
+
+void stopSurfaceFlinger() {
+ ALOGI("Stop SurfaceFlinger");
+ system("stop surfaceflinger");
+ sp<android::IServiceManager> sm(android::defaultServiceManager());
+ sp<android::IBinder> sf;
+ while (sf != nullptr) {
+ std::this_thread::sleep_for(10ms);
+ sf = sm->checkService(String16(android::SurfaceFlinger::getServiceName()));
+ }
+ ALOGV("SurfaceFlinger stopped");
+}
+
+////////////////////////////////////////////////
+
+void FakeHwcEnvironment::SetUp() {
+ ALOGI("Test env setup");
+ system("setenforce 0");
+ system("stop");
+ property_set("debug.sf.nobootanimation", "1");
+ {
+ char value[PROPERTY_VALUE_MAX];
+ property_get("debug.sf.nobootanimation", value, "0");
+ LOG_FATAL_IF(atoi(value) != 1, "boot skip not set");
+ }
+ // TODO: Try registering the mock as the default service instead.
+ property_set("debug.sf.hwc_service_name", "mock");
+ // This allows the SurfaceFlinger to load a HIDL service not listed in manifest files.
+ property_set("debug.sf.treble_testing_override", "true");
+}
+
+void FakeHwcEnvironment::TearDown() {
+ ALOGI("Test env tear down");
+ system("stop");
+ // Wait for mock call signaling teardown?
+ property_set("debug.sf.nobootanimation", "0");
+ property_set("debug.sf.hwc_service_name", "default");
+ ALOGI("Test env tear down - done");
+}
+
+} // namespace sftest
diff --git a/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.h b/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.h
new file mode 100644
index 0000000..1258a97
--- /dev/null
+++ b/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.h
@@ -0,0 +1,122 @@
+/*
+ * 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 "FakeComposerClient.h"
+
+#include <gui/SurfaceComposerClient.h>
+
+#include <hardware/hwcomposer_defs.h>
+
+#include <log/log.h>
+
+#include <gtest/gtest.h>
+
+// clang-format off
+// Note: This needs to reside in the global namespace for the GTest to use it
+inline ::std::ostream& operator<<(::std::ostream& os, const hwc_rect_t& rect) {
+ return os << "(" << rect.left << ","
+ << rect.top << ","
+ << rect.right << ","
+ << rect.bottom << ")";
+}
+
+inline ::std::ostream& operator<<(::std::ostream& os, const hwc_frect_t& rect) {
+ return os << "(" << rect.left << ","
+ << rect.top << ","
+ << rect.right << ","
+ << rect.bottom << ")";
+}
+// clang-format on
+
+namespace sftest {
+
+class RenderState;
+
+// clang-format off
+inline bool operator==(const hwc_rect_t& a, const hwc_rect_t& b) {
+ return a.top == b.top &&
+ a.left == b.left &&
+ a.bottom == b.bottom &&
+ a.right == b.right;
+}
+
+inline bool operator==(const hwc_frect_t& a, const hwc_frect_t& b) {
+ return a.top == b.top &&
+ a.left == b.left &&
+ a.bottom == b.bottom &&
+ a.right == b.right;
+}
+// clang-format on
+
+inline bool operator!=(const hwc_rect_t& a, const hwc_rect_t& b) {
+ return !(a == b);
+}
+
+inline bool operator!=(const hwc_frect_t& a, const hwc_frect_t& b) {
+ return !(a == b);
+}
+
+::testing::AssertionResult rectsAreSame(const RenderState& ref, const RenderState& val);
+::testing::AssertionResult framesAreSame(const std::vector<RenderState>& ref,
+ const std::vector<RenderState>& val);
+
+void startSurfaceFlinger();
+void stopSurfaceFlinger();
+
+class FakeHwcEnvironment : public ::testing::Environment {
+public:
+ virtual ~FakeHwcEnvironment() {}
+ void SetUp() override;
+ void TearDown() override;
+};
+
+/*
+ * All surface state changes are supposed to happen inside a global
+ * transaction. TransactionScope object at the beginning of
+ * scope automates the process. The resulting scope gives a visual cue
+ * on the span of the transaction as well.
+ *
+ * Closing the transaction is synchronous, i.e., it waits for
+ * SurfaceFlinger to composite one frame. Now, the FakeComposerClient
+ * is built to explicitly request vsyncs one at the time. A delayed
+ * request must be made before closing the transaction or the test
+ * thread stalls until SurfaceFlinger does an emergency vsync by
+ * itself. TransactionScope encapsulates this vsync magic.
+ */
+class TransactionScope : public android::SurfaceComposerClient::Transaction {
+public:
+ TransactionScope(FakeComposerClient& composer) :
+ Transaction(),
+ mComposer(composer) {
+ }
+
+ ~TransactionScope() {
+ int frameCount = mComposer.getFrameCount();
+ mComposer.runVSyncAfter(1ms);
+ LOG_ALWAYS_FATAL_IF(android::NO_ERROR != apply());
+ // Make sure that exactly one frame has been rendered.
+ mComposer.waitUntilFrame(frameCount + 1);
+ LOG_ALWAYS_FATAL_IF(frameCount + 1 != mComposer.getFrameCount(),
+ "Unexpected frame advance. Delta: %d",
+ mComposer.getFrameCount() - frameCount);
+ }
+
+ FakeComposerClient& mComposer;
+};
+
+} // namespace sftest
diff --git a/services/surfaceflinger/tests/fakehwc/RenderState.h b/services/surfaceflinger/tests/fakehwc/RenderState.h
new file mode 100644
index 0000000..0059289
--- /dev/null
+++ b/services/surfaceflinger/tests/fakehwc/RenderState.h
@@ -0,0 +1,44 @@
+/*
+ * 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 <hardware/hwcomposer2.h>
+
+#include <vector>
+
+namespace sftest {
+// Description of a rendered rectangle. Should only contain
+// instructions necessary to rasterize the rectangle. The full scene
+// is given as a sorted list of rectangles, bottom layer at index 0.
+class RenderState {
+public:
+ RenderState() = default;
+ // Default copy-ctor
+
+ hwc_rect_t mDisplayFrame = {0, 0, 0, 0};
+ hwc_frect_t mSourceCrop = {0.f, 0.f, 0.f, 0.f};
+ std::vector<hwc_rect_t> mVisibleRegion;
+ hwc2_blend_mode_t mBlendMode = HWC2_BLEND_MODE_NONE;
+ buffer_handle_t mBuffer = 0;
+ uint32_t mSwapCount = 0; // How many set buffer calls to the layer.
+ int32_t mAcquireFence = 0; // Probably should not be here.
+ float mPlaneAlpha = 0.f;
+ hwc_color_t mLayerColor = {0, 0, 0, 0};
+ hwc_transform_t mTransform = static_cast<hwc_transform_t>(0);
+};
+
+} // namespace sftest
diff --git a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
new file mode 100644
index 0000000..7f4c58a
--- /dev/null
+++ b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
@@ -0,0 +1,1300 @@
+/*
+ * Copyright (C) 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.
+ */
+
+// #define LOG_NDEBUG 0
+#undef LOG_TAG
+#define LOG_TAG "FakeHwcTest"
+
+#include "FakeComposerClient.h"
+#include "FakeComposerService.h"
+#include "FakeComposerUtils.h"
+
+#include <gui/ISurfaceComposer.h>
+#include <gui/LayerDebugInfo.h>
+#include <gui/LayerState.h>
+#include <gui/Surface.h>
+#include <gui/SurfaceComposerClient.h>
+
+#include <private/gui/ComposerService.h>
+
+#include <ui/DisplayInfo.h>
+
+#include <android/native_window.h>
+
+#include <android/hidl/manager/1.0/IServiceManager.h>
+
+#include <hwbinder/ProcessState.h>
+
+#include <binder/ProcessState.h>
+
+#include <log/log.h>
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <limits>
+
+using namespace std::chrono_literals;
+
+using namespace android;
+using namespace android::hardware;
+
+using namespace sftest;
+
+namespace {
+
+// Mock test helpers
+using ::testing::Invoke;
+using ::testing::Return;
+using ::testing::SetArgPointee;
+using ::testing::_;
+
+using Transaction = SurfaceComposerClient::Transaction;
+
+///////////////////////////////////////////////
+
+struct TestColor {
+public:
+ uint8_t r;
+ uint8_t g;
+ uint8_t b;
+ uint8_t a;
+};
+
+constexpr static TestColor RED = {195, 63, 63, 255};
+constexpr static TestColor LIGHT_RED = {255, 177, 177, 255};
+constexpr static TestColor GREEN = {63, 195, 63, 255};
+constexpr static TestColor BLUE = {63, 63, 195, 255};
+constexpr static TestColor DARK_GRAY = {63, 63, 63, 255};
+constexpr static TestColor LIGHT_GRAY = {200, 200, 200, 255};
+
+// Fill an RGBA_8888 formatted surface with a single color.
+static void fillSurfaceRGBA8(const sp<SurfaceControl>& sc, const TestColor& color,
+ bool unlock = true) {
+ ANativeWindow_Buffer outBuffer;
+ sp<Surface> s = sc->getSurface();
+ ASSERT_TRUE(s != nullptr);
+ ASSERT_EQ(NO_ERROR, s->lock(&outBuffer, nullptr));
+ uint8_t* img = reinterpret_cast<uint8_t*>(outBuffer.bits);
+ for (int y = 0; y < outBuffer.height; y++) {
+ for (int x = 0; x < outBuffer.width; x++) {
+ uint8_t* pixel = img + (4 * (y * outBuffer.stride + x));
+ pixel[0] = color.r;
+ pixel[1] = color.g;
+ pixel[2] = color.b;
+ pixel[3] = color.a;
+ }
+ }
+ if (unlock) {
+ ASSERT_EQ(NO_ERROR, s->unlockAndPost());
+ }
+}
+
+inline RenderState makeSimpleRect(int left, int top, int right, int bottom) {
+ RenderState res;
+ res.mDisplayFrame = hwc_rect_t{left, top, right, bottom};
+ res.mPlaneAlpha = 1.0f;
+ res.mSwapCount = 0;
+ res.mSourceCrop = hwc_frect_t{0.f, 0.f, static_cast<float>(right - left),
+ static_cast<float>(bottom - top)};
+ return res;
+}
+
+inline RenderState makeSimpleRect(unsigned int left, unsigned int top, unsigned int right,
+ unsigned int bottom) {
+ EXPECT_LE(left, static_cast<unsigned int>(INT_MAX));
+ EXPECT_LE(top, static_cast<unsigned int>(INT_MAX));
+ EXPECT_LE(right, static_cast<unsigned int>(INT_MAX));
+ EXPECT_LE(bottom, static_cast<unsigned int>(INT_MAX));
+ return makeSimpleRect(static_cast<int>(left), static_cast<int>(top), static_cast<int>(right),
+ static_cast<int>(bottom));
+}
+
+////////////////////////////////////////////////
+
+class DisplayTest : public ::testing::Test {
+public:
+ class MockComposerClient : public FakeComposerClient {
+ public:
+ MOCK_METHOD2(getDisplayType, Error(Display display, ComposerClient::DisplayType* outType));
+ MOCK_METHOD4(getDisplayAttribute,
+ Error(Display display, Config config, IComposerClient::Attribute attribute,
+ int32_t* outValue));
+
+ // Re-routing to basic fake implementation
+ Error getDisplayAttributeFake(Display display, Config config,
+ IComposerClient::Attribute attribute, int32_t* outValue) {
+ return FakeComposerClient::getDisplayAttribute(display, config, attribute, outValue);
+ }
+ };
+
+protected:
+ void SetUp() override;
+ void TearDown() override;
+
+ sp<IComposer> mFakeService;
+ sp<SurfaceComposerClient> mComposerClient;
+
+ MockComposerClient* mMockComposer;
+};
+
+void DisplayTest::SetUp() {
+ // TODO: The mMockComposer should be a unique_ptr, but it needs to
+ // outlive the test class. Currently ComposerClient only dies
+ // when the service is replaced. The Mock deletes itself when
+ // removeClient is called on it, which is ugly. This can be
+ // changed if HIDL ServiceManager allows removing services or
+ // ComposerClient starts taking the ownership of the contained
+ // implementation class. Moving the fake class to the HWC2
+ // interface instead of the current Composer interface might also
+ // change the situation.
+ mMockComposer = new MockComposerClient;
+ sp<ComposerClient> client = new ComposerClient(*mMockComposer);
+ mMockComposer->setClient(client.get());
+ mFakeService = new FakeComposerService(client);
+ mFakeService->registerAsService("mock");
+
+ android::hardware::ProcessState::self()->startThreadPool();
+ android::ProcessState::self()->startThreadPool();
+
+ EXPECT_CALL(*mMockComposer, getDisplayType(PRIMARY_DISPLAY, _))
+ .WillOnce(DoAll(SetArgPointee<1>(IComposerClient::DisplayType::PHYSICAL),
+ Return(Error::NONE)));
+ // Primary display will be queried twice for all 5 attributes. One
+ // set of queries comes from the SurfaceFlinger proper an the
+ // other set from the VR composer.
+ // TODO: Is VR composer always present? Change to atLeast(5)?
+ EXPECT_CALL(*mMockComposer, getDisplayAttribute(PRIMARY_DISPLAY, 1, _, _))
+ .Times(2 * 5)
+ .WillRepeatedly(Invoke(mMockComposer, &MockComposerClient::getDisplayAttributeFake));
+
+ startSurfaceFlinger();
+
+ // Fake composer wants to enable VSync injection
+ mMockComposer->onSurfaceFlingerStart();
+
+ mComposerClient = new SurfaceComposerClient;
+ ASSERT_EQ(NO_ERROR, mComposerClient->initCheck());
+}
+
+void DisplayTest::TearDown() {
+ mComposerClient->dispose();
+ mComposerClient = nullptr;
+
+ // Fake composer needs to release SurfaceComposerClient before the stop.
+ mMockComposer->onSurfaceFlingerStop();
+ stopSurfaceFlinger();
+
+ mFakeService = nullptr;
+ // TODO: Currently deleted in FakeComposerClient::removeClient(). Devise better lifetime
+ // management.
+ mMockComposer = nullptr;
+}
+
+TEST_F(DisplayTest, Hotplug) {
+ ALOGD("DisplayTest::Hotplug");
+
+ EXPECT_CALL(*mMockComposer, getDisplayType(EXTERNAL_DISPLAY, _))
+ .Times(2)
+ .WillRepeatedly(DoAll(SetArgPointee<1>(IComposerClient::DisplayType::PHYSICAL),
+ Return(Error::NONE)));
+ // The attribute queries will get done twice. This is for defaults
+ EXPECT_CALL(*mMockComposer, getDisplayAttribute(EXTERNAL_DISPLAY, 1, _, _))
+ .Times(2 * 3)
+ .WillRepeatedly(Invoke(mMockComposer, &MockComposerClient::getDisplayAttributeFake));
+ // ... and then special handling for dimensions. Specifying this
+ // rules later means that gmock will try them first, i.e.,
+ // ordering of width/height vs. the default implementation for
+ // other queries is significant.
+ EXPECT_CALL(*mMockComposer,
+ getDisplayAttribute(EXTERNAL_DISPLAY, 1, IComposerClient::Attribute::WIDTH, _))
+ .Times(2)
+ .WillRepeatedly(DoAll(SetArgPointee<3>(400), Return(Error::NONE)));
+
+ EXPECT_CALL(*mMockComposer,
+ getDisplayAttribute(EXTERNAL_DISPLAY, 1, IComposerClient::Attribute::HEIGHT, _))
+ .Times(2)
+ .WillRepeatedly(DoAll(SetArgPointee<3>(200), Return(Error::NONE)));
+
+ // TODO: Width and height queries are not actually called. Display
+ // info returns dimensions 0x0 in display info. Why?
+
+ mMockComposer->hotplugDisplay(EXTERNAL_DISPLAY, IComposerCallback::Connection::CONNECTED);
+
+ {
+ sp<android::IBinder> display(
+ SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdHdmi));
+ DisplayInfo info;
+ SurfaceComposerClient::getDisplayInfo(display, &info);
+ ASSERT_EQ(400u, info.w);
+ ASSERT_EQ(200u, info.h);
+
+ auto surfaceControl =
+ mComposerClient->createSurface(String8("Display Test Surface Foo"), info.w, info.h,
+ PIXEL_FORMAT_RGBA_8888, 0);
+ ASSERT_TRUE(surfaceControl != nullptr);
+ ASSERT_TRUE(surfaceControl->isValid());
+ fillSurfaceRGBA8(surfaceControl, BLUE);
+
+ {
+ TransactionScope ts(*mMockComposer);
+ ts.setDisplayLayerStack(display, 0);
+
+ ts.setLayer(surfaceControl, INT32_MAX - 2)
+ .show(surfaceControl);
+ }
+ }
+
+ mMockComposer->hotplugDisplay(EXTERNAL_DISPLAY, IComposerCallback::Connection::DISCONNECTED);
+
+ mMockComposer->clearFrames();
+
+ mMockComposer->hotplugDisplay(EXTERNAL_DISPLAY, IComposerCallback::Connection::CONNECTED);
+
+ {
+ sp<android::IBinder> display(
+ SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdHdmi));
+ DisplayInfo info;
+ SurfaceComposerClient::getDisplayInfo(display, &info);
+ ASSERT_EQ(400u, info.w);
+ ASSERT_EQ(200u, info.h);
+
+ auto surfaceControl =
+ mComposerClient->createSurface(String8("Display Test Surface Bar"), info.w, info.h,
+ PIXEL_FORMAT_RGBA_8888, 0);
+ ASSERT_TRUE(surfaceControl != nullptr);
+ ASSERT_TRUE(surfaceControl->isValid());
+ fillSurfaceRGBA8(surfaceControl, BLUE);
+
+ {
+ TransactionScope ts(*mMockComposer);
+ ts.setDisplayLayerStack(display, 0);
+
+ ts.setLayer(surfaceControl, INT32_MAX - 2)
+ .show(surfaceControl);
+ }
+ }
+ mMockComposer->hotplugDisplay(EXTERNAL_DISPLAY, IComposerCallback::Connection::DISCONNECTED);
+}
+
+////////////////////////////////////////////////
+
+class TransactionTest : public ::testing::Test {
+protected:
+ // Layer array indexing constants.
+ constexpr static int BG_LAYER = 0;
+ constexpr static int FG_LAYER = 1;
+
+ static void SetUpTestCase();
+ static void TearDownTestCase();
+
+ void SetUp() override;
+ void TearDown() override;
+
+ sp<SurfaceComposerClient> mComposerClient;
+ sp<SurfaceControl> mBGSurfaceControl;
+ sp<SurfaceControl> mFGSurfaceControl;
+ std::vector<RenderState> mBaseFrame;
+ uint32_t mDisplayWidth;
+ uint32_t mDisplayHeight;
+
+ static FakeComposerClient* sFakeComposer;
+};
+
+FakeComposerClient* TransactionTest::sFakeComposer;
+
+void TransactionTest::SetUpTestCase() {
+ // TODO: See TODO comment at DisplayTest::SetUp for background on
+ // the lifetime of the FakeComposerClient.
+ sFakeComposer = new FakeComposerClient;
+ sp<ComposerClient> client = new ComposerClient(*sFakeComposer);
+ sFakeComposer->setClient(client.get());
+ sp<IComposer> fakeService = new FakeComposerService(client);
+ fakeService->registerAsService("mock");
+
+ android::hardware::ProcessState::self()->startThreadPool();
+ android::ProcessState::self()->startThreadPool();
+
+ startSurfaceFlinger();
+
+ // Fake composer wants to enable VSync injection
+ sFakeComposer->onSurfaceFlingerStart();
+}
+
+void TransactionTest::TearDownTestCase() {
+ // Fake composer needs to release SurfaceComposerClient before the stop.
+ sFakeComposer->onSurfaceFlingerStop();
+ stopSurfaceFlinger();
+ // TODO: This is deleted when the ComposerClient calls
+ // removeClient. Devise better lifetime control.
+ sFakeComposer = nullptr;
+}
+
+void TransactionTest::SetUp() {
+ ALOGI("TransactionTest::SetUp");
+ mComposerClient = new SurfaceComposerClient;
+ ASSERT_EQ(NO_ERROR, mComposerClient->initCheck());
+
+ ALOGI("TransactionTest::SetUp - display");
+ sp<android::IBinder> display(
+ SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
+ DisplayInfo info;
+ SurfaceComposerClient::getDisplayInfo(display, &info);
+
+ mDisplayWidth = info.w;
+ mDisplayHeight = info.h;
+
+ // Background surface
+ mBGSurfaceControl = mComposerClient->createSurface(String8("BG Test Surface"), mDisplayWidth,
+ mDisplayHeight, PIXEL_FORMAT_RGBA_8888, 0);
+ ASSERT_TRUE(mBGSurfaceControl != nullptr);
+ ASSERT_TRUE(mBGSurfaceControl->isValid());
+ fillSurfaceRGBA8(mBGSurfaceControl, BLUE);
+
+ // Foreground surface
+ mFGSurfaceControl = mComposerClient->createSurface(String8("FG Test Surface"), 64, 64,
+ PIXEL_FORMAT_RGBA_8888, 0);
+ ASSERT_TRUE(mFGSurfaceControl != nullptr);
+ ASSERT_TRUE(mFGSurfaceControl->isValid());
+
+ fillSurfaceRGBA8(mFGSurfaceControl, RED);
+
+ Transaction t;
+ t.setDisplayLayerStack(display, 0);
+
+ t.setLayer(mBGSurfaceControl, INT32_MAX - 2);
+ t.show(mBGSurfaceControl);
+
+ t.setLayer(mFGSurfaceControl, INT32_MAX - 1);
+ t.setPosition(mFGSurfaceControl, 64, 64);
+ t.show(mFGSurfaceControl);
+
+ // Synchronous transaction will stop this thread, so we set up a
+ // delayed, off-thread vsync request before closing the
+ // transaction. In the test code this is usually done with
+ // TransactionScope. Leaving here in the 'vanilla' form for
+ // reference.
+ ASSERT_EQ(0, sFakeComposer->getFrameCount());
+ sFakeComposer->runVSyncAfter(1ms);
+ t.apply();
+ sFakeComposer->waitUntilFrame(1);
+
+ // Reference data. This is what the HWC should see.
+ static_assert(BG_LAYER == 0 && FG_LAYER == 1, "Unexpected enum values for array indexing");
+ mBaseFrame.push_back(makeSimpleRect(0u, 0u, mDisplayWidth, mDisplayHeight));
+ mBaseFrame[BG_LAYER].mSwapCount = 1;
+ mBaseFrame.push_back(makeSimpleRect(64, 64, 64 + 64, 64 + 64));
+ mBaseFrame[FG_LAYER].mSwapCount = 1;
+
+ auto frame = sFakeComposer->getFrameRects(0);
+ ASSERT_TRUE(framesAreSame(mBaseFrame, frame));
+}
+
+void TransactionTest::TearDown() {
+ ALOGD("TransactionTest::TearDown");
+
+ mComposerClient->dispose();
+ mBGSurfaceControl = 0;
+ mFGSurfaceControl = 0;
+ mComposerClient = 0;
+
+ sFakeComposer->runVSyncAndWait();
+ mBaseFrame.clear();
+ sFakeComposer->clearFrames();
+ ASSERT_EQ(0, sFakeComposer->getFrameCount());
+
+ sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+ std::vector<LayerDebugInfo> layers;
+ status_t result = sf->getLayerDebugInfo(&layers);
+ if (result != NO_ERROR) {
+ ALOGE("Failed to get layers %s %d", strerror(-result), result);
+ } else {
+ // If this fails, the test being torn down leaked layers.
+ EXPECT_EQ(0u, layers.size());
+ if (layers.size() > 0) {
+ for (auto layer = layers.begin(); layer != layers.end(); ++layer) {
+ std::cout << to_string(*layer).c_str();
+ }
+ // To ensure the next test has clean slate, will run the class
+ // tear down and setup here.
+ TearDownTestCase();
+ SetUpTestCase();
+ }
+ }
+ ALOGD("TransactionTest::TearDown - complete");
+}
+
+TEST_F(TransactionTest, LayerMove) {
+ ALOGD("TransactionTest::LayerMove");
+
+ // The scope opens and closes a global transaction and, at the
+ // same time, makes sure the SurfaceFlinger progresses one frame
+ // after the transaction closes. The results of the transaction
+ // should be available in the latest frame stored by the fake
+ // composer.
+ {
+ TransactionScope ts(*sFakeComposer);
+ ts.setPosition(mFGSurfaceControl, 128, 128);
+ // NOTE: No changes yet, so vsync will do nothing, HWC does not get any calls.
+ // (How to verify that? Throw in vsync and wait a 2x frame time? Separate test?)
+ //
+ // sFakeComposer->runVSyncAndWait();
+ }
+
+ fillSurfaceRGBA8(mFGSurfaceControl, GREEN);
+ sFakeComposer->runVSyncAndWait();
+
+ ASSERT_EQ(3, sFakeComposer->getFrameCount()); // Make sure the waits didn't time out and there's
+ // no extra frames.
+
+ // NOTE: Frame 0 is produced in the SetUp.
+ auto frame1Ref = mBaseFrame;
+ frame1Ref[FG_LAYER].mDisplayFrame =
+ hwc_rect_t{128, 128, 128 + 64, 128 + 64}; // Top-most layer moves.
+ EXPECT_TRUE(framesAreSame(frame1Ref, sFakeComposer->getFrameRects(1)));
+
+ auto frame2Ref = frame1Ref;
+ frame2Ref[FG_LAYER].mSwapCount++;
+ EXPECT_TRUE(framesAreSame(frame2Ref, sFakeComposer->getFrameRects(2)));
+}
+
+TEST_F(TransactionTest, LayerResize) {
+ ALOGD("TransactionTest::LayerResize");
+ {
+ TransactionScope ts(*sFakeComposer);
+ ts.setSize(mFGSurfaceControl, 128, 128);
+ }
+
+ fillSurfaceRGBA8(mFGSurfaceControl, GREEN);
+ sFakeComposer->runVSyncAndWait();
+
+ ASSERT_EQ(3, sFakeComposer->getFrameCount()); // Make sure the waits didn't time out and there's
+ // no extra frames.
+
+ auto frame1Ref = mBaseFrame;
+ // NOTE: The resize should not be visible for frame 1 as there's no buffer with new size posted.
+ EXPECT_TRUE(framesAreSame(frame1Ref, sFakeComposer->getFrameRects(1)));
+
+ auto frame2Ref = frame1Ref;
+ frame2Ref[FG_LAYER].mSwapCount++;
+ frame2Ref[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 64 + 128, 64 + 128};
+ frame2Ref[FG_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 128.f, 128.f};
+ EXPECT_TRUE(framesAreSame(frame2Ref, sFakeComposer->getFrameRects(2)));
+}
+
+TEST_F(TransactionTest, LayerCrop) {
+ // TODO: Add scaling to confirm that crop happens in buffer space?
+ {
+ TransactionScope ts(*sFakeComposer);
+ Rect cropRect(16, 16, 32, 32);
+ ts.setCrop(mFGSurfaceControl, cropRect);
+ }
+ ASSERT_EQ(2, sFakeComposer->getFrameCount());
+
+ auto referenceFrame = mBaseFrame;
+ referenceFrame[FG_LAYER].mSourceCrop = hwc_frect_t{16.f, 16.f, 32.f, 32.f};
+ referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{64 + 16, 64 + 16, 64 + 32, 64 + 32};
+ EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+}
+
+TEST_F(TransactionTest, LayerFinalCrop) {
+ // TODO: Add scaling to confirm that crop happens in display space?
+ {
+ TransactionScope ts(*sFakeComposer);
+ Rect cropRect(32, 32, 32 + 64, 32 + 64);
+ ts.setFinalCrop(mFGSurfaceControl, cropRect);
+ }
+ ASSERT_EQ(2, sFakeComposer->getFrameCount());
+
+ // In display space we are cropping with [32, 32, 96, 96] against display rect
+ // [64, 64, 128, 128]. Should yield display rect [64, 64, 96, 96]
+ auto referenceFrame = mBaseFrame;
+ referenceFrame[FG_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 32.f, 32.f};
+ referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 64 + 32, 64 + 32};
+
+ EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+}
+
+TEST_F(TransactionTest, LayerFinalCropEmpty) {
+ // TODO: Add scaling to confirm that crop happens in display space?
+ {
+ TransactionScope ts(*sFakeComposer);
+ Rect cropRect(16, 16, 32, 32);
+ ts.setFinalCrop(mFGSurfaceControl, cropRect);
+ }
+ ASSERT_EQ(2, sFakeComposer->getFrameCount());
+
+ // In display space we are cropping with [16, 16, 32, 32] against display rect
+ // [64, 64, 128, 128]. The intersection is empty and only the background layer is composited.
+ std::vector<RenderState> referenceFrame(1);
+ referenceFrame[BG_LAYER] = mBaseFrame[BG_LAYER];
+ EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+}
+
+TEST_F(TransactionTest, LayerSetLayer) {
+ {
+ TransactionScope ts(*sFakeComposer);
+ ts.setLayer(mFGSurfaceControl, INT_MAX - 3);
+ }
+ ASSERT_EQ(2, sFakeComposer->getFrameCount());
+
+ // The layers will switch order, but both are rendered because the background layer is
+ // transparent (RGBA8888).
+ std::vector<RenderState> referenceFrame(2);
+ referenceFrame[0] = mBaseFrame[FG_LAYER];
+ referenceFrame[1] = mBaseFrame[BG_LAYER];
+ EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+}
+
+TEST_F(TransactionTest, LayerSetLayerOpaque) {
+ {
+ TransactionScope ts(*sFakeComposer);
+ ts.setLayer(mFGSurfaceControl, INT_MAX - 3);
+ ts.setFlags(mBGSurfaceControl, layer_state_t::eLayerOpaque,
+ layer_state_t::eLayerOpaque);
+ }
+ ASSERT_EQ(2, sFakeComposer->getFrameCount());
+
+ // The former foreground layer is now covered with opaque layer - it should have disappeared
+ std::vector<RenderState> referenceFrame(1);
+ referenceFrame[BG_LAYER] = mBaseFrame[BG_LAYER];
+ EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+}
+
+TEST_F(TransactionTest, SetLayerStack) {
+ ALOGD("TransactionTest::SetLayerStack");
+ {
+ TransactionScope ts(*sFakeComposer);
+ ts.setLayerStack(mFGSurfaceControl, 1);
+ }
+
+ // Foreground layer should have disappeared.
+ ASSERT_EQ(2, sFakeComposer->getFrameCount());
+ std::vector<RenderState> refFrame(1);
+ refFrame[BG_LAYER] = mBaseFrame[BG_LAYER];
+ EXPECT_TRUE(framesAreSame(refFrame, sFakeComposer->getLatestFrame()));
+}
+
+TEST_F(TransactionTest, LayerShowHide) {
+ ALOGD("TransactionTest::LayerShowHide");
+ {
+ TransactionScope ts(*sFakeComposer);
+ ts.hide(mFGSurfaceControl);
+ }
+
+ // Foreground layer should have disappeared.
+ ASSERT_EQ(2, sFakeComposer->getFrameCount());
+ std::vector<RenderState> refFrame(1);
+ refFrame[BG_LAYER] = mBaseFrame[BG_LAYER];
+ EXPECT_TRUE(framesAreSame(refFrame, sFakeComposer->getLatestFrame()));
+
+ {
+ TransactionScope ts(*sFakeComposer);
+ ts.show(mFGSurfaceControl);
+ }
+
+ // Foreground layer should be back
+ ASSERT_EQ(3, sFakeComposer->getFrameCount());
+ EXPECT_TRUE(framesAreSame(mBaseFrame, sFakeComposer->getLatestFrame()));
+}
+
+TEST_F(TransactionTest, LayerSetAlpha) {
+ {
+ TransactionScope ts(*sFakeComposer);
+ ts.setAlpha(mFGSurfaceControl, 0.75f);
+ }
+
+ ASSERT_EQ(2, sFakeComposer->getFrameCount());
+ auto referenceFrame = mBaseFrame;
+ referenceFrame[FG_LAYER].mPlaneAlpha = 0.75f;
+ EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+}
+
+TEST_F(TransactionTest, LayerSetFlags) {
+ {
+ TransactionScope ts(*sFakeComposer);
+ ts.setFlags(mFGSurfaceControl, layer_state_t::eLayerHidden,
+ layer_state_t::eLayerHidden);
+ }
+
+ // Foreground layer should have disappeared.
+ ASSERT_EQ(2, sFakeComposer->getFrameCount());
+ std::vector<RenderState> refFrame(1);
+ refFrame[BG_LAYER] = mBaseFrame[BG_LAYER];
+ EXPECT_TRUE(framesAreSame(refFrame, sFakeComposer->getLatestFrame()));
+}
+
+TEST_F(TransactionTest, LayerSetMatrix) {
+ struct matrixTestData {
+ float matrix[4];
+ hwc_transform_t expectedTransform;
+ hwc_rect_t expectedDisplayFrame;
+ };
+
+ // The matrix operates on the display frame and is applied before
+ // the position is added. So, the foreground layer rect is (0, 0,
+ // 64, 64) is first transformed, potentially yielding negative
+ // coordinates and then the position (64, 64) is added yielding
+ // the final on-screen rectangles given.
+
+ const matrixTestData MATRIX_TESTS[7] = // clang-format off
+ {{{-1.f, 0.f, 0.f, 1.f}, HWC_TRANSFORM_FLIP_H, {0, 64, 64, 128}},
+ {{1.f, 0.f, 0.f, -1.f}, HWC_TRANSFORM_FLIP_V, {64, 0, 128, 64}},
+ {{0.f, 1.f, -1.f, 0.f}, HWC_TRANSFORM_ROT_90, {0, 64, 64, 128}},
+ {{-1.f, 0.f, 0.f, -1.f}, HWC_TRANSFORM_ROT_180, {0, 0, 64, 64}},
+ {{0.f, -1.f, 1.f, 0.f}, HWC_TRANSFORM_ROT_270, {64, 0, 128, 64}},
+ {{0.f, 1.f, 1.f, 0.f}, HWC_TRANSFORM_FLIP_H_ROT_90, {64, 64, 128, 128}},
+ {{0.f, 1.f, 1.f, 0.f}, HWC_TRANSFORM_FLIP_V_ROT_90, {64, 64, 128, 128}}};
+ // clang-format on
+ constexpr int TEST_COUNT = sizeof(MATRIX_TESTS) / sizeof(matrixTestData);
+
+ for (int i = 0; i < TEST_COUNT; i++) {
+ // TODO: How to leverage the HWC2 stringifiers?
+ const matrixTestData& xform = MATRIX_TESTS[i];
+ SCOPED_TRACE(i);
+ {
+ TransactionScope ts(*sFakeComposer);
+ ts.setMatrix(mFGSurfaceControl, xform.matrix[0], xform.matrix[1],
+ xform.matrix[2], xform.matrix[3]);
+ }
+
+ auto referenceFrame = mBaseFrame;
+ referenceFrame[FG_LAYER].mTransform = xform.expectedTransform;
+ referenceFrame[FG_LAYER].mDisplayFrame = xform.expectedDisplayFrame;
+
+ EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+ }
+}
+
+#if 0
+TEST_F(TransactionTest, LayerSetMatrix2) {
+ {
+ TransactionScope ts(*sFakeComposer);
+ // TODO: PLEASE SPEC THE FUNCTION!
+ ts.setMatrix(mFGSurfaceControl, 0.11f, 0.123f,
+ -2.33f, 0.22f);
+ }
+ auto referenceFrame = mBaseFrame;
+ // TODO: Is this correct for sure?
+ //referenceFrame[FG_LAYER].mTransform = HWC_TRANSFORM_FLIP_V & HWC_TRANSFORM_ROT_90;
+
+ EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+}
+#endif
+
+TEST_F(TransactionTest, DeferredTransaction) {
+ // Synchronization surface
+ constexpr static int SYNC_LAYER = 2;
+ auto syncSurfaceControl = mComposerClient->createSurface(String8("Sync Test Surface"), 1, 1,
+ PIXEL_FORMAT_RGBA_8888, 0);
+ ASSERT_TRUE(syncSurfaceControl != nullptr);
+ ASSERT_TRUE(syncSurfaceControl->isValid());
+
+ fillSurfaceRGBA8(syncSurfaceControl, DARK_GRAY);
+
+ {
+ TransactionScope ts(*sFakeComposer);
+ ts.setLayer(syncSurfaceControl, INT32_MAX - 1);
+ ts.setPosition(syncSurfaceControl, mDisplayWidth - 2, mDisplayHeight - 2);
+ ts.show(syncSurfaceControl);
+ }
+ auto referenceFrame = mBaseFrame;
+ referenceFrame.push_back(makeSimpleRect(mDisplayWidth - 2, mDisplayHeight - 2,
+ mDisplayWidth - 1, mDisplayHeight - 1));
+ referenceFrame[SYNC_LAYER].mSwapCount = 1;
+ EXPECT_EQ(2, sFakeComposer->getFrameCount());
+ EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+
+ // set up two deferred transactions on different frames - these should not yield composited
+ // frames
+ {
+ TransactionScope ts(*sFakeComposer);
+ ts.setAlpha(mFGSurfaceControl, 0.75);
+ ts.deferTransactionUntil(mFGSurfaceControl,
+ syncSurfaceControl->getHandle(),
+ syncSurfaceControl->getSurface()->getNextFrameNumber());
+ }
+ EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+
+ {
+ TransactionScope ts(*sFakeComposer);
+ ts.setPosition(mFGSurfaceControl, 128, 128);
+ ts.deferTransactionUntil(mFGSurfaceControl,
+ syncSurfaceControl->getHandle(),
+ syncSurfaceControl->getSurface()->getNextFrameNumber() + 1);
+ }
+ EXPECT_EQ(4, sFakeComposer->getFrameCount());
+ EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+
+ // should trigger the first deferred transaction, but not the second one
+ fillSurfaceRGBA8(syncSurfaceControl, DARK_GRAY);
+ sFakeComposer->runVSyncAndWait();
+ EXPECT_EQ(5, sFakeComposer->getFrameCount());
+
+ referenceFrame[FG_LAYER].mPlaneAlpha = 0.75f;
+ referenceFrame[SYNC_LAYER].mSwapCount++;
+ EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+
+ // should show up immediately since it's not deferred
+ {
+ TransactionScope ts(*sFakeComposer);
+ ts.setAlpha(mFGSurfaceControl, 1.0);
+ }
+ referenceFrame[FG_LAYER].mPlaneAlpha = 1.f;
+ EXPECT_EQ(6, sFakeComposer->getFrameCount());
+ EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+
+ // trigger the second deferred transaction
+ fillSurfaceRGBA8(syncSurfaceControl, DARK_GRAY);
+ sFakeComposer->runVSyncAndWait();
+ // TODO: Compute from layer size?
+ referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{128, 128, 128 + 64, 128 + 64};
+ referenceFrame[SYNC_LAYER].mSwapCount++;
+ EXPECT_EQ(7, sFakeComposer->getFrameCount());
+ EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+}
+
+TEST_F(TransactionTest, SetRelativeLayer) {
+ constexpr int RELATIVE_LAYER = 2;
+ auto relativeSurfaceControl = mComposerClient->createSurface(String8("Test Surface"), 64, 64,
+ PIXEL_FORMAT_RGBA_8888, 0);
+ fillSurfaceRGBA8(relativeSurfaceControl, LIGHT_RED);
+
+ // Now we stack the surface above the foreground surface and make sure it is visible.
+ {
+ TransactionScope ts(*sFakeComposer);
+ ts.setPosition(relativeSurfaceControl, 64, 64);
+ ts.show(relativeSurfaceControl);
+ ts.setRelativeLayer(relativeSurfaceControl, mFGSurfaceControl->getHandle(), 1);
+ }
+ auto referenceFrame = mBaseFrame;
+ // NOTE: All three layers will be visible as the surfaces are
+ // transparent because of the RGBA format.
+ referenceFrame.push_back(makeSimpleRect(64, 64, 64 + 64, 64 + 64));
+ referenceFrame[RELATIVE_LAYER].mSwapCount = 1;
+ EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+
+ // A call to setLayer will override a call to setRelativeLayer
+ {
+ TransactionScope ts(*sFakeComposer);
+ ts.setLayer(relativeSurfaceControl, 0);
+ }
+
+ // Previous top layer will now appear at the bottom.
+ auto referenceFrame2 = mBaseFrame;
+ referenceFrame2.insert(referenceFrame2.begin(), referenceFrame[RELATIVE_LAYER]);
+ EXPECT_EQ(3, sFakeComposer->getFrameCount());
+ EXPECT_TRUE(framesAreSame(referenceFrame2, sFakeComposer->getLatestFrame()));
+}
+
+class ChildLayerTest : public TransactionTest {
+protected:
+ constexpr static int CHILD_LAYER = 2;
+
+ void SetUp() override {
+ TransactionTest::SetUp();
+ mChild = mComposerClient->createSurface(String8("Child surface"), 10, 10,
+ PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
+ fillSurfaceRGBA8(mChild, LIGHT_GRAY);
+
+ sFakeComposer->runVSyncAndWait();
+ mBaseFrame.push_back(makeSimpleRect(64, 64, 64 + 10, 64 + 10));
+ mBaseFrame[CHILD_LAYER].mSwapCount = 1;
+ ASSERT_EQ(2, sFakeComposer->getFrameCount());
+ ASSERT_TRUE(framesAreSame(mBaseFrame, sFakeComposer->getLatestFrame()));
+ }
+ void TearDown() override {
+ mChild = 0;
+ TransactionTest::TearDown();
+ }
+
+ sp<SurfaceControl> mChild;
+};
+
+TEST_F(ChildLayerTest, Positioning) {
+ {
+ TransactionScope ts(*sFakeComposer);
+ ts.show(mChild);
+ ts.setPosition(mChild, 10, 10);
+ // Move to the same position as in the original setup.
+ ts.setPosition(mFGSurfaceControl, 64, 64);
+ }
+
+ auto referenceFrame = mBaseFrame;
+ referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 64 + 64, 64 + 64};
+ referenceFrame[CHILD_LAYER].mDisplayFrame =
+ hwc_rect_t{64 + 10, 64 + 10, 64 + 10 + 10, 64 + 10 + 10};
+ EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+
+ {
+ TransactionScope ts(*sFakeComposer);
+ ts.setPosition(mFGSurfaceControl, 0, 0);
+ }
+
+ auto referenceFrame2 = mBaseFrame;
+ referenceFrame2[FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 0 + 64, 0 + 64};
+ referenceFrame2[CHILD_LAYER].mDisplayFrame =
+ hwc_rect_t{0 + 10, 0 + 10, 0 + 10 + 10, 0 + 10 + 10};
+ EXPECT_TRUE(framesAreSame(referenceFrame2, sFakeComposer->getLatestFrame()));
+}
+
+TEST_F(ChildLayerTest, Cropping) {
+ {
+ TransactionScope ts(*sFakeComposer);
+ ts.show(mChild);
+ ts.setPosition(mChild, 0, 0);
+ ts.setPosition(mFGSurfaceControl, 0, 0);
+ ts.setCrop(mFGSurfaceControl, Rect(0, 0, 5, 5));
+ }
+ // NOTE: The foreground surface would be occluded by the child
+ // now, but is included in the stack because the child is
+ // transparent.
+ auto referenceFrame = mBaseFrame;
+ referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 0 + 5, 0 + 5};
+ referenceFrame[FG_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 5.f, 5.f};
+ referenceFrame[CHILD_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 0 + 5, 0 + 5};
+ referenceFrame[CHILD_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 5.f, 5.f};
+ EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+}
+
+TEST_F(ChildLayerTest, FinalCropping) {
+ {
+ TransactionScope ts(*sFakeComposer);
+ ts.show(mChild);
+ ts.setPosition(mChild, 0, 0);
+ ts.setPosition(mFGSurfaceControl, 0, 0);
+ ts.setFinalCrop(mFGSurfaceControl, Rect(0, 0, 5, 5));
+ }
+ auto referenceFrame = mBaseFrame;
+ referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 0 + 5, 0 + 5};
+ referenceFrame[FG_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 5.f, 5.f};
+ referenceFrame[CHILD_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 0 + 5, 0 + 5};
+ referenceFrame[CHILD_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 5.f, 5.f};
+ EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+}
+
+TEST_F(ChildLayerTest, Constraints) {
+ {
+ TransactionScope ts(*sFakeComposer);
+ ts.show(mChild);
+ ts.setPosition(mFGSurfaceControl, 0, 0);
+ ts.setPosition(mChild, 63, 63);
+ }
+ auto referenceFrame = mBaseFrame;
+ referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 64, 64};
+ referenceFrame[CHILD_LAYER].mDisplayFrame = hwc_rect_t{63, 63, 64, 64};
+ referenceFrame[CHILD_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 1.f, 1.f};
+ EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+}
+
+TEST_F(ChildLayerTest, Scaling) {
+ {
+ TransactionScope ts(*sFakeComposer);
+ ts.setPosition(mFGSurfaceControl, 0, 0);
+ }
+ auto referenceFrame = mBaseFrame;
+ referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 64, 64};
+ referenceFrame[CHILD_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 10, 10};
+ EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+
+ {
+ TransactionScope ts(*sFakeComposer);
+ ts.setMatrix(mFGSurfaceControl, 2.0, 0, 0, 2.0);
+ }
+
+ auto referenceFrame2 = mBaseFrame;
+ referenceFrame2[FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 128, 128};
+ referenceFrame2[CHILD_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 20, 20};
+ EXPECT_TRUE(framesAreSame(referenceFrame2, sFakeComposer->getLatestFrame()));
+}
+
+TEST_F(ChildLayerTest, LayerAlpha) {
+ {
+ TransactionScope ts(*sFakeComposer);
+ ts.show(mChild);
+ ts.setPosition(mChild, 0, 0);
+ ts.setPosition(mFGSurfaceControl, 0, 0);
+ ts.setAlpha(mChild, 0.5);
+ }
+
+ auto referenceFrame = mBaseFrame;
+ referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 64, 64};
+ referenceFrame[CHILD_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 10, 10};
+ referenceFrame[CHILD_LAYER].mPlaneAlpha = 0.5f;
+ EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+
+ {
+ TransactionScope ts(*sFakeComposer);
+ ts.setAlpha(mFGSurfaceControl, 0.5);
+ }
+
+ auto referenceFrame2 = referenceFrame;
+ referenceFrame2[FG_LAYER].mPlaneAlpha = 0.5f;
+ referenceFrame2[CHILD_LAYER].mPlaneAlpha = 0.25f;
+ EXPECT_TRUE(framesAreSame(referenceFrame2, sFakeComposer->getLatestFrame()));
+}
+
+TEST_F(ChildLayerTest, ReparentChildren) {
+ {
+ TransactionScope ts(*sFakeComposer);
+ ts.show(mChild);
+ ts.setPosition(mChild, 10, 10);
+ ts.setPosition(mFGSurfaceControl, 64, 64);
+ }
+ auto referenceFrame = mBaseFrame;
+ referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 64 + 64, 64 + 64};
+ referenceFrame[CHILD_LAYER].mDisplayFrame =
+ hwc_rect_t{64 + 10, 64 + 10, 64 + 10 + 10, 64 + 10 + 10};
+ EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+
+ {
+ TransactionScope ts(*sFakeComposer);
+ ts.reparentChildren(mFGSurfaceControl, mBGSurfaceControl->getHandle());
+ }
+
+ auto referenceFrame2 = referenceFrame;
+ referenceFrame2[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 64 + 64, 64 + 64};
+ referenceFrame2[CHILD_LAYER].mDisplayFrame = hwc_rect_t{10, 10, 10 + 10, 10 + 10};
+ EXPECT_TRUE(framesAreSame(referenceFrame2, sFakeComposer->getLatestFrame()));
+}
+
+TEST_F(ChildLayerTest, DetachChildren) {
+ {
+ TransactionScope ts(*sFakeComposer);
+ ts.show(mChild);
+ ts.setPosition(mChild, 10, 10);
+ ts.setPosition(mFGSurfaceControl, 64, 64);
+ }
+
+ auto referenceFrame = mBaseFrame;
+ referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 64 + 64, 64 + 64};
+ referenceFrame[CHILD_LAYER].mDisplayFrame =
+ hwc_rect_t{64 + 10, 64 + 10, 64 + 10 + 10, 64 + 10 + 10};
+ EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+
+ {
+ TransactionScope ts(*sFakeComposer);
+ ts.detachChildren(mFGSurfaceControl);
+ }
+
+ {
+ TransactionScope ts(*sFakeComposer);
+ ts.hide(mChild);
+ }
+
+ // Nothing should have changed. The child control becomes a no-op
+ // zombie on detach. See comments for detachChildren in the
+ // SurfaceControl.h file.
+ EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+}
+
+TEST_F(ChildLayerTest, InheritNonTransformScalingFromParent) {
+ {
+ TransactionScope ts(*sFakeComposer);
+ ts.show(mChild);
+ ts.setPosition(mChild, 0, 0);
+ ts.setPosition(mFGSurfaceControl, 0, 0);
+ }
+
+ {
+ TransactionScope ts(*sFakeComposer);
+ ts.setOverrideScalingMode(mFGSurfaceControl, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
+ // We cause scaling by 2.
+ ts.setSize(mFGSurfaceControl, 128, 128);
+ }
+
+ auto referenceFrame = mBaseFrame;
+ referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 128, 128};
+ referenceFrame[FG_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 64.f, 64.f};
+ referenceFrame[CHILD_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 20, 20};
+ referenceFrame[CHILD_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 10.f, 10.f};
+ EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+}
+
+// Regression test for b/37673612
+TEST_F(ChildLayerTest, ChildrenWithParentBufferTransform) {
+ {
+ TransactionScope ts(*sFakeComposer);
+ ts.show(mChild);
+ ts.setPosition(mChild, 0, 0);
+ ts.setPosition(mFGSurfaceControl, 0, 0);
+ }
+
+ // We set things up as in b/37673612 so that there is a mismatch between the buffer size and
+ // the WM specified state size.
+ {
+ TransactionScope ts(*sFakeComposer);
+ ts.setSize(mFGSurfaceControl, 128, 64);
+ }
+
+ sp<Surface> s = mFGSurfaceControl->getSurface();
+ auto anw = static_cast<ANativeWindow*>(s.get());
+ native_window_set_buffers_transform(anw, NATIVE_WINDOW_TRANSFORM_ROT_90);
+ native_window_set_buffers_dimensions(anw, 64, 128);
+ fillSurfaceRGBA8(mFGSurfaceControl, RED);
+ sFakeComposer->runVSyncAndWait();
+
+ // The child should still be in the same place and not have any strange scaling as in
+ // b/37673612.
+ auto referenceFrame = mBaseFrame;
+ referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 128, 64};
+ referenceFrame[FG_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 64.f, 128.f};
+ referenceFrame[FG_LAYER].mSwapCount++;
+ referenceFrame[CHILD_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 10, 10};
+ EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+}
+
+TEST_F(ChildLayerTest, Bug36858924) {
+ // Destroy the child layer
+ mChild.clear();
+
+ // Now recreate it as hidden
+ mChild = mComposerClient->createSurface(String8("Child surface"), 10, 10,
+ PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eHidden,
+ mFGSurfaceControl.get());
+
+ // Show the child layer in a deferred transaction
+ {
+ TransactionScope ts(*sFakeComposer);
+ ts.deferTransactionUntil(mChild, mFGSurfaceControl->getHandle(),
+ mFGSurfaceControl->getSurface()->getNextFrameNumber());
+ ts.show(mChild);
+ }
+
+ // Render the foreground surface a few times
+ //
+ // Prior to the bugfix for b/36858924, this would usually hang while trying to fill the third
+ // frame because SurfaceFlinger would never process the deferred transaction and would therefore
+ // never acquire/release the first buffer
+ ALOGI("Filling 1");
+ fillSurfaceRGBA8(mFGSurfaceControl, GREEN);
+ sFakeComposer->runVSyncAndWait();
+ ALOGI("Filling 2");
+ fillSurfaceRGBA8(mFGSurfaceControl, BLUE);
+ sFakeComposer->runVSyncAndWait();
+ ALOGI("Filling 3");
+ fillSurfaceRGBA8(mFGSurfaceControl, RED);
+ sFakeComposer->runVSyncAndWait();
+ ALOGI("Filling 4");
+ fillSurfaceRGBA8(mFGSurfaceControl, GREEN);
+ sFakeComposer->runVSyncAndWait();
+}
+
+class LatchingTest : public TransactionTest {
+protected:
+ void lockAndFillFGBuffer() { fillSurfaceRGBA8(mFGSurfaceControl, RED, false); }
+
+ void unlockFGBuffer() {
+ sp<Surface> s = mFGSurfaceControl->getSurface();
+ ASSERT_EQ(NO_ERROR, s->unlockAndPost());
+ sFakeComposer->runVSyncAndWait();
+ }
+
+ void completeFGResize() {
+ fillSurfaceRGBA8(mFGSurfaceControl, RED);
+ sFakeComposer->runVSyncAndWait();
+ }
+ void restoreInitialState() {
+ TransactionScope ts(*sFakeComposer);
+ ts.setSize(mFGSurfaceControl, 64, 64);
+ ts.setPosition(mFGSurfaceControl, 64, 64);
+ ts.setCrop(mFGSurfaceControl, Rect(0, 0, 64, 64));
+ ts.setFinalCrop(mFGSurfaceControl, Rect(0, 0, -1, -1));
+ }
+};
+
+TEST_F(LatchingTest, SurfacePositionLatching) {
+ // By default position can be updated even while
+ // a resize is pending.
+ {
+ TransactionScope ts(*sFakeComposer);
+ ts.setSize(mFGSurfaceControl, 32, 32);
+ ts.setPosition(mFGSurfaceControl, 100, 100);
+ }
+
+ // The size should not have updated as we have not provided a new buffer.
+ auto referenceFrame1 = mBaseFrame;
+ referenceFrame1[FG_LAYER].mDisplayFrame = hwc_rect_t{100, 100, 100 + 64, 100 + 64};
+ EXPECT_TRUE(framesAreSame(referenceFrame1, sFakeComposer->getLatestFrame()));
+
+ restoreInitialState();
+
+ // Now we repeat with setGeometryAppliesWithResize
+ // and verify the position DOESN'T latch.
+ {
+ TransactionScope ts(*sFakeComposer);
+ ts.setGeometryAppliesWithResize(mFGSurfaceControl);
+ ts.setSize(mFGSurfaceControl, 32, 32);
+ ts.setPosition(mFGSurfaceControl, 100, 100);
+ }
+ EXPECT_TRUE(framesAreSame(mBaseFrame, sFakeComposer->getLatestFrame()));
+
+ completeFGResize();
+
+ auto referenceFrame2 = mBaseFrame;
+ referenceFrame2[FG_LAYER].mDisplayFrame = hwc_rect_t{100, 100, 100 + 32, 100 + 32};
+ referenceFrame2[FG_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 32.f, 32.f};
+ referenceFrame2[FG_LAYER].mSwapCount++;
+ EXPECT_TRUE(framesAreSame(referenceFrame2, sFakeComposer->getLatestFrame()));
+}
+
+TEST_F(LatchingTest, CropLatching) {
+ // Normally the crop applies immediately even while a resize is pending.
+ {
+ TransactionScope ts(*sFakeComposer);
+ ts.setSize(mFGSurfaceControl, 128, 128);
+ ts.setCrop(mFGSurfaceControl, Rect(0, 0, 63, 63));
+ }
+
+ auto referenceFrame1 = mBaseFrame;
+ referenceFrame1[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 64 + 63, 64 + 63};
+ referenceFrame1[FG_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 63.f, 63.f};
+ EXPECT_TRUE(framesAreSame(referenceFrame1, sFakeComposer->getLatestFrame()));
+
+ restoreInitialState();
+
+ {
+ TransactionScope ts(*sFakeComposer);
+ ts.setSize(mFGSurfaceControl, 128, 128);
+ ts.setGeometryAppliesWithResize(mFGSurfaceControl);
+ ts.setCrop(mFGSurfaceControl, Rect(0, 0, 63, 63));
+ }
+ EXPECT_TRUE(framesAreSame(mBaseFrame, sFakeComposer->getLatestFrame()));
+
+ completeFGResize();
+
+ auto referenceFrame2 = mBaseFrame;
+ referenceFrame2[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 64 + 63, 64 + 63};
+ referenceFrame2[FG_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 63.f, 63.f};
+ referenceFrame2[FG_LAYER].mSwapCount++;
+ EXPECT_TRUE(framesAreSame(referenceFrame2, sFakeComposer->getLatestFrame()));
+}
+
+TEST_F(LatchingTest, FinalCropLatching) {
+ // Normally the crop applies immediately even while a resize is pending.
+ {
+ TransactionScope ts(*sFakeComposer);
+ ts.setSize(mFGSurfaceControl, 128, 128);
+ ts.setFinalCrop(mFGSurfaceControl, Rect(64, 64, 127, 127));
+ }
+
+ auto referenceFrame1 = mBaseFrame;
+ referenceFrame1[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 127, 127};
+ referenceFrame1[FG_LAYER].mSourceCrop =
+ hwc_frect_t{0.f, 0.f, static_cast<float>(127 - 64), static_cast<float>(127 - 64)};
+ EXPECT_TRUE(framesAreSame(referenceFrame1, sFakeComposer->getLatestFrame()));
+
+ restoreInitialState();
+
+ {
+ TransactionScope ts(*sFakeComposer);
+ ts.setSize(mFGSurfaceControl, 128, 128);
+ ts.setGeometryAppliesWithResize(mFGSurfaceControl);
+ ts.setFinalCrop(mFGSurfaceControl, Rect(64, 64, 127, 127));
+ }
+ EXPECT_TRUE(framesAreSame(mBaseFrame, sFakeComposer->getLatestFrame()));
+
+ completeFGResize();
+
+ auto referenceFrame2 = mBaseFrame;
+ referenceFrame2[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 127, 127};
+ referenceFrame2[FG_LAYER].mSourceCrop =
+ hwc_frect_t{0.f, 0.f, static_cast<float>(127 - 64), static_cast<float>(127 - 64)};
+ referenceFrame2[FG_LAYER].mSwapCount++;
+ EXPECT_TRUE(framesAreSame(referenceFrame2, sFakeComposer->getLatestFrame()));
+}
+
+// In this test we ensure that setGeometryAppliesWithResize actually demands
+// a buffer of the new size, and not just any size.
+TEST_F(LatchingTest, FinalCropLatchingBufferOldSize) {
+ // Normally the crop applies immediately even while a resize is pending.
+ {
+ TransactionScope ts(*sFakeComposer);
+ ts.setSize(mFGSurfaceControl, 128, 128);
+ ts.setFinalCrop(mFGSurfaceControl, Rect(64, 64, 127, 127));
+ }
+
+ auto referenceFrame1 = mBaseFrame;
+ referenceFrame1[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 127, 127};
+ referenceFrame1[FG_LAYER].mSourceCrop =
+ hwc_frect_t{0.f, 0.f, static_cast<float>(127 - 64), static_cast<float>(127 - 64)};
+ EXPECT_TRUE(framesAreSame(referenceFrame1, sFakeComposer->getLatestFrame()));
+
+ restoreInitialState();
+
+ // In order to prepare to submit a buffer at the wrong size, we acquire it prior to
+ // initiating the resize.
+ lockAndFillFGBuffer();
+
+ {
+ TransactionScope ts(*sFakeComposer);
+ ts.setSize(mFGSurfaceControl, 128, 128);
+ ts.setGeometryAppliesWithResize(mFGSurfaceControl);
+ ts.setFinalCrop(mFGSurfaceControl, Rect(64, 64, 127, 127));
+ }
+ EXPECT_TRUE(framesAreSame(mBaseFrame, sFakeComposer->getLatestFrame()));
+
+ // We now submit our old buffer, at the old size, and ensure it doesn't
+ // trigger geometry latching.
+ unlockFGBuffer();
+
+ auto referenceFrame2 = mBaseFrame;
+ referenceFrame2[FG_LAYER].mSwapCount++;
+ EXPECT_TRUE(framesAreSame(referenceFrame2, sFakeComposer->getLatestFrame()));
+
+ completeFGResize();
+ auto referenceFrame3 = referenceFrame2;
+ referenceFrame3[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 127, 127};
+ referenceFrame3[FG_LAYER].mSourceCrop =
+ hwc_frect_t{0.f, 0.f, static_cast<float>(127 - 64), static_cast<float>(127 - 64)};
+ referenceFrame3[FG_LAYER].mSwapCount++;
+ EXPECT_TRUE(framesAreSame(referenceFrame3, sFakeComposer->getLatestFrame()));
+}
+
+TEST_F(LatchingTest, FinalCropLatchingRegressionForb37531386) {
+ // In this scenario, we attempt to set the final crop a second time while the resize
+ // is still pending, and ensure we are successful. Success meaning the second crop
+ // is the one which eventually latches and not the first.
+ {
+ TransactionScope ts(*sFakeComposer);
+ ts.setSize(mFGSurfaceControl, 128, 128);
+ ts.setGeometryAppliesWithResize(mFGSurfaceControl);
+ ts.setFinalCrop(mFGSurfaceControl, Rect(64, 64, 127, 127));
+ }
+
+ {
+ TransactionScope ts(*sFakeComposer);
+ ts.setFinalCrop(mFGSurfaceControl, Rect(0, 0, -1, -1));
+ }
+ EXPECT_TRUE(framesAreSame(mBaseFrame, sFakeComposer->getLatestFrame()));
+
+ completeFGResize();
+
+ auto referenceFrame = mBaseFrame;
+ referenceFrame[FG_LAYER].mSwapCount++;
+ EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+}
+
+} // namespace
+
+int main(int argc, char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+
+ sftest::FakeHwcEnvironment* fakeEnvironment = new sftest::FakeHwcEnvironment;
+ ::testing::AddGlobalTestEnvironment(fakeEnvironment);
+ ::testing::InitGoogleMock(&argc, argv);
+ return RUN_ALL_TESTS();
+}
diff --git a/services/surfaceflinger/tests/hwc2/Android.mk b/services/surfaceflinger/tests/hwc2/Android.mk
index 203ced5c..010ac9c 100644
--- a/services/surfaceflinger/tests/hwc2/Android.mk
+++ b/services/surfaceflinger/tests/hwc2/Android.mk
@@ -36,7 +36,9 @@
libui \
libgui \
liblog \
- libsync
+ libsync \
+ libhwui \
+ android.hardware.graphics.common@1.0
LOCAL_STATIC_LIBRARIES := \
libbase \
libadf \
@@ -49,6 +51,7 @@
Hwc2TestLayers.cpp \
Hwc2TestBuffer.cpp \
Hwc2TestClientTarget.cpp \
- Hwc2TestVirtualDisplay.cpp
+ Hwc2TestVirtualDisplay.cpp \
+ Hwc2TestPixelComparator.cpp
include $(BUILD_NATIVE_TEST)
diff --git a/services/surfaceflinger/tests/hwc2/Hwc2Test.cpp b/services/surfaceflinger/tests/hwc2/Hwc2Test.cpp
index 062485e..4878c14 100644
--- a/services/surfaceflinger/tests/hwc2/Hwc2Test.cpp
+++ b/services/surfaceflinger/tests/hwc2/Hwc2Test.cpp
@@ -382,7 +382,9 @@
if (outErr) {
*outErr = err;
} else {
- ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to set cursor position";
+ ASSERT_TRUE((err == HWC2_ERROR_NONE) ||
+ (err == HWC2_ERROR_BAD_LAYER)) <<
+ "failed to set cursor position";
}
}
@@ -652,7 +654,7 @@
hwc2_layer_request_t request = requests.at(i);
EXPECT_EQ(std::count(layers.begin(), layers.end(), requestedLayer),
- 0) << "get display requests returned an unknown layer";
+ 1) << "get display requests returned an unknown layer";
EXPECT_NE(request, 0) << "returned empty request for layer "
<< requestedLayer;
@@ -1603,9 +1605,10 @@
EXPECT_EQ(layers.size(), fences.size());
for (int32_t fence : fences) {
- EXPECT_GE(sync_wait(fence, msWait), 0);
- if (fence >= 0)
+ if (fence >= 0) {
+ EXPECT_GE(sync_wait(fence, msWait), 0);
close(fence);
+ }
}
}
@@ -1643,8 +1646,9 @@
testLayers->getBlendMode(layer)));
EXPECT_NO_FATAL_FAILURE(setLayerColor(display, layer,
testLayers->getColor(layer)));
- EXPECT_NO_FATAL_FAILURE(setCursorPosition(display, layer, cursor.left,
- cursor.top));
+ if (composition == HWC2_COMPOSITION_CURSOR)
+ EXPECT_NO_FATAL_FAILURE(setCursorPosition(display, layer,
+ cursor.left, cursor.top));
EXPECT_NO_FATAL_FAILURE(setLayerDataspace(display, layer,
testLayers->getDataspace(layer)));
EXPECT_NO_FATAL_FAILURE(setLayerDisplayFrame(display, layer,
@@ -1771,6 +1775,145 @@
}
}
+ void createAndPresentVirtualDisplay(size_t layerCnt,
+ Hwc2TestCoverage coverage,
+ const std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage>&
+ coverageExceptions)
+ {
+ Hwc2TestVirtualDisplay testVirtualDisplay(coverage);
+ hwc2_display_t display;
+ android_pixel_format_t desiredFormat = HAL_PIXEL_FORMAT_RGBA_8888;
+
+ do {
+ // Items dependent on the display dimensions
+ hwc2_error_t err = HWC2_ERROR_NONE;
+ const UnsignedArea& dimension =
+ testVirtualDisplay.getDisplayDimension();
+ ASSERT_NO_FATAL_FAILURE(createVirtualDisplay(dimension.width,
+ dimension.height, &desiredFormat, &display, &err));
+ ASSERT_TRUE(err == HWC2_ERROR_NONE)
+ << "Cannot allocate virtual display";
+
+ ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_ON));
+ ASSERT_NO_FATAL_FAILURE(enableVsync(display));
+
+ std::vector<hwc2_config_t> configs;
+ ASSERT_NO_FATAL_FAILURE(getDisplayConfigs(display, &configs));
+
+ for (auto config : configs) {
+ ASSERT_NO_FATAL_FAILURE(setActiveConfig(display, config));
+
+ Area displayArea;
+ ASSERT_NO_FATAL_FAILURE(getActiveDisplayArea(display,
+ &displayArea));
+
+ std::vector<hwc2_layer_t> layers;
+ ASSERT_NO_FATAL_FAILURE(createLayers(display, &layers,
+ layerCnt));
+ Hwc2TestLayers testLayers(layers, coverage, displayArea,
+ coverageExceptions);
+
+ /*
+ * Layouts that do not cover an entire virtual display will
+ * cause undefined behavior.
+ * Enable optimizeLayouts to avoid this.
+ */
+ testLayers.optimizeLayouts();
+ do {
+ // Items dependent on the testLayers properties
+ std::set<hwc2_layer_t> clientLayers;
+ std::set<hwc2_layer_t> clearLayers;
+ uint32_t numTypes, numRequests;
+ bool hasChanges, skip;
+ bool flipClientTarget;
+ int32_t presentFence;
+ Hwc2TestClientTarget testClientTarget;
+ buffer_handle_t outputBufferHandle;
+ android::base::unique_fd outputBufferReleaseFence;
+
+ ASSERT_NO_FATAL_FAILURE(setLayerProperties(display, layers,
+ &testLayers, &skip));
+
+ if (skip)
+ continue;
+
+ ASSERT_NO_FATAL_FAILURE(validateDisplay(display, &numTypes,
+ &numRequests, &hasChanges));
+
+ if (hasChanges)
+ EXPECT_LE(numTypes, static_cast<uint32_t>(layers.size()))
+ << "wrong number of requests";
+
+ ASSERT_NO_FATAL_FAILURE(handleCompositionChanges(display,
+ testLayers, layers, numTypes, &clientLayers));
+
+ ASSERT_NO_FATAL_FAILURE(handleRequests(display, layers,
+ numRequests, &clearLayers, &flipClientTarget));
+ ASSERT_NO_FATAL_FAILURE(setClientTarget(display,
+ &testClientTarget, testLayers, clientLayers,
+ clearLayers, flipClientTarget, displayArea));
+ ASSERT_NO_FATAL_FAILURE(acceptDisplayChanges(display));
+
+ ASSERT_EQ(testVirtualDisplay.getOutputBuffer(
+ &outputBufferHandle, &outputBufferReleaseFence), 0);
+ ASSERT_NO_FATAL_FAILURE(setOutputBuffer(display,
+ outputBufferHandle, outputBufferReleaseFence));
+
+ EXPECT_NO_FATAL_FAILURE(presentDisplay(display,
+ &presentFence));
+ ASSERT_NO_FATAL_FAILURE(closeFences(display, presentFence));
+
+ ASSERT_EQ(testVirtualDisplay.verifyOutputBuffer(&testLayers,
+ &layers, &clearLayers), 0);
+
+ /*
+ * Upscaling the image causes minor pixel differences.
+ * Work around this by using some threshold.
+ *
+ * Fail test if we are off by more than 1% of our
+ * pixels.
+ */
+ ComparatorResult& comparatorResult = ComparatorResult::get();
+ int threshold = (dimension.width * dimension.height) / 100;
+ double diffPercent = (comparatorResult.getDifferentPixelCount() * 100.0) /
+ (dimension.width * dimension.height);
+
+ if (comparatorResult.getDifferentPixelCount() != 0)
+ EXPECT_TRUE(false)
+ << comparatorResult.getDifferentPixelCount() << " pixels ("
+ << diffPercent << "%) are different.";
+
+ if (comparatorResult.getDifferentPixelCount() > threshold) {
+ EXPECT_TRUE(false)
+ << "Mismatched pixel count exceeds threshold. "
+ << "Writing buffers to file.";
+
+ const ::testing::TestInfo* const test_info =
+ ::testing::UnitTest::GetInstance()
+ ->current_test_info();
+
+ EXPECT_EQ(testVirtualDisplay.writeBuffersToFile(
+ test_info->name()), 0)
+ << "Failed to write buffers.";
+ }
+
+ ASSERT_LE(comparatorResult.getDifferentPixelCount(), threshold)
+ << comparatorResult.getDifferentPixelCount() << " pixels ("
+ << diffPercent << "%) are different. "
+ << "Exceeds 1% threshold, terminating test. "
+ << "Test case: " << testLayers.dump();
+
+ } while (testLayers.advance());
+
+ ASSERT_NO_FATAL_FAILURE(destroyLayers(display,
+ std::move(layers)));
+ }
+ ASSERT_NO_FATAL_FAILURE(disableVsync(display));
+ ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_OFF));
+ ASSERT_NO_FATAL_FAILURE(destroyVirtualDisplay(display));
+ } while (testVirtualDisplay.advance());
+ }
+
hwc2_device_t* mHwc2Device = nullptr;
enum class Hwc2TestHotplugStatus {
@@ -2895,7 +3038,6 @@
ASSERT_NO_FATAL_FAILURE(setLayerProperty(Hwc2TestCoverage::Complete,
[] (Hwc2Test* test, hwc2_display_t display, hwc2_layer_t layer,
Hwc2TestLayer* testLayer, hwc2_error_t* outErr) {
-
const hwc_rect_t cursorPosition = testLayer->getCursorPosition();
EXPECT_NO_FATAL_FAILURE(test->setCursorPosition(display, layer,
cursorPosition.left, cursorPosition.top, outErr));
@@ -4406,11 +4548,11 @@
/* TESTCASE: Tests that the HWC2 cannot destroy a physical display. */
TEST_F(Hwc2Test, DESTROY_VIRTUAL_DISPLAY_bad_parameter)
{
- hwc2_display_t display = HWC_DISPLAY_PRIMARY;
hwc2_error_t err = HWC2_ERROR_NONE;
-
- ASSERT_NO_FATAL_FAILURE(destroyVirtualDisplay(display, &err));
- EXPECT_EQ(err, HWC2_ERROR_BAD_PARAMETER) << "returned wrong error code";
+ for (auto display : mDisplays) {
+ ASSERT_NO_FATAL_FAILURE(destroyVirtualDisplay(display, &err));
+ EXPECT_EQ(err, HWC2_ERROR_BAD_PARAMETER) << "returned wrong error code";
+ }
}
/* TESTCASE: Tests that the HWC2 can get the max virtual display count. */
@@ -4476,7 +4618,7 @@
buffer_handle_t handle;
android::base::unique_fd acquireFence;
- if (testVirtualDisplay->getBuffer(&handle, &acquireFence) >= 0)
+ if (testVirtualDisplay->getOutputBuffer(&handle, &acquireFence) >= 0)
EXPECT_NO_FATAL_FAILURE(test->setOutputBuffer(display,
handle, acquireFence));
}));
@@ -4496,7 +4638,7 @@
ASSERT_NO_FATAL_FAILURE(test->getBadDisplay(&badDisplay));
- if (testVirtualDisplay->getBuffer(&handle, &acquireFence) < 0)
+ if (testVirtualDisplay->getOutputBuffer(&handle, &acquireFence) < 0)
return;
ASSERT_NO_FATAL_FAILURE(test->setOutputBuffer(badDisplay,
@@ -4536,7 +4678,7 @@
android::base::unique_fd acquireFence;
hwc2_error_t err = HWC2_ERROR_NONE;
- if (testVirtualDisplay.getBuffer(&handle, &acquireFence) < 0)
+ if (testVirtualDisplay.getOutputBuffer(&handle, &acquireFence) < 0)
continue;
ASSERT_NO_FATAL_FAILURE(setOutputBuffer(display, handle,
@@ -4554,3 +4696,74 @@
ASSERT_NO_FATAL_FAILURE(dump(&buffer));
}
+
+/*
+ * TODO(b/64724708): Hwc2TestPropertyName::BufferArea MUST be default for all
+ * virtual display tests as we don't handle this case correctly.
+ *
+ * Only default dataspace is supported in our drawing code.
+ */
+const std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage>
+ virtualDisplayExceptions =
+ {{Hwc2TestPropertyName::BufferArea, Hwc2TestCoverage::Default},
+ {Hwc2TestPropertyName::Dataspace, Hwc2TestCoverage::Default}};
+
+/* TESTCASE: Tests that the HWC2 can present 1 layer with default coverage on a
+ * virtual display. */
+TEST_F(Hwc2Test, PRESENT_VIRTUAL_DISPLAY_default_1)
+{
+ Hwc2TestCoverage coverage = Hwc2TestCoverage::Default;
+ const size_t layerCnt = 1;
+ ASSERT_NO_FATAL_FAILURE(createAndPresentVirtualDisplay(layerCnt, coverage,
+ virtualDisplayExceptions));
+}
+
+/* TESTCASE: Tests that the HWC2 can present 1 layer with basic coverage on a
+ * virtual display. */
+TEST_F(Hwc2Test, PRESENT_VIRTUAL_DISPLAY_basic_1)
+{
+ Hwc2TestCoverage coverage = Hwc2TestCoverage::Basic;
+ const size_t layerCnt = 1;
+ ASSERT_NO_FATAL_FAILURE(createAndPresentVirtualDisplay(layerCnt, coverage,
+ virtualDisplayExceptions));
+}
+
+/* TESTCASE: Tests that the HWC2 can present 2 layers with default coverage on a
+ * virtual display. */
+TEST_F(Hwc2Test, PRESENT_VIRTUAL_DISPLAY_default_2)
+{
+ Hwc2TestCoverage coverage = Hwc2TestCoverage::Default;
+ const size_t layerCnt = 2;
+ ASSERT_NO_FATAL_FAILURE(createAndPresentVirtualDisplay(layerCnt, coverage,
+ virtualDisplayExceptions));
+}
+
+/* TESTCASE: Tests that the HWC2 can present 3 layers with default coverage on a
+ * virtual display. */
+TEST_F(Hwc2Test, PRESENT_VIRTUAL_DISPLAY_default_3)
+{
+ Hwc2TestCoverage coverage = Hwc2TestCoverage::Default;
+ const size_t layerCnt = 3;
+ ASSERT_NO_FATAL_FAILURE(createAndPresentVirtualDisplay(layerCnt, coverage,
+ virtualDisplayExceptions));
+}
+
+/* TESTCASE: Tests that the HWC2 can present 4 layers with default coverage on a
+ * virtual display. */
+TEST_F(Hwc2Test, PRESENT_VIRTUAL_DISPLAY_default_4)
+{
+ Hwc2TestCoverage coverage = Hwc2TestCoverage::Default;
+ const size_t layerCnt = 4;
+ ASSERT_NO_FATAL_FAILURE(createAndPresentVirtualDisplay(layerCnt, coverage,
+ virtualDisplayExceptions));
+}
+
+/* TESTCASE: Tests that the HWC2 can present 5 layers with default coverage on a
+ * virtual display. */
+TEST_F(Hwc2Test, PRESENT_VIRTUAL_DISPLAY_default_5)
+{
+ Hwc2TestCoverage coverage = Hwc2TestCoverage::Default;
+ const size_t layerCnt = 5;
+ ASSERT_NO_FATAL_FAILURE(createAndPresentVirtualDisplay(layerCnt, coverage,
+ virtualDisplayExceptions));
+}
diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestBuffer.cpp b/services/surfaceflinger/tests/hwc2/Hwc2TestBuffer.cpp
index 1d3a1d3..6484562 100644
--- a/services/surfaceflinger/tests/hwc2/Hwc2TestBuffer.cpp
+++ b/services/surfaceflinger/tests/hwc2/Hwc2TestBuffer.cpp
@@ -23,14 +23,17 @@
#include <gui/BufferItemConsumer.h>
#include <ui/GraphicBuffer.h>
+#include <android/hardware/graphics/common/1.0/types.h>
#include <math/vec4.h>
#include <GLES3/gl3.h>
-
+#include <SkImageEncoder.h>
+#include <SkStream.h>
#include "Hwc2TestBuffer.h"
#include "Hwc2TestLayers.h"
using namespace android;
+using android::hardware::graphics::common::V1_0::BufferUsage;
/* Returns a fence from egl */
typedef void (*FenceCallback)(int32_t fence, void* callbackArgs);
@@ -396,8 +399,9 @@
{
/* Create new graphic buffer with correct dimensions */
mGraphicBuffer = new GraphicBuffer(mBufferArea.width, mBufferArea.height,
- mFormat, GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_HW_RENDER,
- "hwc2_test_buffer");
+ mFormat, BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+ BufferUsage::COMPOSER_OVERLAY, "hwc2_test_buffer");
+
int ret = mGraphicBuffer->initCheck();
if (ret) {
return ret;
@@ -408,7 +412,8 @@
/* Locks the buffer for writing */
uint8_t* img;
- mGraphicBuffer->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
+ mGraphicBuffer->lock(static_cast<uint32_t>(BufferUsage::CPU_WRITE_OFTEN),
+ (void**)(&img));
uint32_t stride = mGraphicBuffer->getStride();
@@ -458,31 +463,22 @@
Hwc2TestClientTargetBuffer::~Hwc2TestClientTargetBuffer() { }
-/* Generates a client target buffer using the layers assigned for client
- * composition. Takes into account the individual layer properties such as
+/* Generates a buffer from layersToDraw.
+ * Takes into account the individual layer properties such as
* transform, blend mode, source crop, etc. */
-int Hwc2TestClientTargetBuffer::get(buffer_handle_t* outHandle,
- int32_t* outFence, const Area& bufferArea,
+static void compositeBufferFromLayers(
+ const android::sp<android::GraphicBuffer>& graphicBuffer,
+ android_pixel_format_t format, const Area& bufferArea,
const Hwc2TestLayers* testLayers,
- const std::set<hwc2_layer_t>* clientLayers,
+ const std::set<hwc2_layer_t>* layersToDraw,
const std::set<hwc2_layer_t>* clearLayers)
{
- /* Create new graphic buffer with correct dimensions */
- mGraphicBuffer = new GraphicBuffer(bufferArea.width, bufferArea.height,
- mFormat, GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_HW_RENDER,
- "hwc2_test_buffer");
- int ret = mGraphicBuffer->initCheck();
- if (ret) {
- return ret;
- }
- if (!mGraphicBuffer->handle) {
- return -EINVAL;
- }
-
+ /* Locks the buffer for writing */
uint8_t* img;
- mGraphicBuffer->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
+ graphicBuffer->lock(static_cast<uint32_t>(BufferUsage::CPU_WRITE_OFTEN),
+ (void**)(&img));
- uint32_t stride = mGraphicBuffer->getStride();
+ uint32_t stride = graphicBuffer->getStride();
float bWDiv3 = bufferArea.width / 3;
float bW2Div3 = bufferArea.width * 2 / 3;
@@ -497,10 +493,10 @@
uint8_t r = 0, g = 0, b = 0;
float a = 0.0f;
- /* Cycle through each client layer from back to front and
+ /* Cycle through each layer from back to front and
* update the pixel color. */
- for (auto layer = clientLayers->rbegin();
- layer != clientLayers->rend(); ++layer) {
+ for (auto layer = layersToDraw->rbegin();
+ layer != layersToDraw->rend(); ++layer) {
const hwc_rect_t df = testLayers->getDisplayFrame(*layer);
@@ -570,8 +566,8 @@
* (100x50) at the end of the transformation. */
if (transform & HWC_TRANSFORM_ROT_90) {
float tmp = xPos;
- xPos = -yPos * dfW / dfH;
- yPos = tmp * dfH / dfW;
+ xPos = yPos * dfW / dfH;
+ yPos = -tmp * dfH / dfW;
}
/* Change origin back to the top left corner of the
@@ -682,14 +678,114 @@
}
/* Set the pixel color */
- setColor(x, y, mFormat, stride, img, r, g, b, a * 255);
+ setColor(x, y, format, stride, img, r, g, b, a * 255);
}
}
- mGraphicBuffer->unlock();
+ graphicBuffer->unlock();
+}
+
+/* Generates a client target buffer using the layers assigned for client
+ * composition. Takes into account the individual layer properties such as
+ * transform, blend mode, source crop, etc. */
+int Hwc2TestClientTargetBuffer::get(buffer_handle_t* outHandle,
+ int32_t* outFence, const Area& bufferArea,
+ const Hwc2TestLayers* testLayers,
+ const std::set<hwc2_layer_t>* clientLayers,
+ const std::set<hwc2_layer_t>* clearLayers)
+{
+ /* Create new graphic buffer with correct dimensions */
+ mGraphicBuffer = new GraphicBuffer(bufferArea.width, bufferArea.height,
+ mFormat, BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+ BufferUsage::COMPOSER_OVERLAY, "hwc2_test_buffer");
+
+ int ret = mGraphicBuffer->initCheck();
+ if (ret)
+ return ret;
+
+ if (!mGraphicBuffer->handle)
+ return -EINVAL;
+
+ compositeBufferFromLayers(mGraphicBuffer, mFormat, bufferArea, testLayers,
+ clientLayers, clearLayers);
*outFence = mFenceGenerator->get();
*outHandle = mGraphicBuffer->handle;
return 0;
}
+
+void Hwc2TestVirtualBuffer::updateBufferArea(const Area& bufferArea)
+{
+ mBufferArea.width = bufferArea.width;
+ mBufferArea.height = bufferArea.height;
+}
+
+bool Hwc2TestVirtualBuffer::writeBufferToFile(std::string path)
+{
+ SkFILEWStream file(path.c_str());
+ const SkImageInfo info = SkImageInfo::Make(mBufferArea.width,
+ mBufferArea.height, SkColorType::kRGBA_8888_SkColorType,
+ SkAlphaType::kPremul_SkAlphaType);
+
+ uint8_t* img;
+ mGraphicBuffer->lock(static_cast<uint32_t>(BufferUsage::CPU_WRITE_OFTEN),
+ (void**)(&img));
+
+ SkPixmap pixmap(info, img, mGraphicBuffer->getStride());
+ bool result = file.isValid() && SkEncodeImage(&file, pixmap,
+ SkEncodedImageFormat::kPNG, 100);
+
+ mGraphicBuffer->unlock();
+ return result;
+}
+
+/* Generates a buffer that holds the expected result of compositing all of our
+ * layers */
+int Hwc2TestExpectedBuffer::generateExpectedBuffer(
+ const Hwc2TestLayers* testLayers,
+ const std::vector<hwc2_layer_t>* allLayers,
+ const std::set<hwc2_layer_t>* clearLayers)
+{
+ mGraphicBuffer = new GraphicBuffer(mBufferArea.width, mBufferArea.height,
+ mFormat, BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN,
+ "hwc2_test_buffer");
+
+ int ret = mGraphicBuffer->initCheck();
+ if (ret)
+ return ret;
+
+ if (!mGraphicBuffer->handle)
+ return -EINVAL;
+
+ const std::set<hwc2_layer_t> allLayerSet(allLayers->begin(),
+ allLayers->end());
+
+ compositeBufferFromLayers(mGraphicBuffer, mFormat, mBufferArea, testLayers,
+ &allLayerSet, clearLayers);
+
+ return 0;
+}
+
+int Hwc2TestOutputBuffer::getOutputBuffer(buffer_handle_t* outHandle,
+ int32_t* outFence)
+{
+ if (mBufferArea.width == -1 || mBufferArea.height == -1)
+ return -EINVAL;
+
+ mGraphicBuffer = new GraphicBuffer(mBufferArea.width, mBufferArea.height,
+ mFormat, BufferUsage::CPU_READ_OFTEN |
+ BufferUsage::GPU_RENDER_TARGET, "hwc2_test_buffer");
+
+ int ret = mGraphicBuffer->initCheck();
+ if (ret)
+ return ret;
+
+ if (!mGraphicBuffer->handle)
+ return -EINVAL;
+
+ *outFence = -1;
+ *outHandle = mGraphicBuffer->handle;
+
+ return 0;
+}
diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestBuffer.h b/services/surfaceflinger/tests/hwc2/Hwc2TestBuffer.h
index b2b3a66..fd54fef 100644
--- a/services/surfaceflinger/tests/hwc2/Hwc2TestBuffer.h
+++ b/services/surfaceflinger/tests/hwc2/Hwc2TestBuffer.h
@@ -71,4 +71,38 @@
const android_pixel_format_t mFormat = HAL_PIXEL_FORMAT_RGBA_8888;
};
+
+class Hwc2TestVirtualBuffer {
+public:
+ void updateBufferArea(const Area& bufferArea);
+
+ bool writeBufferToFile(std::string path);
+
+ android::sp<android::GraphicBuffer>& graphicBuffer()
+ {
+ return mGraphicBuffer;
+ }
+
+protected:
+ android::sp<android::GraphicBuffer> mGraphicBuffer;
+
+ Area mBufferArea = {-1, -1};
+
+ const android_pixel_format_t mFormat = HAL_PIXEL_FORMAT_RGBA_8888;
+};
+
+
+class Hwc2TestExpectedBuffer : public Hwc2TestVirtualBuffer {
+public:
+ int generateExpectedBuffer(const Hwc2TestLayers* testLayers,
+ const std::vector<hwc2_layer_t>* allLayers,
+ const std::set<hwc2_layer_t>* clearLayers);
+};
+
+
+class Hwc2TestOutputBuffer : public Hwc2TestVirtualBuffer {
+public:
+ int getOutputBuffer(buffer_handle_t* outHandle, int32_t* outFence);
+};
+
#endif /* ifndef _HWC2_TEST_BUFFER_H */
diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestPixelComparator.cpp b/services/surfaceflinger/tests/hwc2/Hwc2TestPixelComparator.cpp
new file mode 100644
index 0000000..904b927
--- /dev/null
+++ b/services/surfaceflinger/tests/hwc2/Hwc2TestPixelComparator.cpp
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 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 <sstream>
+#include <android/hardware/graphics/common/1.0/types.h>
+
+#include "Hwc2TestPixelComparator.h"
+
+using android::hardware::graphics::common::V1_0::BufferUsage;
+
+uint32_t ComparatorResult::getPixel(int32_t x, int32_t y, uint32_t stride,
+ uint8_t* img) const
+{
+ uint32_t r = img[(y * stride + x) * 4 + 0];
+ uint32_t g = img[(y * stride + x) * 4 + 1];
+ uint32_t b = img[(y * stride + x) * 4 + 2];
+ uint32_t a = img[(y * stride + x) * 4 + 3];
+
+ uint32_t pixel = 0;
+ pixel |= r;
+ pixel |= g << 8;
+ pixel |= b << 16;
+ pixel |= a << 24;
+ return pixel;
+}
+
+void ComparatorResult::CompareBuffers(
+ android::sp<android::GraphicBuffer>& resultBuffer,
+ android::sp<android::GraphicBuffer>& expectedBuffer)
+{
+ uint8_t* resultBufferImg;
+ uint8_t* expectedBufferImg;
+ resultBuffer->lock(static_cast<uint32_t>(BufferUsage::CPU_READ_OFTEN),
+ (void**)(&resultBufferImg));
+
+ expectedBuffer->lock(static_cast<uint32_t>(BufferUsage::CPU_READ_OFTEN),
+ (void**)(&expectedBufferImg));
+ mComparisons.clear();
+ int32_t mDifferentPixelCount = 0;
+ int32_t mBlankPixelCount = 0;
+
+ for (uint32_t y = 0; y < resultBuffer->getHeight(); y++) {
+ for (uint32_t x = 0; x < resultBuffer->getWidth(); x++) {
+ uint32_t result = getPixel(x, y, resultBuffer->getStride(),
+ resultBufferImg);
+ uint32_t expected = getPixel(x, y, expectedBuffer->getStride(),
+ expectedBufferImg);
+
+ if (result == 0)
+ mBlankPixelCount++;
+
+ if (result != expected)
+ mDifferentPixelCount++;
+
+ mComparisons.emplace_back(std::make_tuple(x, y, result, expected));
+ }
+ }
+ resultBuffer->unlock();
+ expectedBuffer->unlock();
+}
+
+std::string ComparatorResult::pixelDiff(uint32_t x, uint32_t y,
+ uint32_t resultPixel, uint32_t expectedPixel) const
+{
+ uint32_t resultAlpha = (resultPixel >> 24) & 0xFF;
+ uint32_t resultBlue = (resultPixel >> 16) & 0xFF;
+ uint32_t resultGreen = (resultPixel >> 8) & 0xFF;
+ uint32_t resultRed = resultPixel & 0xFF;
+
+ uint32_t expectedAlpha = (expectedPixel >> 24) & 0xFF;
+ uint32_t expectedBlue = (expectedPixel >> 16) & 0xFF;
+ uint32_t expectedGreen = (expectedPixel >> 8) & 0xFF;
+ uint32_t expectedRed = expectedPixel & 0xFF;
+
+ std::ostringstream stream;
+
+ stream << "x: " << x << " y: " << y << std::endl;
+ stream << std::hex;
+ stream << "Result pixel: " << resultRed << "|" << resultGreen << "|"
+ << resultBlue << "|" << resultAlpha << std::endl;
+
+ stream << "Expected pixel: " << expectedRed << "|" << expectedGreen << "|"
+ << expectedBlue << "|" << expectedAlpha << std::endl;
+
+ return stream.str();
+}
+
+std::string ComparatorResult::dumpComparison() const
+{
+ std::ostringstream stream;
+ stream << "Number of different pixels: " << mDifferentPixelCount;
+
+ for (const auto& comparison : mComparisons) {
+ if (std::get<2>(comparison) != std::get<3>(comparison))
+ stream << pixelDiff(std::get<0>(comparison),
+ std::get<1>(comparison), std::get<2>(comparison),
+ std::get<3>(comparison));
+ }
+ return stream.str();
+}
diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestPixelComparator.h b/services/surfaceflinger/tests/hwc2/Hwc2TestPixelComparator.h
new file mode 100644
index 0000000..55fa936
--- /dev/null
+++ b/services/surfaceflinger/tests/hwc2/Hwc2TestPixelComparator.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 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.
+ */
+#ifndef _HWC2_TEST_PIXEL_COMPARATOR_H
+#define _HWC2_TEST_PIXEL_COMPARATOR_H
+
+#include <ui/GraphicBuffer.h>
+#include <cstdint>
+#include <string>
+#include <utility>
+#include <vector>
+
+class ComparatorResult {
+public:
+ static ComparatorResult& get()
+ {
+ static ComparatorResult instance;
+ return instance;
+ }
+
+ void CompareBuffers(android::sp<android::GraphicBuffer>& resultBuffer,
+ android::sp<android::GraphicBuffer>& expectedBuffer);
+
+ std::string dumpComparison() const;
+
+ ComparatorResult(const ComparatorResult&) = delete;
+ ComparatorResult(ComparatorResult&&) = delete;
+ ComparatorResult& operator=(ComparatorResult const&) = delete;
+ ComparatorResult& operator=(ComparatorResult&&) = delete;
+
+ int32_t getDifferentPixelCount() const { return mDifferentPixelCount; }
+ int32_t getBlankPixelCount() const { return mBlankPixelCount; }
+
+private:
+ ComparatorResult() = default;
+ uint32_t getPixel(int32_t x, int32_t y, uint32_t stride, uint8_t* img) const;
+ std::string pixelDiff(uint32_t x, uint32_t y, uint32_t resultPixel,
+ uint32_t expectedPixel) const;
+
+ int32_t mDifferentPixelCount;
+ int32_t mBlankPixelCount;
+ /* std::tuple<X coordinate, Y coordinate, resultPixel, expectedPixel> */
+ std::vector<std::tuple<uint32_t, uint32_t, uint32_t, uint32_t>>
+ mComparisons;
+};
+
+#endif /* ifndef _HWC2_TEST_PIXEL_COMPARATOR_H */
diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestProperties.cpp b/services/surfaceflinger/tests/hwc2/Hwc2TestProperties.cpp
index b5522de..5b3bbeb 100644
--- a/services/surfaceflinger/tests/hwc2/Hwc2TestProperties.cpp
+++ b/services/surfaceflinger/tests/hwc2/Hwc2TestProperties.cpp
@@ -335,9 +335,9 @@
return dmp.str();
}
-void Hwc2TestDisplayDimension::setDependent(Hwc2TestBuffer* buffer)
+void Hwc2TestDisplayDimension::setDependent(Hwc2TestVirtualBuffer* buffer)
{
- mBuffer = buffer;
+ mBuffers.insert(buffer);
updateDependents();
}
@@ -345,8 +345,8 @@
{
const UnsignedArea& curr = get();
- if (mBuffer)
- mBuffer->updateBufferArea({static_cast<int32_t>(curr.width),
+ for (Hwc2TestVirtualBuffer* buffer : mBuffers)
+ buffer->updateBufferArea({static_cast<int32_t>(curr.width),
static_cast<int32_t>(curr.height)});
}
diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestProperties.h b/services/surfaceflinger/tests/hwc2/Hwc2TestProperties.h
index c2029ab..cb811e0 100644
--- a/services/surfaceflinger/tests/hwc2/Hwc2TestProperties.h
+++ b/services/surfaceflinger/tests/hwc2/Hwc2TestProperties.h
@@ -243,6 +243,7 @@
static const std::array<bool, 6> mCompositionSupport;
};
+class Hwc2TestVirtualBuffer;
class Hwc2TestDisplayDimension : public Hwc2TestProperty<UnsignedArea> {
public:
@@ -250,12 +251,12 @@
std::string dump() const;
- void setDependent(Hwc2TestBuffer* buffer);
+ void setDependent(Hwc2TestVirtualBuffer* buffer);
private:
void updateDependents();
- Hwc2TestBuffer* mBuffer;
+ std::set<Hwc2TestVirtualBuffer*> mBuffers;
static const std::vector<UnsignedArea> mDefaultDisplayDimensions;
static const std::vector<UnsignedArea> mBasicDisplayDimensions;
diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestVirtualDisplay.cpp b/services/surfaceflinger/tests/hwc2/Hwc2TestVirtualDisplay.cpp
index d0fbc0b..e6cceb8 100644
--- a/services/surfaceflinger/tests/hwc2/Hwc2TestVirtualDisplay.cpp
+++ b/services/surfaceflinger/tests/hwc2/Hwc2TestVirtualDisplay.cpp
@@ -15,14 +15,18 @@
*/
#include <sstream>
+#include <sys/stat.h>
#include "Hwc2TestVirtualDisplay.h"
+#define DIR_NAME "images"
+
Hwc2TestVirtualDisplay::Hwc2TestVirtualDisplay(
Hwc2TestCoverage coverage)
: mDisplayDimension(coverage)
{
- mDisplayDimension.setDependent(&mBuffer);
+ mDisplayDimension.setDependent(&mOutputBuffer);
+ mDisplayDimension.setDependent(&mExpectedBuffer);
}
std::string Hwc2TestVirtualDisplay::dump() const
@@ -36,11 +40,11 @@
return dmp.str();
}
-int Hwc2TestVirtualDisplay::getBuffer(buffer_handle_t* outHandle,
+int Hwc2TestVirtualDisplay::getOutputBuffer(buffer_handle_t* outHandle,
android::base::unique_fd* outAcquireFence)
{
int32_t acquireFence;
- int ret = mBuffer.get(outHandle, &acquireFence);
+ int ret = mOutputBuffer.getOutputBuffer(outHandle, &acquireFence);
outAcquireFence->reset(acquireFence);
return ret;
}
@@ -59,3 +63,36 @@
{
return mDisplayDimension.get();
}
+
+int Hwc2TestVirtualDisplay::verifyOutputBuffer(const Hwc2TestLayers* testLayers,
+ const std::vector<hwc2_layer_t>* allLayers,
+ const std::set<hwc2_layer_t>* clearLayers)
+{
+ int ret = mExpectedBuffer.generateExpectedBuffer(testLayers, allLayers,
+ clearLayers);
+ if (ret)
+ return ret;
+
+ ComparatorResult::get().CompareBuffers(mOutputBuffer.graphicBuffer(),
+ mExpectedBuffer.graphicBuffer());
+
+ return 0;
+}
+
+int Hwc2TestVirtualDisplay::writeBuffersToFile(std::string name)
+{
+ std::ostringstream expectedPath;
+ std::ostringstream resultPath;
+ int ret = mkdir(DIR_NAME, DEFFILEMODE);
+ if (ret && errno != EEXIST)
+ return ret;
+
+ expectedPath << DIR_NAME << "/expected-" << name << ".png";
+ resultPath << DIR_NAME << "/result-" << name << ".png";
+
+ if (!mExpectedBuffer.writeBufferToFile(expectedPath.str()) ||
+ !mOutputBuffer.writeBufferToFile(resultPath.str()))
+ return -1;
+
+ return 0;
+}
diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestVirtualDisplay.h b/services/surfaceflinger/tests/hwc2/Hwc2TestVirtualDisplay.h
index 09420ef..10c8ef0 100644
--- a/services/surfaceflinger/tests/hwc2/Hwc2TestVirtualDisplay.h
+++ b/services/surfaceflinger/tests/hwc2/Hwc2TestVirtualDisplay.h
@@ -18,6 +18,7 @@
#define _HWC2_TEST_VIRTUAL_DISPLAY_H
#include "Hwc2TestBuffer.h"
+#include "Hwc2TestPixelComparator.h"
#include "Hwc2TestProperties.h"
#define HWC2_INCLUDE_STRINGIFICATION
@@ -32,17 +33,22 @@
std::string dump() const;
- int getBuffer(buffer_handle_t* outHandle,
+ int getOutputBuffer(buffer_handle_t* outHandle,
android::base::unique_fd* outAcquireFence);
+ int verifyOutputBuffer(const Hwc2TestLayers* testLayers,
+ const std::vector<hwc2_layer_t>* allLayers,
+ const std::set<hwc2_layer_t>* clearLayers);
+
+ int writeBuffersToFile(std::string name);
void reset();
bool advance();
UnsignedArea getDisplayDimension() const;
private:
- Hwc2TestBuffer mBuffer;
-
+ Hwc2TestOutputBuffer mOutputBuffer;
+ Hwc2TestExpectedBuffer mExpectedBuffer;
Hwc2TestDisplayDimension mDisplayDimension;
};
diff --git a/services/thermalservice/Android.bp b/services/thermalservice/Android.bp
new file mode 100644
index 0000000..d754560
--- /dev/null
+++ b/services/thermalservice/Android.bp
@@ -0,0 +1,61 @@
+subdirs = [
+ "libthermalcallback"
+]
+
+cc_library {
+ name: "libthermalservice",
+
+ srcs: [
+ "aidl/android/os/IThermalEventListener.aidl",
+ "aidl/android/os/IThermalService.aidl",
+ "aidl/android/os/Temperature.cpp",
+ ],
+ aidl: {
+ include_dirs: ["frameworks/native/services/thermalservice/aidl"],
+ export_aidl_headers: true,
+ },
+ export_include_dirs: ["aidl"],
+
+ shared_libs: [
+ "libbinder",
+ "libutils",
+ ],
+
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wunused",
+ "-Wunreachable-code",
+ ],
+}
+
+cc_binary {
+ name: "thermalserviced",
+
+ srcs: [
+ "ThermalService.cpp",
+ "thermalserviced.cpp",
+ ],
+
+ include_dirs: ["frameworks/native"],
+
+ shared_libs: [
+ "libthermalservice",
+ "libbinder",
+ "libutils",
+ "libthermalcallback",
+ "android.hardware.thermal@1.1",
+ "libhidlbase",
+ "libhidltransport",
+ "liblog",
+ ],
+
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wunused",
+ "-Wunreachable-code",
+ ],
+
+ init_rc: ["thermalservice.rc"],
+}
diff --git a/services/thermalservice/ThermalService.cpp b/services/thermalservice/ThermalService.cpp
new file mode 100644
index 0000000..6e09a83
--- /dev/null
+++ b/services/thermalservice/ThermalService.cpp
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 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 "ThermalService.h"
+#include <android/os/IThermalService.h>
+#include <android/os/IThermalEventListener.h>
+#include <android/os/Temperature.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <utils/Errors.h>
+#include <utils/Mutex.h>
+#include <utils/String16.h>
+
+namespace android {
+namespace os {
+
+/**
+ * Notify registered listeners of a thermal throttling start/stop event.
+ * @param temperature the temperature at which the event was generated
+ */
+binder::Status ThermalService::notifyThrottling(
+ const bool isThrottling, const Temperature& temperature) {
+ Mutex::Autolock _l(mListenersLock);
+
+ mThrottled = isThrottling;
+ mThrottleTemperature = temperature;
+
+ for (size_t i = 0; i < mListeners.size(); i++) {
+ mListeners[i]->notifyThrottling(isThrottling, temperature);
+ }
+ return binder::Status::ok();
+}
+
+/**
+ * Query whether the system is currently thermal throttling.
+ * @return true if currently thermal throttling, else false
+ */
+binder::Status ThermalService::isThrottling(bool* _aidl_return) {
+ Mutex::Autolock _l(mListenersLock);
+ *_aidl_return = mThrottled;
+ return binder::Status::ok();
+}
+
+/**
+ * Register a new thermal event listener.
+ * @param listener the client's IThermalEventListener instance to which
+ * notifications are to be sent
+ */
+binder::Status ThermalService::registerThermalEventListener(
+ const sp<IThermalEventListener>& listener) {
+ {
+ if (listener == NULL)
+ return binder::Status::ok();
+ Mutex::Autolock _l(mListenersLock);
+ // check whether this is a duplicate
+ for (size_t i = 0; i < mListeners.size(); i++) {
+ if (IInterface::asBinder(mListeners[i]) ==
+ IInterface::asBinder(listener)) {
+ return binder::Status::ok();
+ }
+ }
+
+ mListeners.add(listener);
+ IInterface::asBinder(listener)->linkToDeath(this);
+ }
+
+ return binder::Status::ok();
+}
+
+/**
+ * Unregister a previously-registered thermal event listener.
+ * @param listener the client's IThermalEventListener instance to which
+ * notifications are to no longer be sent
+ */
+binder::Status ThermalService::unregisterThermalEventListener(
+ const sp<IThermalEventListener>& listener) {
+ if (listener == NULL)
+ return binder::Status::ok();
+ Mutex::Autolock _l(mListenersLock);
+ for (size_t i = 0; i < mListeners.size(); i++) {
+ if (IInterface::asBinder(mListeners[i]) ==
+ IInterface::asBinder(listener)) {
+ IInterface::asBinder(mListeners[i])->unlinkToDeath(this);
+ mListeners.removeAt(i);
+ break;
+ }
+ }
+
+ return binder::Status::ok();
+}
+
+void ThermalService::binderDied(const wp<IBinder>& who) {
+ Mutex::Autolock _l(mListenersLock);
+
+ for (size_t i = 0; i < mListeners.size(); i++) {
+ if (IInterface::asBinder(mListeners[i]) == who) {
+ mListeners.removeAt(i);
+ break;
+ }
+ }
+}
+
+/**
+ * Publish the supplied ThermalService to servicemanager.
+ */
+void ThermalService::publish(
+ const sp<ThermalService>& service) {
+ defaultServiceManager()->addService(String16("thermalservice"),
+ service);
+}
+
+} // namespace os
+} // namespace android
diff --git a/services/thermalservice/ThermalService.h b/services/thermalservice/ThermalService.h
new file mode 100644
index 0000000..17dfcbc
--- /dev/null
+++ b/services/thermalservice/ThermalService.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef ANDROID_THERMALSERVICE_THERMALSERVICE_H
+#define ANDROID_THERMALSERVICE_THERMALSERVICE_H
+
+#include <android/os/BnThermalService.h>
+#include <android/os/IThermalEventListener.h>
+#include <android/os/Temperature.h>
+#include <utils/Mutex.h>
+#include <utils/String16.h>
+#include <utils/Vector.h>
+
+namespace android {
+namespace os {
+
+class ThermalService : public BnThermalService,
+ public IBinder::DeathRecipient {
+public:
+ ThermalService() : mThrottled(false) {};
+ void publish(const sp<ThermalService>& service);
+ binder::Status notifyThrottling(
+ const bool isThrottling, const Temperature& temperature);
+
+private:
+ Mutex mListenersLock;
+ Vector<sp<IThermalEventListener> > mListeners;
+ bool mThrottled;
+ Temperature mThrottleTemperature;
+
+ binder::Status registerThermalEventListener(
+ const sp<IThermalEventListener>& listener);
+ binder::Status unregisterThermalEventListener(
+ const sp<IThermalEventListener>& listener);
+ binder::Status isThrottling(bool* _aidl_return);
+ void binderDied(const wp<IBinder>& who);
+};
+
+}; // namespace os
+}; // namespace android
+
+#endif // ANDROID_THERMALSERVICE_THERMALSERVICE_H
diff --git a/services/thermalservice/aidl/android/os/IThermalEventListener.aidl b/services/thermalservice/aidl/android/os/IThermalEventListener.aidl
new file mode 100644
index 0000000..050325e
--- /dev/null
+++ b/services/thermalservice/aidl/android/os/IThermalEventListener.aidl
@@ -0,0 +1,32 @@
+/**
+ * Copyright (c) 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.
+ */
+
+package android.os;
+
+import android.os.Temperature;
+
+/**
+ * Listener for thermal events.
+ * {@hide}
+ */
+oneway interface IThermalEventListener {
+ /**
+ * Called when a thermal throttling start/stop event is received.
+ * @param temperature the temperature at which the event was generated.
+ */
+ void notifyThrottling(
+ in boolean isThrottling, in Temperature temperature);
+}
diff --git a/services/thermalservice/aidl/android/os/IThermalService.aidl b/services/thermalservice/aidl/android/os/IThermalService.aidl
new file mode 100644
index 0000000..e699202
--- /dev/null
+++ b/services/thermalservice/aidl/android/os/IThermalService.aidl
@@ -0,0 +1,48 @@
+/**
+ * Copyright (c) 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.
+ */
+
+package android.os;
+
+import android.os.IThermalEventListener;
+import android.os.Temperature;
+
+/** {@hide} */
+interface IThermalService {
+ /**
+ * Register a listener for thermal events.
+ * @param listener the IThermalEventListener to be notified.
+ * {@hide}
+ */
+ void registerThermalEventListener(in IThermalEventListener listener);
+ /**
+ * Unregister a previously-registered listener for thermal events.
+ * @param listener the IThermalEventListener to no longer be notified.
+ * {@hide}
+ */
+ void unregisterThermalEventListener(in IThermalEventListener listener);
+ /**
+ * Send a thermal throttling start/stop notification to all listeners.
+ * @param temperature the temperature at which the event was generated.
+ * {@hide}
+ */
+ oneway void notifyThrottling(
+ in boolean isThrottling, in Temperature temperature);
+ /**
+ * Return whether system performance is currently thermal throttling.
+ * {@hide}
+ */
+ boolean isThrottling();
+}
diff --git a/services/thermalservice/aidl/android/os/Temperature.aidl b/services/thermalservice/aidl/android/os/Temperature.aidl
new file mode 100644
index 0000000..0293c39
--- /dev/null
+++ b/services/thermalservice/aidl/android/os/Temperature.aidl
@@ -0,0 +1,5 @@
+package android.os;
+
+/* Encodes a temperature used by ThermalService. */
+
+parcelable Temperature cpp_header "android/os/Temperature.h";
diff --git a/services/thermalservice/aidl/android/os/Temperature.cpp b/services/thermalservice/aidl/android/os/Temperature.cpp
new file mode 100644
index 0000000..df207b7
--- /dev/null
+++ b/services/thermalservice/aidl/android/os/Temperature.cpp
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 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 "android/os/Temperature.h"
+
+#include <math.h>
+#include <stdint.h>
+#include <binder/Parcel.h>
+#include <hardware/thermal.h>
+#include <sys/types.h>
+#include <utils/Errors.h>
+
+namespace android {
+namespace os {
+
+Temperature::Temperature() : value_(NAN), type_(DEVICE_TEMPERATURE_UNKNOWN) {}
+
+Temperature::Temperature(const float value, const int type) :
+ value_(value), type_(type) {}
+
+Temperature::~Temperature() {}
+
+/*
+ * Parcel read/write code must be kept in sync with
+ * frameworks/base/core/java/android/os/Temperature.java
+ */
+
+status_t Temperature::readFromParcel(const Parcel* p) {
+ value_ = p->readFloat();
+ type_ = p->readInt32();
+ return OK;
+}
+
+status_t Temperature::writeToParcel(Parcel* p) const {
+ p->writeFloat(value_);
+ p->writeInt32(type_);
+ return OK;
+}
+
+} // namespace os
+} // namespace android
diff --git a/services/thermalservice/aidl/android/os/Temperature.h b/services/thermalservice/aidl/android/os/Temperature.h
new file mode 100644
index 0000000..bbc5607
--- /dev/null
+++ b/services/thermalservice/aidl/android/os/Temperature.h
@@ -0,0 +1,33 @@
+#ifndef ANDROID_THERMALSERVICE_AIDL_ANDROID_OS_TEMPERATURE_H
+#define ANDROID_THERMALSERVICE_AIDL_ANDROID_OS_TEMPERATURE_H
+
+#include <binder/Parcelable.h>
+
+namespace android {
+namespace os {
+
+class Temperature : public Parcelable {
+ public:
+
+ Temperature();
+ Temperature(const float value, const int type);
+ ~Temperature() override;
+
+ float getValue() const {return value_;};
+ float getType() const {return type_;};
+
+ status_t writeToParcel(Parcel* parcel) const override;
+ status_t readFromParcel(const Parcel* parcel) override;
+
+ private:
+ // The value of the temperature as a float, or NAN if unknown.
+ float value_;
+ // The type of the temperature, an enum temperature_type from
+ // hardware/thermal.h
+ int type_;
+};
+
+} // namespace os
+} // namespace android
+
+#endif // ANDROID_THERMALSERVICE_AIDL_ANDROID_OS_TEMPERATURE_H
diff --git a/services/thermalservice/libthermalcallback/Android.bp b/services/thermalservice/libthermalcallback/Android.bp
new file mode 100644
index 0000000..e98506e
--- /dev/null
+++ b/services/thermalservice/libthermalcallback/Android.bp
@@ -0,0 +1,19 @@
+cc_library_shared {
+ name: "libthermalcallback",
+ srcs: [
+ "ThermalCallback.cpp",
+ ],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+ include_dirs: ["frameworks/native"],
+ shared_libs: [
+ "android.hardware.thermal@1.1",
+ "libhidlbase",
+ "libhidltransport",
+ "liblog",
+ "libthermalservice",
+ "libutils",
+ ],
+}
diff --git a/services/thermalservice/libthermalcallback/ThermalCallback.cpp b/services/thermalservice/libthermalcallback/ThermalCallback.cpp
new file mode 100644
index 0000000..5e094fa
--- /dev/null
+++ b/services/thermalservice/libthermalcallback/ThermalCallback.cpp
@@ -0,0 +1,69 @@
+#define LOG_TAG "android.hardware.thermal.thermalcallback@1.1-impl"
+#include <log/log.h>
+
+#include "ThermalCallback.h"
+#include "services/thermalservice/ThermalService.h"
+#include <math.h>
+#include <android/os/Temperature.h>
+#include <hardware/thermal.h>
+
+namespace android {
+namespace hardware {
+namespace thermal {
+namespace V1_1 {
+namespace implementation {
+
+using ::android::os::ThermalService;
+using ::android::hardware::thermal::V1_0::TemperatureType;
+
+// Register a binder ThermalService object for sending events
+void ThermalCallback::registerThermalService(sp<ThermalService> thermalService)
+{
+ mThermalService = thermalService;
+}
+
+// Methods from IThermalCallback::V1_1 follow.
+Return<void> ThermalCallback::notifyThrottling(
+ bool isThrottling,
+ const android::hardware::thermal::V1_0::Temperature& temperature) {
+
+ // Convert HIDL IThermal Temperature to binder IThermalService Temperature.
+ if (mThermalService != nullptr) {
+ float value = NAN;
+ int type = DEVICE_TEMPERATURE_UNKNOWN;
+
+ switch(temperature.type) {
+ case TemperatureType::CPU:
+ type = DEVICE_TEMPERATURE_CPU;
+ break;
+ case TemperatureType::GPU:
+ type = DEVICE_TEMPERATURE_GPU;
+ break;
+ case TemperatureType::BATTERY:
+ type = DEVICE_TEMPERATURE_BATTERY;
+ break;
+ case TemperatureType::SKIN:
+ type = DEVICE_TEMPERATURE_SKIN;
+ break;
+ case TemperatureType::UNKNOWN:
+ default:
+ type = DEVICE_TEMPERATURE_UNKNOWN;
+ break;
+ }
+
+ value = temperature.currentValue == UNKNOWN_TEMPERATURE ? NAN :
+ temperature.currentValue;
+
+ android::os::Temperature thermal_svc_temp(value, type);
+ mThermalService->notifyThrottling(isThrottling, thermal_svc_temp);
+ } else {
+ ALOGE("IThermalService binder service not created, drop throttling event");
+ }
+ return Void();
+}
+
+} // namespace implementation
+} // namespace V1_1
+} // namespace thermal
+} // namespace hardware
+} // namespace android
diff --git a/services/thermalservice/libthermalcallback/ThermalCallback.h b/services/thermalservice/libthermalcallback/ThermalCallback.h
new file mode 100644
index 0000000..3d72c68
--- /dev/null
+++ b/services/thermalservice/libthermalcallback/ThermalCallback.h
@@ -0,0 +1,43 @@
+#ifndef ANDROID_HARDWARE_THERMAL_V1_1_THERMALCALLBACK_H
+#define ANDROID_HARDWARE_THERMAL_V1_1_THERMALCALLBACK_H
+
+#include <android/hardware/thermal/1.1/IThermalCallback.h>
+#include <android/hardware/thermal/1.0/types.h>
+#include <android/os/Temperature.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+#include "services/thermalservice/ThermalService.h"
+
+namespace android {
+namespace hardware {
+namespace thermal {
+namespace V1_1 {
+namespace implementation {
+
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::os::ThermalService;
+
+class ThermalCallback : public IThermalCallback {
+ public:
+ // Register a binder ThermalService object for sending events
+ void registerThermalService(sp<ThermalService> thermalService);
+
+ // Methods from IThermalCallback::V1_1 follow.
+ Return<void> notifyThrottling(
+ bool isThrottling,
+ const android::hardware::thermal::V1_0::Temperature& temperature)
+ override;
+
+ private:
+ // Our registered binder ThermalService object to use for sending events
+ sp<android::os::ThermalService> mThermalService;
+};
+
+} // namespace implementation
+} // namespace V1_1
+} // namespace thermal
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_THERMAL_V1_1_THERMALCALLBACK_H
diff --git a/services/thermalservice/thermalservice.rc b/services/thermalservice/thermalservice.rc
new file mode 100644
index 0000000..94c2c78
--- /dev/null
+++ b/services/thermalservice/thermalservice.rc
@@ -0,0 +1,4 @@
+service thermalservice /system/bin/thermalserviced
+ class core
+ user system
+ group system
diff --git a/services/thermalservice/thermalserviced.cpp b/services/thermalservice/thermalserviced.cpp
new file mode 100644
index 0000000..8e27266
--- /dev/null
+++ b/services/thermalservice/thermalserviced.cpp
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#define LOG_TAG "thermalserviced"
+#include <log/log.h>
+
+#include "thermalserviced.h"
+#include "ThermalService.h"
+#include "libthermalcallback/ThermalCallback.h"
+
+#include <android/hardware/thermal/1.1/IThermal.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <hidl/HidlTransportSupport.h>
+
+using namespace android;
+using ::android::hardware::thermal::V1_1::IThermal;
+using ::android::hardware::thermal::V1_0::Temperature;
+using ::android::hardware::thermal::V1_1::IThermalCallback;
+using ::android::hardware::thermal::V1_1::implementation::ThermalCallback;
+using ::android::hardware::configureRpcThreadpool;
+using ::android::hardware::hidl_death_recipient;
+using ::android::hidl::base::V1_0::IBase;
+using ::android::os::ThermalService;
+
+template<typename T>
+using Return = hardware::Return<T>;
+
+namespace {
+
+// Our thermalserviced main object
+ThermalServiceDaemon* gThermalServiceDaemon;
+
+// Thermal HAL client
+sp<IThermal> gThermalHal = nullptr;
+
+// Binder death notifier informing of Thermal HAL death.
+struct ThermalServiceDeathRecipient : hidl_death_recipient {
+ virtual void serviceDied(
+ uint64_t cookie __unused, const wp<IBase>& who __unused) {
+ gThermalHal = nullptr;
+ ALOGE("IThermal HAL died");
+ gThermalServiceDaemon->getThermalHal();
+ }
+};
+
+sp<ThermalServiceDeathRecipient> gThermalHalDied = nullptr;
+
+} // anonymous namespace
+
+void ThermalServiceDaemon::thermalServiceStartup() {
+ // Binder IThermalService startup
+ mThermalService = new android::os::ThermalService;
+ mThermalService->publish(mThermalService);
+ // Register IThermalService object with IThermalCallback
+ if (mThermalCallback != nullptr)
+ mThermalCallback->registerThermalService(mThermalService);
+ IPCThreadState::self()->joinThreadPool();
+}
+
+// Lookup Thermal HAL, register death notifier, register our
+// ThermalCallback with the Thermal HAL.
+void ThermalServiceDaemon::getThermalHal() {
+ gThermalHal = IThermal::getService();
+ if (gThermalHal == nullptr) {
+ ALOGW("Unable to get Thermal HAL V1.1, vendor thermal event notification not available");
+ return;
+ }
+
+ // Binder death notifier for Thermal HAL
+ if (gThermalHalDied == nullptr)
+ gThermalHalDied = new ThermalServiceDeathRecipient();
+
+ if (gThermalHalDied != nullptr)
+ gThermalHal->linkToDeath(gThermalHalDied, 0x451F /* cookie */);
+
+ if (mThermalCallback != nullptr) {
+ Return<void> ret = gThermalHal->registerThermalCallback(
+ mThermalCallback);
+ if (!ret.isOk())
+ ALOGE("registerThermalCallback failed, status: %s",
+ ret.description().c_str());
+ }
+}
+
+void ThermalServiceDaemon::thermalCallbackStartup() {
+ // HIDL IThermalCallback startup
+ // Need at least 2 threads in thread pool since we wait for dead HAL
+ // to come back on the binder death notification thread and we need
+ // another thread for the incoming service now available call.
+ configureRpcThreadpool(2, false /* callerWillJoin */);
+ mThermalCallback = new ThermalCallback();
+ // Lookup Thermal HAL and register our ThermalCallback.
+ getThermalHal();
+}
+
+int main(int /*argc*/, char** /*argv*/) {
+ gThermalServiceDaemon = new ThermalServiceDaemon();
+ gThermalServiceDaemon->thermalCallbackStartup();
+ gThermalServiceDaemon->thermalServiceStartup();
+ /* NOTREACHED */
+}
diff --git a/services/thermalservice/thermalserviced.h b/services/thermalservice/thermalserviced.h
new file mode 100644
index 0000000..309e2fe
--- /dev/null
+++ b/services/thermalservice/thermalserviced.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef ANDROID_THERMALSERVICE_THERMALSERVICED_H
+#define ANDROID_THERMALSERVICE_THERMALSERVICED_H
+
+#include "ThermalService.h"
+#include "libthermalcallback/ThermalCallback.h"
+
+using namespace android;
+using ::android::hardware::thermal::V1_0::Temperature;
+using ::android::hardware::thermal::V1_1::implementation::ThermalCallback;
+using ::android::os::ThermalService;
+
+class ThermalServiceDaemon {
+ public:
+ void thermalServiceStartup();
+ void thermalCallbackStartup();
+ void getThermalHal();
+ ThermalServiceDaemon() {};
+
+ private:
+ sp<ThermalService> mThermalService;
+ sp<ThermalCallback> mThermalCallback;
+};
+
+#endif // ANDROID_THERMALSERVICE_THERMALSERVICED_H
diff --git a/services/utils/Android.bp b/services/utils/Android.bp
new file mode 100644
index 0000000..6132956
--- /dev/null
+++ b/services/utils/Android.bp
@@ -0,0 +1,34 @@
+// Copyright (C) 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.
+
+//
+// Static library used in testing and executables
+//
+cc_library_static {
+ name: "libserviceutils",
+
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+
+ srcs: [
+ "PriorityDumper.cpp",
+ ],
+
+ clang: true,
+ export_include_dirs: ["include"],
+}
+
+subdirs = ["tests"]
diff --git a/services/utils/PriorityDumper.cpp b/services/utils/PriorityDumper.cpp
new file mode 100644
index 0000000..967dee5
--- /dev/null
+++ b/services/utils/PriorityDumper.cpp
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 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 "include/serviceutils/PriorityDumper.h"
+
+namespace android {
+
+const char16_t PriorityDumper::PROTO_ARG[] = u"--proto";
+const char16_t PriorityDumper::PRIORITY_ARG[] = u"--dump-priority";
+const char16_t PriorityDumper::PRIORITY_ARG_CRITICAL[] = u"CRITICAL";
+const char16_t PriorityDumper::PRIORITY_ARG_HIGH[] = u"HIGH";
+const char16_t PriorityDumper::PRIORITY_ARG_NORMAL[] = u"NORMAL";
+
+enum class PriorityType { INVALID, CRITICAL, HIGH, NORMAL };
+
+static PriorityType getPriorityType(const String16& arg) {
+ if (arg == PriorityDumper::PRIORITY_ARG_CRITICAL) {
+ return PriorityType::CRITICAL;
+ } else if (arg == PriorityDumper::PRIORITY_ARG_HIGH) {
+ return PriorityType::HIGH;
+ } else if (arg == PriorityDumper::PRIORITY_ARG_NORMAL) {
+ return PriorityType::NORMAL;
+ }
+ return PriorityType::INVALID;
+}
+
+status_t PriorityDumper::dumpAll(int fd, const Vector<String16>& args, bool asProto) {
+ status_t status;
+ status = dumpCritical(fd, args, asProto);
+ if (status != OK) return status;
+ status = dumpHigh(fd, args, asProto);
+ if (status != OK) return status;
+ status = dumpNormal(fd, args, asProto);
+ if (status != OK) return status;
+ return status;
+}
+
+status_t PriorityDumper::priorityDump(int fd, const Vector<String16>& args) {
+ status_t status;
+ bool asProto = false;
+ PriorityType priority = PriorityType::INVALID;
+
+ Vector<String16> strippedArgs;
+ for (uint32_t argIndex = 0; argIndex < args.size(); argIndex++) {
+ if (args[argIndex] == PROTO_ARG) {
+ asProto = true;
+ } else if (args[argIndex] == PRIORITY_ARG) {
+ if (argIndex + 1 < args.size()) {
+ argIndex++;
+ priority = getPriorityType(args[argIndex]);
+ }
+ } else {
+ strippedArgs.add(args[argIndex]);
+ }
+ }
+
+ switch (priority) {
+ case PriorityType::CRITICAL:
+ status = dumpCritical(fd, strippedArgs, asProto);
+ break;
+ case PriorityType::HIGH:
+ status = dumpHigh(fd, strippedArgs, asProto);
+ break;
+ case PriorityType::NORMAL:
+ status = dumpNormal(fd, strippedArgs, asProto);
+ break;
+ default:
+ status = dumpAll(fd, strippedArgs, asProto);
+ break;
+ }
+ return status;
+}
+} // namespace android
diff --git a/services/utils/include/serviceutils/PriorityDumper.h b/services/utils/include/serviceutils/PriorityDumper.h
new file mode 100644
index 0000000..d01a102
--- /dev/null
+++ b/services/utils/include/serviceutils/PriorityDumper.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef ANDROID_UTILS_PRIORITYDUMPER_H
+#define ANDROID_UTILS_PRIORITYDUMPER_H
+
+#include <utils/Errors.h>
+#include <utils/String16.h>
+#include <utils/Vector.h>
+
+namespace android {
+
+// Helper class to parse common arguments responsible for splitting dumps into
+// various priority buckets and changing the output format of the dump.
+class PriorityDumper {
+public:
+ static const char16_t PRIORITY_ARG[];
+ static const char16_t PRIORITY_ARG_CRITICAL[];
+ static const char16_t PRIORITY_ARG_HIGH[];
+ static const char16_t PRIORITY_ARG_NORMAL[];
+ static const char16_t PROTO_ARG[];
+
+ // Parses the argument list searching for --dump_priority with a priority type
+ // (HIGH, CRITICAL or NORMAL) and --proto. Matching arguments are stripped.
+ // If a valid priority type is found, the associated PriorityDumper
+ // method is called otherwise all supported sections are dumped.
+ // If --proto is found, the dumpAsProto flag is set to dump sections in proto
+ // format.
+ status_t priorityDump(int fd, const Vector<String16>& args);
+
+ // Dumps CRITICAL priority sections.
+ virtual status_t dumpCritical(int /*fd*/, const Vector<String16>& /*args*/, bool /*asProto*/) {
+ return OK;
+ }
+
+ // Dumps HIGH priority sections.
+ virtual status_t dumpHigh(int /*fd*/, const Vector<String16>& /*args*/, bool /*asProto*/) {
+ return OK;
+ }
+
+ // Dumps normal priority sections.
+ virtual status_t dumpNormal(int /*fd*/, const Vector<String16>& /*args*/, bool /*asProto*/) {
+ return OK;
+ }
+
+ // Dumps all sections.
+ // This method is called when priorityDump is called without priority
+ // arguments. By default, it calls all three dump methods.
+ virtual status_t dumpAll(int fd, const Vector<String16>& args, bool asProto);
+ virtual ~PriorityDumper() = default;
+};
+
+} // namespace android
+
+#endif // ANDROID_UTILS_PRIORITYDUMPER_H
diff --git a/services/utils/tests/Android.bp b/services/utils/tests/Android.bp
new file mode 100644
index 0000000..15829fa
--- /dev/null
+++ b/services/utils/tests/Android.bp
@@ -0,0 +1,29 @@
+// Copyright (C) 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.
+
+// Build unit tests.
+
+cc_test {
+ name: "prioritydumper_test",
+ test_suites: ["device-tests"],
+ srcs: [ "PriorityDumper_test.cpp"],
+ shared_libs: [
+ "libutils",
+ ],
+ static_libs = [
+ "libgmock",
+ "libserviceutils"
+ ],
+ clang: true,
+}
\ No newline at end of file
diff --git a/services/utils/tests/AndroidTest.xml b/services/utils/tests/AndroidTest.xml
new file mode 100644
index 0000000..83c890d
--- /dev/null
+++ b/services/utils/tests/AndroidTest.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 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.
+-->
+<configuration description="Config for prioritydumper_test">
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <option name="cleanup" value="true" />
+ <option name="push" value="prioritydumper_test->/data/local/tmp/prioritydumper_test" />
+ </target_preparer>
+ <option name="test-suite-tag" value="apct" />
+ <test class="com.android.tradefed.testtype.GTest" >
+ <option name="native-test-device-path" value="/data/local/tmp" />
+ <option name="module-name" value="prioritydumper_test" />
+ </test>
+</configuration>
\ No newline at end of file
diff --git a/services/utils/tests/PriorityDumper_test.cpp b/services/utils/tests/PriorityDumper_test.cpp
new file mode 100644
index 0000000..90cc6de
--- /dev/null
+++ b/services/utils/tests/PriorityDumper_test.cpp
@@ -0,0 +1,219 @@
+/*
+ * Copyright (C) 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 "serviceutils/PriorityDumper.h"
+
+#include <vector>
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <utils/String16.h>
+#include <utils/Vector.h>
+
+using namespace android;
+
+using ::testing::ElementsAreArray;
+using ::testing::Mock;
+using ::testing::Test;
+
+class PriorityDumperMock : public PriorityDumper {
+public:
+ MOCK_METHOD3(dumpCritical, status_t(int, const Vector<String16>&, bool));
+ MOCK_METHOD3(dumpHigh, status_t(int, const Vector<String16>&, bool));
+ MOCK_METHOD3(dumpNormal, status_t(int, const Vector<String16>&, bool));
+ MOCK_METHOD3(dumpAll, status_t(int, const Vector<String16>&, bool));
+};
+
+class DumpAllMock : public PriorityDumper {
+public:
+ MOCK_METHOD3(dumpCritical, status_t(int, const Vector<String16>&, bool));
+ MOCK_METHOD3(dumpHigh, status_t(int, const Vector<String16>&, bool));
+ MOCK_METHOD3(dumpNormal, status_t(int, const Vector<String16>&, bool));
+};
+
+class PriorityDumperTest : public Test {
+public:
+ PriorityDumperTest() : dumper_(), dumpAlldumper_(), fd(1) {}
+ PriorityDumperMock dumper_;
+ DumpAllMock dumpAlldumper_;
+ int fd;
+};
+
+static void addAll(Vector<String16>& av, const std::vector<std::string>& v) {
+ for (auto element : v) {
+ av.add(String16(element.c_str()));
+ }
+}
+
+TEST_F(PriorityDumperTest, noArgsPassed) {
+ Vector<String16> args;
+ EXPECT_CALL(dumper_, dumpAll(fd, ElementsAreArray(args), /*asProto=*/false));
+ dumper_.priorityDump(fd, args);
+}
+
+TEST_F(PriorityDumperTest, noPriorityArgsPassed) {
+ Vector<String16> args;
+ addAll(args, {"bunch", "of", "args"});
+ EXPECT_CALL(dumper_, dumpAll(fd, ElementsAreArray(args), /*asProto=*/false));
+ dumper_.priorityDump(fd, args);
+}
+
+TEST_F(PriorityDumperTest, priorityArgsOnly) {
+ Vector<String16> args;
+ addAll(args, {"--dump-priority", "CRITICAL"});
+ Vector<String16> strippedArgs;
+ EXPECT_CALL(dumper_, dumpCritical(fd, ElementsAreArray(strippedArgs), /*asProto=*/false));
+ dumper_.priorityDump(fd, args);
+}
+
+TEST_F(PriorityDumperTest, dumpCritical) {
+ Vector<String16> args;
+ addAll(args, {"--dump-priority", "CRITICAL", "args", "left", "behind"});
+ Vector<String16> strippedArgs;
+ addAll(strippedArgs, {"args", "left", "behind"});
+
+ EXPECT_CALL(dumper_, dumpCritical(fd, ElementsAreArray(strippedArgs), /*asProto=*/false));
+ dumper_.priorityDump(fd, args);
+}
+
+TEST_F(PriorityDumperTest, dumpCriticalInMiddle) {
+ Vector<String16> args;
+ addAll(args, {"args", "left", "--dump-priority", "CRITICAL", "behind"});
+ Vector<String16> strippedArgs;
+ addAll(strippedArgs, {"args", "left", "behind"});
+
+ EXPECT_CALL(dumper_, dumpCritical(fd, ElementsAreArray(strippedArgs), /*asProto=*/false));
+ dumper_.priorityDump(fd, args);
+}
+
+TEST_F(PriorityDumperTest, dumpHigh) {
+ Vector<String16> args;
+ addAll(args, {"--dump-priority", "HIGH", "args", "left", "behind"});
+ Vector<String16> strippedArgs;
+ addAll(strippedArgs, {"args", "left", "behind"});
+
+ EXPECT_CALL(dumper_, dumpHigh(fd, ElementsAreArray(strippedArgs), /*asProto=*/false));
+ dumper_.priorityDump(fd, args);
+}
+
+TEST_F(PriorityDumperTest, dumpHighInEnd) {
+ Vector<String16> args;
+ addAll(args, {"args", "left", "behind", "--dump-priority", "HIGH"});
+ Vector<String16> strippedArgs;
+ addAll(strippedArgs, {"args", "left", "behind"});
+
+ EXPECT_CALL(dumper_, dumpHigh(fd, ElementsAreArray(strippedArgs), /*asProto=*/false));
+ dumper_.priorityDump(fd, args);
+}
+
+TEST_F(PriorityDumperTest, dumpNormal) {
+ Vector<String16> args;
+ addAll(args, {"--dump-priority", "NORMAL", "args", "left", "behind"});
+ Vector<String16> strippedArgs;
+ addAll(strippedArgs, {"args", "left", "behind"});
+
+ EXPECT_CALL(dumper_, dumpNormal(fd, ElementsAreArray(strippedArgs), /*asProto=*/false));
+ dumper_.priorityDump(fd, args);
+}
+
+TEST_F(PriorityDumperTest, dumpAll) {
+ Vector<String16> args;
+ addAll(args, {"args", "left", "behind"});
+
+ EXPECT_CALL(dumpAlldumper_, dumpCritical(fd, ElementsAreArray(args), /*asProto=*/false));
+ EXPECT_CALL(dumpAlldumper_, dumpHigh(fd, ElementsAreArray(args), /*asProto=*/false));
+ EXPECT_CALL(dumpAlldumper_, dumpNormal(fd, ElementsAreArray(args), /*asProto=*/false));
+
+ dumpAlldumper_.priorityDump(fd, args);
+}
+
+TEST_F(PriorityDumperTest, priorityArgWithPriorityMissing) {
+ Vector<String16> args;
+ addAll(args, {"--dump-priority"});
+ Vector<String16> strippedArgs;
+ EXPECT_CALL(dumper_, dumpAll(fd, ElementsAreArray(strippedArgs), /*asProto=*/false));
+
+ dumper_.priorityDump(fd, args);
+}
+
+TEST_F(PriorityDumperTest, priorityArgWithInvalidPriority) {
+ Vector<String16> args;
+ addAll(args, {"--dump-priority", "REALLY_HIGH"});
+ Vector<String16> strippedArgs;
+ EXPECT_CALL(dumper_, dumpAll(fd, ElementsAreArray(strippedArgs), /*asProto=*/false));
+
+ dumper_.priorityDump(fd, args);
+}
+
+TEST_F(PriorityDumperTest, protoArg) {
+ Vector<String16> args;
+ addAll(args, {"--proto"});
+ Vector<String16> strippedArgs;
+ EXPECT_CALL(dumper_, dumpAll(fd, ElementsAreArray(strippedArgs), /*asProto=*/true));
+
+ dumper_.priorityDump(fd, args);
+}
+
+TEST_F(PriorityDumperTest, protoArgWithPriorityArgs) {
+ Vector<String16> args;
+ addAll(args, {"--proto", "args", "--dump-priority", "NORMAL", "left", "behind"});
+ Vector<String16> strippedArgs;
+ addAll(strippedArgs, {"args", "left", "behind"});
+ EXPECT_CALL(dumper_, dumpNormal(fd, ElementsAreArray(strippedArgs), /*asProto=*/true));
+
+ dumper_.priorityDump(fd, args);
+}
+
+TEST_F(PriorityDumperTest, protoArgWithPriorityArgsInReverseOrder) {
+ Vector<String16> args;
+ addAll(args, {"--dump-priority", "NORMAL", "--proto", "args", "left", "behind"});
+ Vector<String16> strippedArgs;
+ addAll(strippedArgs, {"args", "left", "behind"});
+ EXPECT_CALL(dumper_, dumpNormal(fd, ElementsAreArray(strippedArgs), /*asProto=*/true));
+
+ dumper_.priorityDump(fd, args);
+}
+
+TEST_F(PriorityDumperTest, protoArgInMiddle) {
+ Vector<String16> args;
+ addAll(args, {"--unknown", "args", "--proto", "args", "left", "behind"});
+ Vector<String16> strippedArgs;
+ addAll(strippedArgs, {"--unknown", "args", "args", "left", "behind"});
+ EXPECT_CALL(dumper_, dumpAll(fd, ElementsAreArray(strippedArgs), /*asProto=*/true));
+
+ dumper_.priorityDump(fd, args);
+}
+
+TEST_F(PriorityDumperTest, protoArgAtEnd) {
+ Vector<String16> args;
+ addAll(args, {"--unknown", "args", "args", "left", "behind", "--proto"});
+ Vector<String16> strippedArgs;
+ addAll(strippedArgs, {"--unknown", "args", "args", "left", "behind"});
+ EXPECT_CALL(dumper_, dumpAll(fd, ElementsAreArray(strippedArgs), /*asProto=*/true));
+
+ dumper_.priorityDump(fd, args);
+}
+
+TEST_F(PriorityDumperTest, protoArgWithInvalidPriorityType) {
+ Vector<String16> args;
+ addAll(args, {"--dump-priority", "NOT_SO_HIGH", "--proto", "args", "left", "behind"});
+ Vector<String16> strippedArgs;
+ addAll(strippedArgs, {"args", "left", "behind"});
+ EXPECT_CALL(dumper_, dumpAll(fd, ElementsAreArray(strippedArgs), /*asProto=*/true));
+
+ dumper_.priorityDump(fd, args);
+}
\ No newline at end of file
diff --git a/services/vr/bufferhubd/Android.mk b/services/vr/bufferhubd/Android.mk
index 97f0332..28cf53d 100644
--- a/services/vr/bufferhubd/Android.mk
+++ b/services/vr/bufferhubd/Android.mk
@@ -22,6 +22,9 @@
consumer_queue_channel.cpp \
producer_queue_channel.cpp \
+headerLibraries := \
+ libdvr_headers
+
staticLibraries := \
libperformance \
libpdx_default_transport \
@@ -41,6 +44,7 @@
LOCAL_CFLAGS := -DLOG_TAG=\"bufferhubd\"
LOCAL_CFLAGS += -DTRACE=0
LOCAL_CFLAGS += -DATRACE_TAG=ATRACE_TAG_GRAPHICS
+LOCAL_HEADER_LIBRARIES := $(headerLibraries)
LOCAL_STATIC_LIBRARIES := $(staticLibraries)
LOCAL_SHARED_LIBRARIES := $(sharedLibraries)
LOCAL_MODULE := bufferhubd
diff --git a/services/vr/bufferhubd/buffer_hub.cpp b/services/vr/bufferhubd/buffer_hub.cpp
index 26843c9..cdb1f91 100644
--- a/services/vr/bufferhubd/buffer_hub.cpp
+++ b/services/vr/bufferhubd/buffer_hub.cpp
@@ -20,8 +20,8 @@
using android::pdx::ErrorStatus;
using android::pdx::Message;
using android::pdx::Status;
-using android::pdx::rpc::DispatchRemoteMethod;
using android::pdx::default_transport::Endpoint;
+using android::pdx::rpc::DispatchRemoteMethod;
namespace android {
namespace dvr {
@@ -53,7 +53,15 @@
stream << " ";
stream << std::setw(6) << "Format";
stream << " ";
- stream << std::setw(11) << "Usage";
+ stream << std::setw(10) << "Usage";
+ stream << " ";
+ stream << std::setw(9) << "Pending";
+ stream << " ";
+ stream << std::setw(18) << "State";
+ stream << " ";
+ stream << std::setw(18) << "Signaled";
+ stream << " ";
+ stream << std::setw(10) << "Index";
stream << " ";
stream << "Name";
stream << std::endl;
@@ -83,46 +91,15 @@
stream << std::setw(8) << info.usage;
stream << std::dec << std::setfill(' ');
stream << " ";
- stream << info.name;
- stream << std::endl;
- }
- }
-
- stream << "Active Consumer Buffers:\n";
- stream << std::right;
- stream << std::setw(6) << "Id";
- stream << " ";
- stream << std::setw(14) << "Geometry";
- stream << " ";
- stream << "Name";
- stream << std::endl;
-
- for (const auto& channel : channels) {
- if (channel->channel_type() == BufferHubChannel::kConsumerType) {
- BufferHubChannel::BufferInfo info = channel->GetBufferInfo();
-
- stream << std::right;
- stream << std::setw(6) << info.id;
+ stream << std::setw(9) << info.pending_count;
stream << " ";
-
- if (info.consumer_count == 0) {
- // consumer_count is tracked by producer. When it's zero, producer must
- // have already hung up and the consumer is orphaned.
- stream << std::setw(14) << "Orphaned.";
- stream << (" channel_id=" + std::to_string(channel->channel_id()));
- stream << std::endl;
- continue;
- }
-
- if (info.format == HAL_PIXEL_FORMAT_BLOB) {
- std::string size = std::to_string(info.width) + " B";
- stream << std::setw(14) << size;
- } else {
- std::string dimensions = std::to_string(info.width) + "x" +
- std::to_string(info.height) + "x" +
- std::to_string(info.layer_count);
- stream << std::setw(14) << dimensions;
- }
+ stream << "0x" << std::hex << std::setfill('0');
+ stream << std::setw(16) << info.state;
+ stream << " ";
+ stream << "0x" << std::setw(16) << info.signaled_mask;
+ stream << std::dec << std::setfill(' ');
+ stream << " ";
+ stream << std::setw(8) << info.index;
stream << " ";
stream << info.name;
stream << std::endl;
@@ -184,6 +161,32 @@
}
}
+ stream << std::endl;
+ stream << "Orphaned Consumer Buffers:\n";
+ stream << std::right;
+ stream << std::setw(6) << "Id";
+ stream << " ";
+ stream << std::setw(14) << "Geometry";
+ stream << " ";
+ stream << "Name";
+ stream << std::endl;
+
+ for (const auto& channel : channels) {
+ BufferHubChannel::BufferInfo info = channel->GetBufferInfo();
+ // consumer_count is tracked by producer. When it's zero, producer must have
+ // already hung up and the consumer is orphaned.
+ if (channel->channel_type() == BufferHubChannel::kConsumerType &&
+ info.consumer_count == 0) {
+ stream << std::right;
+ stream << std::setw(6) << info.id;
+ stream << " ";
+
+ stream << std::setw(14) << "Orphaned.";
+ stream << (" channel_id=" + std::to_string(channel->channel_id()));
+ stream << std::endl;
+ }
+ }
+
return stream.str();
}
@@ -444,6 +447,7 @@
"BufferHubChannel::SignalAvailable: channel_id=%d buffer_id=%d",
channel_id(), buffer_id());
if (!IsDetached()) {
+ signaled_ = true;
const auto status = service_->ModifyChannelEvents(channel_id_, 0, POLLIN);
ALOGE_IF(!status,
"BufferHubChannel::SignalAvailable: failed to signal availability "
@@ -460,6 +464,7 @@
"BufferHubChannel::ClearAvailable: channel_id=%d buffer_id=%d",
channel_id(), buffer_id());
if (!IsDetached()) {
+ signaled_ = false;
const auto status = service_->ModifyChannelEvents(channel_id_, POLLIN, 0);
ALOGE_IF(!status,
"BufferHubChannel::ClearAvailable: failed to clear availability "
diff --git a/services/vr/bufferhubd/buffer_hub.h b/services/vr/bufferhubd/buffer_hub.h
index b0df11f..270ac95 100644
--- a/services/vr/bufferhubd/buffer_hub.h
+++ b/services/vr/bufferhubd/buffer_hub.h
@@ -53,6 +53,10 @@
uint32_t layer_count = 0;
uint32_t format = 0;
uint64_t usage = 0;
+ size_t pending_count = 0;
+ uint64_t state = 0;
+ uint64_t signaled_mask = 0;
+ uint64_t index = 0;
std::string name;
// Data filed for producer queue.
@@ -60,7 +64,9 @@
UsagePolicy usage_policy{0, 0, 0, 0};
BufferInfo(int id, size_t consumer_count, uint32_t width, uint32_t height,
- uint32_t layer_count, uint32_t format, uint64_t usage, const std::string& name)
+ uint32_t layer_count, uint32_t format, uint64_t usage,
+ size_t pending_count, uint64_t state, uint64_t signaled_mask,
+ uint64_t index, const std::string& name)
: id(id),
type(kProducerType),
consumer_count(consumer_count),
@@ -69,6 +75,10 @@
layer_count(layer_count),
format(format),
usage(usage),
+ pending_count(pending_count),
+ state(state),
+ signaled_mask(signaled_mask),
+ index(index),
name(name) {}
BufferInfo(int id, size_t consumer_count, size_t capacity,
@@ -101,6 +111,8 @@
int channel_id() const { return channel_id_; }
bool IsDetached() const { return channel_id_ == kDetachedId; }
+ bool signaled() const { return signaled_; }
+
void Detach() {
if (channel_type_ == kProducerType)
channel_id_ = kDetachedId;
@@ -124,6 +136,8 @@
// buffer if it is detached and re-attached to another channel.
int channel_id_;
+ bool signaled_;
+
ChannelType channel_type_;
BufferHubChannel(const BufferHubChannel&) = delete;
diff --git a/services/vr/bufferhubd/bufferhubd.cpp b/services/vr/bufferhubd/bufferhubd.cpp
index d4fc540..b27f218 100644
--- a/services/vr/bufferhubd/bufferhubd.cpp
+++ b/services/vr/bufferhubd/bufferhubd.cpp
@@ -2,9 +2,10 @@
#include <unistd.h>
#include <log/log.h>
+#include <sys/resource.h>
#include <dvr/performance_client_api.h>
-#include <pdx/default_transport/service_dispatcher.h>
+#include <pdx/service_dispatcher.h>
#include "buffer_hub.h"
@@ -16,7 +17,24 @@
// We need to be able to create endpoints with full perms.
umask(0000);
- dispatcher = android::pdx::default_transport::ServiceDispatcher::Create();
+ // Bump up the soft limit of open fd to the hard limit.
+ struct rlimit64 rlim;
+ ret = getrlimit64(RLIMIT_NOFILE, &rlim);
+ LOG_ALWAYS_FATAL_IF(ret != 0, "Failed to get nofile limit.");
+
+ ALOGI("Current nofile limit is %llu/%llu.", rlim.rlim_cur, rlim.rlim_max);
+ rlim.rlim_cur = rlim.rlim_max;
+ ret = setrlimit64(RLIMIT_NOFILE, &rlim);
+ ALOGE_IF(ret < 0, "Failed to set nofile limit, error=%s", strerror(errno));
+
+ rlim.rlim_cur = -1;
+ rlim.rlim_max = -1;
+ if (getrlimit64(RLIMIT_NOFILE, &rlim) < 0)
+ ALOGE("Failed to get nofile limit.");
+ else
+ ALOGI("New nofile limit is %llu/%llu.", rlim.rlim_cur, rlim.rlim_max);
+
+ dispatcher = android::pdx::ServiceDispatcher::Create();
CHECK_ERROR(!dispatcher, error, "Failed to create service dispatcher\n");
service = android::dvr::BufferHubService::Create();
diff --git a/services/vr/bufferhubd/consumer_channel.cpp b/services/vr/bufferhubd/consumer_channel.cpp
index 08b2790..a6d2dbb 100644
--- a/services/vr/bufferhubd/consumer_channel.cpp
+++ b/services/vr/bufferhubd/consumer_channel.cpp
@@ -8,9 +8,9 @@
#include <private/dvr/bufferhub_rpc.h>
#include "producer_channel.h"
-using android::pdx::ErrorStatus;
using android::pdx::BorrowedHandle;
using android::pdx::Channel;
+using android::pdx::ErrorStatus;
using android::pdx::Message;
using android::pdx::Status;
using android::pdx::rpc::DispatchRemoteMethod;
@@ -19,11 +19,10 @@
namespace dvr {
ConsumerChannel::ConsumerChannel(BufferHubService* service, int buffer_id,
- int channel_id,
+ int channel_id, uint64_t consumer_state_bit,
const std::shared_ptr<Channel> producer)
: BufferHubChannel(service, buffer_id, channel_id, kConsumerType),
- handled_(true),
- ignored_(false),
+ consumer_state_bit_(consumer_state_bit),
producer_(producer) {
GetProducer()->AddConsumer(this);
}
@@ -34,8 +33,6 @@
channel_id(), buffer_id());
if (auto producer = GetProducer()) {
- if (!handled_) // Producer is waiting for our Release.
- producer->OnConsumerIgnored();
producer->RemoveConsumer(this);
}
}
@@ -45,6 +42,8 @@
if (auto producer = GetProducer()) {
// If producer has not hung up, copy most buffer info from the producer.
info = producer->GetBufferInfo();
+ } else {
+ info.signaled_mask = consumer_state_bit();
}
info.id = buffer_id();
return info;
@@ -57,6 +56,9 @@
void ConsumerChannel::HandleImpulse(Message& message) {
ATRACE_NAME("ConsumerChannel::HandleImpulse");
switch (message.GetOp()) {
+ case BufferHubRPC::ConsumerAcquire::Opcode:
+ OnConsumerAcquire(message);
+ break;
case BufferHubRPC::ConsumerRelease::Opcode:
OnConsumerRelease(message, {});
break;
@@ -72,7 +74,7 @@
switch (message.GetOp()) {
case BufferHubRPC::GetBuffer::Opcode:
DispatchRemoteMethod<BufferHubRPC::GetBuffer>(
- *producer, &ProducerChannel::OnGetBuffer, message);
+ *this, &ConsumerChannel::OnGetBuffer, message);
return true;
case BufferHubRPC::NewConsumer::Opcode:
@@ -100,23 +102,37 @@
}
}
-Status<std::pair<BorrowedFence, ConsumerChannel::MetaData>>
-ConsumerChannel::OnConsumerAcquire(Message& message,
- std::size_t metadata_size) {
+Status<BufferDescription<BorrowedHandle>> ConsumerChannel::OnGetBuffer(
+ Message& /*message*/) {
+ ATRACE_NAME("ConsumerChannel::OnGetBuffer");
+ ALOGD_IF(TRACE, "ConsumerChannel::OnGetBuffer: buffer=%d", buffer_id());
+ if (auto producer = GetProducer()) {
+ return {producer->GetBuffer(consumer_state_bit_)};
+ } else {
+ return ErrorStatus(EPIPE);
+ }
+}
+
+Status<LocalFence> ConsumerChannel::OnConsumerAcquire(Message& message) {
ATRACE_NAME("ConsumerChannel::OnConsumerAcquire");
auto producer = GetProducer();
if (!producer)
return ErrorStatus(EPIPE);
- if (ignored_ || handled_) {
+ if (acquired_ || released_) {
ALOGE(
"ConsumerChannel::OnConsumerAcquire: Acquire when not posted: "
- "ignored=%d handled=%d channel_id=%d buffer_id=%d",
- ignored_, handled_, message.GetChannelId(), producer->buffer_id());
+ "ignored=%d acquired=%d released=%d channel_id=%d buffer_id=%d",
+ ignored_, acquired_, released_, message.GetChannelId(),
+ producer->buffer_id());
return ErrorStatus(EBUSY);
} else {
- ClearAvailable();
- return producer->OnConsumerAcquire(message, metadata_size);
+ auto status = producer->OnConsumerAcquire(message);
+ if (status) {
+ ClearAvailable();
+ acquired_ = true;
+ }
+ return status;
}
}
@@ -127,17 +143,21 @@
if (!producer)
return ErrorStatus(EPIPE);
- if (ignored_ || handled_) {
+ if (!acquired_ || released_) {
ALOGE(
"ConsumerChannel::OnConsumerRelease: Release when not acquired: "
- "ignored=%d handled=%d channel_id=%d buffer_id=%d",
- ignored_, handled_, message.GetChannelId(), producer->buffer_id());
+ "ignored=%d acquired=%d released=%d channel_id=%d buffer_id=%d",
+ ignored_, acquired_, released_, message.GetChannelId(),
+ producer->buffer_id());
return ErrorStatus(EBUSY);
} else {
- ClearAvailable();
auto status =
producer->OnConsumerRelease(message, std::move(release_fence));
- handled_ = !!status;
+ if (status) {
+ ClearAvailable();
+ acquired_ = false;
+ released_ = true;
+ }
return status;
}
}
@@ -149,12 +169,13 @@
return ErrorStatus(EPIPE);
ignored_ = ignored;
- if (ignored_ && !handled_) {
+ if (ignored_ && acquired_) {
// Update the producer if ignore is set after the consumer acquires the
// buffer.
ClearAvailable();
producer->OnConsumerIgnored();
- handled_ = false;
+ acquired_ = false;
+ released_ = true;
}
return {};
@@ -162,10 +183,12 @@
bool ConsumerChannel::OnProducerPosted() {
if (ignored_) {
- handled_ = true;
+ acquired_ = false;
+ released_ = true;
return false;
} else {
- handled_ = false;
+ acquired_ = false;
+ released_ = false;
SignalAvailable();
return true;
}
diff --git a/services/vr/bufferhubd/consumer_channel.h b/services/vr/bufferhubd/consumer_channel.h
index d84055c..55cf969 100644
--- a/services/vr/bufferhubd/consumer_channel.h
+++ b/services/vr/bufferhubd/consumer_channel.h
@@ -12,34 +12,38 @@
// Consumer channels are attached to a Producer channel
class ConsumerChannel : public BufferHubChannel {
public:
+ using BorrowedHandle = pdx::BorrowedHandle;
using Channel = pdx::Channel;
using Message = pdx::Message;
ConsumerChannel(BufferHubService* service, int buffer_id, int channel_id,
+ uint64_t consumer_state_bit,
const std::shared_ptr<Channel> producer);
~ConsumerChannel() override;
bool HandleMessage(Message& message) override;
void HandleImpulse(Message& message) override;
+ uint64_t consumer_state_bit() const { return consumer_state_bit_; }
BufferInfo GetBufferInfo() const override;
bool OnProducerPosted();
void OnProducerClosed();
private:
- using MetaData = pdx::rpc::BufferWrapper<std::uint8_t*>;
-
std::shared_ptr<ProducerChannel> GetProducer() const;
- pdx::Status<std::pair<BorrowedFence, MetaData>> OnConsumerAcquire(
- Message& message, std::size_t metadata_size);
+ pdx::Status<BufferDescription<BorrowedHandle>> OnGetBuffer(Message& message);
+
+ pdx::Status<LocalFence> OnConsumerAcquire(Message& message);
pdx::Status<void> OnConsumerRelease(Message& message,
LocalFence release_fence);
pdx::Status<void> OnConsumerSetIgnore(Message& message, bool ignore);
- bool handled_; // True if we have processed RELEASE.
- bool ignored_; // True if we are ignoring events.
+ uint64_t consumer_state_bit_{0};
+ bool acquired_{false};
+ bool released_{true};
+ bool ignored_{false}; // True if we are ignoring events.
std::weak_ptr<Channel> producer_;
ConsumerChannel(const ConsumerChannel&) = delete;
diff --git a/services/vr/bufferhubd/consumer_queue_channel.cpp b/services/vr/bufferhubd/consumer_queue_channel.cpp
index f447e00..4d43001 100644
--- a/services/vr/bufferhubd/consumer_queue_channel.cpp
+++ b/services/vr/bufferhubd/consumer_queue_channel.cpp
@@ -15,10 +15,11 @@
ConsumerQueueChannel::ConsumerQueueChannel(
BufferHubService* service, int buffer_id, int channel_id,
- const std::shared_ptr<Channel>& producer)
+ const std::shared_ptr<Channel>& producer, bool silent)
: BufferHubChannel(service, buffer_id, channel_id, kConsumerQueueType),
producer_(producer),
- capacity_(0) {
+ capacity_(0),
+ silent_(silent) {
GetProducer()->AddConsumer(this);
}
@@ -83,23 +84,30 @@
void ConsumerQueueChannel::RegisterNewBuffer(
const std::shared_ptr<ProducerChannel>& producer_channel, size_t slot) {
ALOGD_IF(TRACE,
- "ConsumerQueueChannel::RegisterNewBuffer: buffer_id=%d slot=%zu",
- producer_channel->buffer_id(), slot);
- pending_buffer_slots_.emplace(producer_channel, slot);
+ "ConsumerQueueChannel::RegisterNewBuffer: queue_id=%d buffer_id=%d "
+ "slot=%zu silent=%d",
+ buffer_id(), producer_channel->buffer_id(), slot, silent_);
+ // Only register buffers if the queue is not silent.
+ if (!silent_) {
+ pending_buffer_slots_.emplace(producer_channel, slot);
- // Signal the client that there is new buffer available throught POLLIN.
- SignalAvailable();
+ // Signal the client that there is new buffer available.
+ SignalAvailable();
+ }
}
Status<std::vector<std::pair<RemoteChannelHandle, size_t>>>
ConsumerQueueChannel::OnConsumerQueueImportBuffers(Message& message) {
std::vector<std::pair<RemoteChannelHandle, size_t>> buffer_handles;
ATRACE_NAME("ConsumerQueueChannel::OnConsumerQueueImportBuffers");
- ALOGD_IF(
- TRACE,
- "ConsumerQueueChannel::OnConsumerQueueImportBuffers number of buffers to "
- "import: %zu",
- pending_buffer_slots_.size());
+ ALOGD_IF(TRACE,
+ "ConsumerQueueChannel::OnConsumerQueueImportBuffers: "
+ "pending_buffer_slots=%zu",
+ pending_buffer_slots_.size());
+
+ // Indicate this is a silent queue that will not import buffers.
+ if (silent_)
+ return ErrorStatus(EBADR);
while (!pending_buffer_slots_.empty()) {
auto producer_channel = pending_buffer_slots_.front().first.lock();
diff --git a/services/vr/bufferhubd/consumer_queue_channel.h b/services/vr/bufferhubd/consumer_queue_channel.h
index aa3f531..8437c4c 100644
--- a/services/vr/bufferhubd/consumer_queue_channel.h
+++ b/services/vr/bufferhubd/consumer_queue_channel.h
@@ -19,7 +19,7 @@
using RemoteChannelHandle = pdx::RemoteChannelHandle;
ConsumerQueueChannel(BufferHubService* service, int buffer_id, int channel_id,
- const std::shared_ptr<Channel>& producer);
+ const std::shared_ptr<Channel>& producer, bool silent);
~ConsumerQueueChannel() override;
bool HandleMessage(Message& message) override;
@@ -54,6 +54,10 @@
// Tracks how many buffers have this queue imported.
size_t capacity_;
+ // A silent queue does not signal or export buffers. It is only used to spawn
+ // another consumer queue.
+ bool silent_;
+
ConsumerQueueChannel(const ConsumerQueueChannel&) = delete;
void operator=(const ConsumerQueueChannel&) = delete;
};
diff --git a/services/vr/bufferhubd/producer_channel.cpp b/services/vr/bufferhubd/producer_channel.cpp
index b9984a0..716db5e 100644
--- a/services/vr/bufferhubd/producer_channel.cpp
+++ b/services/vr/bufferhubd/producer_channel.cpp
@@ -2,6 +2,8 @@
#include <log/log.h>
#include <sync/sync.h>
+#include <sys/epoll.h>
+#include <sys/eventfd.h>
#include <sys/poll.h>
#include <utils/Trace.h>
@@ -24,24 +26,88 @@
namespace android {
namespace dvr {
+namespace {
+
+static inline uint64_t FindNextClearedBit(uint64_t bits) {
+ return ~bits - (~bits & (~bits - 1));
+}
+
+} // namespace
+
ProducerChannel::ProducerChannel(BufferHubService* service, int channel_id,
uint32_t width, uint32_t height,
uint32_t layer_count, uint32_t format,
- uint64_t usage, size_t meta_size_bytes,
+ uint64_t usage, size_t user_metadata_size,
int* error)
: BufferHubChannel(service, channel_id, channel_id, kProducerType),
pending_consumers_(0),
producer_owns_(true),
- meta_size_bytes_(meta_size_bytes),
- meta_(meta_size_bytes ? new uint8_t[meta_size_bytes] : nullptr) {
- const int ret = buffer_.Alloc(width, height, layer_count, format, usage);
- if (ret < 0) {
+ user_metadata_size_(user_metadata_size),
+ metadata_buf_size_(BufferHubDefs::kMetadataHeaderSize +
+ user_metadata_size) {
+ if (int ret = buffer_.Alloc(width, height, layer_count, format, usage)) {
ALOGE("ProducerChannel::ProducerChannel: Failed to allocate buffer: %s",
strerror(-ret));
*error = ret;
return;
}
+ if (int ret = metadata_buffer_.Alloc(metadata_buf_size_, /*height=*/1,
+ /*layer_count=*/1,
+ BufferHubDefs::kMetadataFormat,
+ BufferHubDefs::kMetadataUsage)) {
+ ALOGE("ProducerChannel::ProducerChannel: Failed to allocate metadata: %s",
+ strerror(-ret));
+ *error = ret;
+ return;
+ }
+
+ void* metadata_ptr = nullptr;
+ if (int ret = metadata_buffer_.Lock(BufferHubDefs::kMetadataUsage, /*x=*/0,
+ /*y=*/0, metadata_buf_size_,
+ /*height=*/1, &metadata_ptr)) {
+ ALOGE("ProducerChannel::ProducerChannel: Failed to lock metadata.");
+ *error = -ret;
+ return;
+ }
+ metadata_header_ =
+ reinterpret_cast<BufferHubDefs::MetadataHeader*>(metadata_ptr);
+
+ // Using placement new here to reuse shared memory instead of new allocation
+ // and also initialize the value to zero.
+ buffer_state_ =
+ new (&metadata_header_->buffer_state) std::atomic<uint64_t>(0);
+ fence_state_ =
+ new (&metadata_header_->fence_state) std::atomic<uint64_t>(0);
+
+ acquire_fence_fd_.Reset(epoll_create1(EPOLL_CLOEXEC));
+ release_fence_fd_.Reset(epoll_create1(EPOLL_CLOEXEC));
+ if (!acquire_fence_fd_ || !release_fence_fd_) {
+ ALOGE("ProducerChannel::ProducerChannel: Failed to create shared fences.");
+ *error = -EIO;
+ return;
+ }
+
+ dummy_fence_fd_.Reset(eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK));
+ if (!dummy_fence_fd_) {
+ ALOGE("ProducerChannel::ProducerChannel: Failed to create dummy fences.");
+ *error = -EIO;
+ return;
+ }
+
+ epoll_event event;
+ event.events = 0;
+ event.data.u64 = 0ULL;
+ if (epoll_ctl(release_fence_fd_.Get(), EPOLL_CTL_ADD, dummy_fence_fd_.Get(),
+ &event) < 0) {
+ ALOGE(
+ "ProducerChannel::ProducerChannel: Failed to modify the shared "
+ "release fence to include the dummy fence: %s",
+ strerror(errno));
+ *error = -EIO;
+ return;
+ }
+
// Success.
*error = 0;
}
@@ -49,11 +115,11 @@
Status<std::shared_ptr<ProducerChannel>> ProducerChannel::Create(
BufferHubService* service, int channel_id, uint32_t width, uint32_t height,
uint32_t layer_count, uint32_t format, uint64_t usage,
- size_t meta_size_bytes) {
+ size_t user_metadata_size) {
int error;
std::shared_ptr<ProducerChannel> producer(
new ProducerChannel(service, channel_id, width, height, layer_count,
- format, usage, meta_size_bytes, &error));
+ format, usage, user_metadata_size, &error));
if (error < 0)
return ErrorStatus(-error);
else
@@ -62,16 +128,24 @@
ProducerChannel::~ProducerChannel() {
ALOGD_IF(TRACE,
- "ProducerChannel::~ProducerChannel: channel_id=%d buffer_id=%d",
- channel_id(), buffer_id());
+ "ProducerChannel::~ProducerChannel: channel_id=%d buffer_id=%d "
+ "state=%" PRIx64 ".",
+ channel_id(), buffer_id(), buffer_state_->load());
for (auto consumer : consumer_channels_)
consumer->OnProducerClosed();
}
BufferHubChannel::BufferInfo ProducerChannel::GetBufferInfo() const {
+ // Derive the mask of signaled buffers in this producer / consumer set.
+ uint64_t signaled_mask = signaled() ? BufferHubDefs::kProducerStateBit : 0;
+ for (const ConsumerChannel* consumer : consumer_channels_) {
+ signaled_mask |= consumer->signaled() ? consumer->consumer_state_bit() : 0;
+ }
+
return BufferInfo(buffer_id(), consumer_channels_.size(), buffer_.width(),
buffer_.height(), buffer_.layer_count(), buffer_.format(),
- buffer_.usage(), name_);
+ buffer_.usage(), pending_consumers_, buffer_state_->load(),
+ signaled_mask, metadata_header_->queue_index, name_);
}
void ProducerChannel::HandleImpulse(Message& message) {
@@ -80,6 +154,9 @@
case BufferHubRPC::ProducerGain::Opcode:
OnProducerGain(message);
break;
+ case BufferHubRPC::ProducerPost::Opcode:
+ OnProducerPost(message, {});
+ break;
}
}
@@ -121,16 +198,26 @@
}
}
-Status<NativeBufferHandle<BorrowedHandle>> ProducerChannel::OnGetBuffer(
- Message& message) {
+BufferDescription<BorrowedHandle> ProducerChannel::GetBuffer(
+ uint64_t buffer_state_bit) {
+ return {
+ buffer_, metadata_buffer_, buffer_id(),
+ buffer_state_bit, acquire_fence_fd_.Borrow(), release_fence_fd_.Borrow()};
+}
+
+Status<BufferDescription<BorrowedHandle>> ProducerChannel::OnGetBuffer(
+ Message& /*message*/) {
ATRACE_NAME("ProducerChannel::OnGetBuffer");
- ALOGD_IF(TRACE, "ProducerChannel::OnGetBuffer: buffer=%d", buffer_id());
- return {NativeBufferHandle<BorrowedHandle>(buffer_, buffer_id())};
+ ALOGD_IF(TRACE, "ProducerChannel::OnGetBuffer: buffer=%d, state=%" PRIx64 ".",
+ buffer_id(), buffer_state_->load());
+ return {GetBuffer(BufferHubDefs::kProducerStateBit)};
}
Status<RemoteChannelHandle> ProducerChannel::CreateConsumer(Message& message) {
ATRACE_NAME("ProducerChannel::CreateConsumer");
- ALOGD_IF(TRACE, "ProducerChannel::CreateConsumer: buffer_id=%d", buffer_id());
+ ALOGD_IF(TRACE,
+ "ProducerChannel::CreateConsumer: buffer_id=%d, producer_owns=%d",
+ buffer_id(), producer_owns_);
int channel_id;
auto status = message.PushChannel(0, nullptr, &channel_id);
@@ -141,8 +228,21 @@
return ErrorStatus(ENOMEM);
}
- auto consumer = std::make_shared<ConsumerChannel>(
- service(), buffer_id(), channel_id, shared_from_this());
+ // Try find the next consumer state bit which has not been claimed by any
+ // consumer yet.
+ uint64_t consumer_state_bit = FindNextClearedBit(
+ active_consumer_bit_mask_ | orphaned_consumer_bit_mask_ |
+ BufferHubDefs::kProducerStateBit);
+ if (consumer_state_bit == 0ULL) {
+ ALOGE(
+ "ProducerChannel::CreateConsumer: reached the maximum mumber of "
+ "consumers per producer: 63.");
+ return ErrorStatus(E2BIG);
+ }
+
+ auto consumer =
+ std::make_shared<ConsumerChannel>(service(), buffer_id(), channel_id,
+ consumer_state_bit, shared_from_this());
const auto channel_status = service()->SetChannel(channel_id, consumer);
if (!channel_status) {
ALOGE(
@@ -152,12 +252,14 @@
return ErrorStatus(ENOMEM);
}
- if (!producer_owns_) {
+ if (!producer_owns_ &&
+ !BufferHubDefs::IsBufferReleased(buffer_state_->load())) {
// Signal the new consumer when adding it to a posted producer.
if (consumer->OnProducerPosted())
pending_consumers_++;
}
+ active_consumer_bit_mask_ |= consumer_state_bit;
return {status.take()};
}
@@ -168,8 +270,7 @@
}
Status<void> ProducerChannel::OnProducerPost(
- Message&, LocalFence acquire_fence,
- BufferWrapper<std::vector<std::uint8_t>> metadata) {
+ Message&, LocalFence acquire_fence) {
ATRACE_NAME("ProducerChannel::OnProducerPost");
ALOGD_IF(TRACE, "ProducerChannel::OnProducerPost: buffer_id=%d", buffer_id());
if (!producer_owns_) {
@@ -177,34 +278,52 @@
return ErrorStatus(EBUSY);
}
- if (meta_size_bytes_ != metadata.size()) {
- ALOGD_IF(TRACE,
- "ProducerChannel::OnProducerPost: Expected meta_size_bytes=%zu "
- "got size=%zu",
- meta_size_bytes_, metadata.size());
- return ErrorStatus(EINVAL);
+ epoll_event event;
+ event.events = 0;
+ event.data.u64 = 0ULL;
+ int ret = epoll_ctl(release_fence_fd_.Get(), EPOLL_CTL_MOD,
+ dummy_fence_fd_.Get(), &event);
+ ALOGE_IF(ret < 0,
+ "ProducerChannel::OnProducerPost: Failed to modify the shared "
+ "release fence to include the dummy fence: %s",
+ strerror(errno));
+
+ eventfd_t dummy_fence_count = 0ULL;
+ if (eventfd_read(dummy_fence_fd_.Get(), &dummy_fence_count) < 0) {
+ const int error = errno;
+ if (error != EAGAIN) {
+ ALOGE(
+ "ProducerChannel::ProducerChannel: Failed to read dummy fence, "
+ "error: %s",
+ strerror(error));
+ return ErrorStatus(error);
+ }
}
- std::copy(metadata.begin(), metadata.end(), meta_.get());
+ ALOGW_IF(dummy_fence_count > 0,
+ "ProducerChannel::ProducerChannel: %" PRIu64
+ " dummy fence(s) was signaled during last release/gain cycle "
+ "buffer_id=%d.",
+ dummy_fence_count, buffer_id());
+
post_fence_ = std::move(acquire_fence);
producer_owns_ = false;
- // Signal any interested consumers. If there are none, automatically release
- // the buffer.
+ // Signal any interested consumers. If there are none, the buffer will stay
+ // in posted state until a consumer comes online. This behavior guarantees
+ // that no frame is silently dropped.
pending_consumers_ = 0;
for (auto consumer : consumer_channels_) {
if (consumer->OnProducerPosted())
pending_consumers_++;
}
- if (pending_consumers_ == 0)
- SignalAvailable();
ALOGD_IF(TRACE, "ProducerChannel::OnProducerPost: %d pending consumers",
pending_consumers_);
return {};
}
-Status<LocalFence> ProducerChannel::OnProducerGain(Message& message) {
+Status<LocalFence> ProducerChannel::OnProducerGain(Message& /*message*/) {
ATRACE_NAME("ProducerChannel::OnGain");
ALOGD_IF(TRACE, "ProducerChannel::OnGain: buffer_id=%d", buffer_id());
if (producer_owns_) {
@@ -214,8 +333,13 @@
}
// There are still pending consumers, return busy.
- if (pending_consumers_ > 0)
+ if (pending_consumers_ > 0) {
+ ALOGE(
+ "ProducerChannel::OnGain: Producer (id=%d) is gaining a buffer that "
+ "still has %d pending consumer(s).",
+ buffer_id(), pending_consumers_);
return ErrorStatus(EBUSY);
+ }
ClearAvailable();
producer_owns_ = true;
@@ -223,9 +347,7 @@
return {std::move(returned_fence_)};
}
-Status<std::pair<BorrowedFence, BufferWrapper<std::uint8_t*>>>
-ProducerChannel::OnConsumerAcquire(Message& message,
- std::size_t metadata_size) {
+Status<LocalFence> ProducerChannel::OnConsumerAcquire(Message& /*message*/) {
ATRACE_NAME("ProducerChannel::OnConsumerAcquire");
ALOGD_IF(TRACE, "ProducerChannel::OnConsumerAcquire: buffer_id=%d",
buffer_id());
@@ -236,12 +358,7 @@
// Return a borrowed fd to avoid unnecessary duplication of the underlying fd.
// Serialization just needs to read the handle.
- if (metadata_size == 0)
- return {std::make_pair(post_fence_.borrow(),
- WrapBuffer<std::uint8_t>(nullptr, 0))};
- else
- return {std::make_pair(post_fence_.borrow(),
- WrapBuffer(meta_.get(), meta_size_bytes_))};
+ return {std::move(post_fence_)};
}
Status<void> ProducerChannel::OnConsumerRelease(Message&,
@@ -273,17 +390,75 @@
}
OnConsumerIgnored();
+ if (pending_consumers_ == 0) {
+ // Clear the producer bit atomically to transit into released state. This
+ // has to done by BufferHub as it requries synchronization among all
+ // consumers.
+ BufferHubDefs::ModifyBufferState(buffer_state_,
+ BufferHubDefs::kProducerStateBit, 0ULL);
+ ALOGD_IF(TRACE,
+ "ProducerChannel::OnConsumerRelease: releasing last consumer: "
+ "buffer_id=%d state=%" PRIx64 ".",
+ buffer_id(), buffer_state_->load());
+
+ if (orphaned_consumer_bit_mask_) {
+ ALOGW(
+ "ProducerChannel::OnConsumerRelease: orphaned buffer detected "
+ "during the this acquire/release cycle: id=%d orphaned=0x%" PRIx64
+ " queue_index=%" PRIu64 ".",
+ buffer_id(), orphaned_consumer_bit_mask_,
+ metadata_header_->queue_index);
+ orphaned_consumer_bit_mask_ = 0;
+ }
+
+ SignalAvailable();
+ }
+
+ ALOGE_IF(pending_consumers_ &&
+ BufferHubDefs::IsBufferReleased(buffer_state_->load()),
+ "ProducerChannel::OnConsumerRelease: buffer state inconsistent: "
+ "pending_consumers=%d, buffer buffer is in releaed state.",
+ pending_consumers_);
return {};
}
void ProducerChannel::OnConsumerIgnored() {
- if (!--pending_consumers_)
- SignalAvailable();
+ if (pending_consumers_ == 0) {
+ ALOGE("ProducerChannel::OnConsumerIgnored: no pending consumer.");
+ return;
+ }
+
+ --pending_consumers_;
ALOGD_IF(TRACE,
"ProducerChannel::OnConsumerIgnored: buffer_id=%d %d consumers left",
buffer_id(), pending_consumers_);
}
+void ProducerChannel::OnConsumerOrphaned(ConsumerChannel* channel) {
+ // Ignore the orphaned consumer.
+ OnConsumerIgnored();
+
+ const uint64_t consumer_state_bit = channel->consumer_state_bit();
+ ALOGE_IF(orphaned_consumer_bit_mask_ & consumer_state_bit,
+ "ProducerChannel::OnConsumerOrphaned: Consumer "
+ "(consumer_state_bit=%" PRIx64 ") is already orphaned.",
+ consumer_state_bit);
+ orphaned_consumer_bit_mask_ |= consumer_state_bit;
+
+ // Atomically clear the fence state bit as an orphaned consumer will never
+ // signal a release fence. Also clear the buffer state as it won't be released
+ // as well.
+ fence_state_->fetch_and(~consumer_state_bit);
+ BufferHubDefs::ModifyBufferState(buffer_state_, consumer_state_bit, 0ULL);
+
+ ALOGW(
+ "ProducerChannel::OnConsumerOrphaned: detected new orphaned consumer "
+ "buffer_id=%d consumer_state_bit=%" PRIx64 " queue_index=%" PRIu64
+ " buffer_state=%" PRIx64 " fence_state=%" PRIx64 ".",
+ buffer_id(), consumer_state_bit, metadata_header_->queue_index,
+ buffer_state_->load(), fence_state_->load());
+}
+
Status<void> ProducerChannel::OnProducerMakePersistent(Message& message,
const std::string& name,
int user_id,
@@ -335,6 +510,40 @@
void ProducerChannel::RemoveConsumer(ConsumerChannel* channel) {
consumer_channels_.erase(
std::find(consumer_channels_.begin(), consumer_channels_.end(), channel));
+ active_consumer_bit_mask_ &= ~channel->consumer_state_bit();
+
+ const uint64_t buffer_state = buffer_state_->load();
+ if (BufferHubDefs::IsBufferPosted(buffer_state) ||
+ BufferHubDefs::IsBufferAcquired(buffer_state)) {
+ // The consumer client is being destoryed without releasing. This could
+ // happen in corner cases when the consumer crashes. Here we mark it
+ // orphaned before remove it from producer.
+ OnConsumerOrphaned(channel);
+ }
+
+ if (BufferHubDefs::IsBufferReleased(buffer_state) ||
+ BufferHubDefs::IsBufferGained(buffer_state)) {
+ // The consumer is being close while it is suppose to signal a release
+ // fence. Signal the dummy fence here.
+ if (fence_state_->load() & channel->consumer_state_bit()) {
+ epoll_event event;
+ event.events = EPOLLIN;
+ event.data.u64 = channel->consumer_state_bit();
+ if (epoll_ctl(release_fence_fd_.Get(), EPOLL_CTL_MOD,
+ dummy_fence_fd_.Get(), &event) < 0) {
+ ALOGE(
+ "ProducerChannel::RemoveConsumer: Failed to modify the shared "
+ "release fence to include the dummy fence: %s",
+ strerror(errno));
+ return;
+ }
+ ALOGW(
+ "ProducerChannel::RemoveConsumer: signal dummy release fence "
+ "buffer_id=%d",
+ buffer_id());
+ eventfd_write(dummy_fence_fd_.Get(), 1);
+ }
+ }
}
// Returns true if either the user or group ids match the owning ids or both
@@ -350,10 +559,12 @@
// Returns true if the given parameters match the underlying buffer parameters.
bool ProducerChannel::CheckParameters(uint32_t width, uint32_t height,
uint32_t layer_count, uint32_t format,
- uint64_t usage, size_t meta_size_bytes) {
- return meta_size_bytes == meta_size_bytes_ && buffer_.width() == width &&
- buffer_.height() == height && buffer_.layer_count() == layer_count &&
- buffer_.format() == format && buffer_.usage() == usage;
+ uint64_t usage,
+ size_t user_metadata_size) {
+ return user_metadata_size == user_metadata_size_ &&
+ buffer_.width() == width && buffer_.height() == height &&
+ buffer_.layer_count() == layer_count && buffer_.format() == format &&
+ buffer_.usage() == usage;
}
} // namespace dvr
diff --git a/services/vr/bufferhubd/producer_channel.h b/services/vr/bufferhubd/producer_channel.h
index 5ada478..e280f4d 100644
--- a/services/vr/bufferhubd/producer_channel.h
+++ b/services/vr/bufferhubd/producer_channel.h
@@ -33,7 +33,7 @@
static pdx::Status<std::shared_ptr<ProducerChannel>> Create(
BufferHubService* service, int channel_id, uint32_t width,
uint32_t height, uint32_t layer_count, uint32_t format, uint64_t usage,
- size_t meta_size_bytes);
+ size_t user_metadata_size);
~ProducerChannel() override;
@@ -42,24 +42,25 @@
BufferInfo GetBufferInfo() const override;
- pdx::Status<NativeBufferHandle<BorrowedHandle>> OnGetBuffer(Message& message);
+ BufferDescription<BorrowedHandle> GetBuffer(uint64_t buffer_state_bit);
pdx::Status<RemoteChannelHandle> CreateConsumer(Message& message);
pdx::Status<RemoteChannelHandle> OnNewConsumer(Message& message);
- pdx::Status<std::pair<BorrowedFence, BufferWrapper<std::uint8_t*>>>
- OnConsumerAcquire(Message& message, std::size_t metadata_size);
+ pdx::Status<LocalFence> OnConsumerAcquire(Message& message);
pdx::Status<void> OnConsumerRelease(Message& message,
LocalFence release_fence);
void OnConsumerIgnored();
+ void OnConsumerOrphaned(ConsumerChannel* channel);
void AddConsumer(ConsumerChannel* channel);
void RemoveConsumer(ConsumerChannel* channel);
bool CheckAccess(int euid, int egid);
bool CheckParameters(uint32_t width, uint32_t height, uint32_t layer_count,
- uint32_t format, uint64_t usage, size_t meta_size_bytes);
+ uint32_t format, uint64_t usage,
+ size_t user_metadata_size);
pdx::Status<void> OnProducerMakePersistent(Message& message,
const std::string& name,
@@ -74,11 +75,28 @@
IonBuffer buffer_;
+ // IonBuffer that is shared between bufferhubd, producer, and consumers.
+ IonBuffer metadata_buffer_;
+ BufferHubDefs::MetadataHeader* metadata_header_ = nullptr;
+ std::atomic<uint64_t>* buffer_state_ = nullptr;
+ std::atomic<uint64_t>* fence_state_ = nullptr;
+
+ // All active consumer bits. Valid bits are the lower 63 bits, while the
+ // highest bit is reserved for the producer and should not be set.
+ uint64_t active_consumer_bit_mask_{0ULL};
+ // All orphaned consumer bits. Valid bits are the lower 63 bits, while the
+ // highest bit is reserved for the producer and should not be set.
+ uint64_t orphaned_consumer_bit_mask_{0ULL};
+
bool producer_owns_;
LocalFence post_fence_;
LocalFence returned_fence_;
- size_t meta_size_bytes_;
- std::unique_ptr<uint8_t[]> meta_;
+ size_t user_metadata_size_; // size of user requested buffer buffer size.
+ size_t metadata_buf_size_; // size of the ion buffer that holds metadata.
+
+ pdx::LocalHandle acquire_fence_fd_;
+ pdx::LocalHandle release_fence_fd_;
+ pdx::LocalHandle dummy_fence_fd_;
static constexpr int kNoCheckId = -1;
static constexpr int kUseCallerId = 0;
@@ -92,11 +110,10 @@
ProducerChannel(BufferHubService* service, int channel, uint32_t width,
uint32_t height, uint32_t layer_count, uint32_t format,
- uint64_t usage, size_t meta_size_bytes, int* error);
+ uint64_t usage, size_t user_metadata_size, int* error);
- pdx::Status<void> OnProducerPost(
- Message& message, LocalFence acquire_fence,
- BufferWrapper<std::vector<std::uint8_t>> metadata);
+ pdx::Status<BufferDescription<BorrowedHandle>> OnGetBuffer(Message& message);
+ pdx::Status<void> OnProducerPost(Message& message, LocalFence acquire_fence);
pdx::Status<LocalFence> OnProducerGain(Message& message);
ProducerChannel(const ProducerChannel&) = delete;
diff --git a/services/vr/bufferhubd/producer_queue_channel.cpp b/services/vr/bufferhubd/producer_queue_channel.cpp
index b8bb728..c0c48c2 100644
--- a/services/vr/bufferhubd/producer_queue_channel.cpp
+++ b/services/vr/bufferhubd/producer_queue_channel.cpp
@@ -7,8 +7,8 @@
using android::pdx::ErrorStatus;
using android::pdx::Message;
-using android::pdx::Status;
using android::pdx::RemoteChannelHandle;
+using android::pdx::Status;
using android::pdx::rpc::DispatchRemoteMethod;
namespace android {
@@ -96,10 +96,12 @@
}
Status<RemoteChannelHandle> ProducerQueueChannel::OnCreateConsumerQueue(
- Message& message) {
+ Message& message, bool silent) {
ATRACE_NAME("ProducerQueueChannel::OnCreateConsumerQueue");
- ALOGD_IF(TRACE, "ProducerQueueChannel::OnCreateConsumerQueue: channel_id=%d",
- channel_id());
+ ALOGD_IF(
+ TRACE,
+ "ProducerQueueChannel::OnCreateConsumerQueue: channel_id=%d slient=%d",
+ channel_id(), silent);
int channel_id;
auto status = message.PushChannel(0, nullptr, &channel_id);
@@ -112,7 +114,7 @@
}
auto consumer_queue_channel = std::make_shared<ConsumerQueueChannel>(
- service(), buffer_id(), channel_id, shared_from_this());
+ service(), buffer_id(), channel_id, shared_from_this(), silent);
// Register the existing buffers with the new consumer queue.
for (size_t slot = 0; slot < BufferHubRPC::kMaxQueueCapacity; slot++) {
@@ -222,7 +224,7 @@
auto producer_channel_status =
ProducerChannel::Create(service(), buffer_id, width, height, layer_count,
- format, usage, config_.meta_size_bytes);
+ format, usage, config_.user_metadata_size);
if (!producer_channel_status) {
ALOGE(
"ProducerQueueChannel::AllocateBuffer: Failed to create producer "
diff --git a/services/vr/bufferhubd/producer_queue_channel.h b/services/vr/bufferhubd/producer_queue_channel.h
index fd519c5..e825f47 100644
--- a/services/vr/bufferhubd/producer_queue_channel.h
+++ b/services/vr/bufferhubd/producer_queue_channel.h
@@ -26,7 +26,7 @@
// Returns a handle for the service channel, as well as the size of the
// metadata associated with the queue.
pdx::Status<pdx::RemoteChannelHandle> OnCreateConsumerQueue(
- pdx::Message& message);
+ pdx::Message& message, bool silent);
pdx::Status<QueueInfo> OnGetQueueInfo(pdx::Message& message);
diff --git a/services/vr/hardware_composer/Android.bp b/services/vr/hardware_composer/Android.bp
index 9201520..e92b8d8 100644
--- a/services/vr/hardware_composer/Android.bp
+++ b/services/vr/hardware_composer/Android.bp
@@ -44,6 +44,13 @@
cflags: [
"-DLOG_TAG=\"vr_hwc\"",
+ "-Wall",
+ "-Werror",
+ // mVrClient unused in vr_composer_client.cpp
+ "-Wno-error=unused-private-field",
+ // Warnings in vr_hwc.cpp to be fixed after sync of goog/master.
+ "-Wno-sign-compare",
+ "-Wno-unused-parameter",
],
}
@@ -63,6 +70,11 @@
},
export_include_dirs: ["aidl"],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+
shared_libs: [
"libbinder",
"libui",
@@ -92,6 +104,8 @@
],
cflags: [
"-DLOG_TAG=\"vr_hwc\"",
+ "-Wall",
+ "-Werror",
],
}
@@ -120,6 +134,8 @@
],
cflags: [
"-DLOG_TAG=\"vr_hwc\"",
+ "-Wall",
+ "-Werror",
],
init_rc: [
"vr_hwc.rc",
@@ -137,6 +153,13 @@
// symbols in the *-binder library get optimized out.
"libvr_hwc-binder",
],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ // warnings in vr_composer_test.cpp to be fixed after merge of goog/master
+ "-Wno-sign-compare",
+ "-Wno-unused-parameter",
+ ],
shared_libs: [
"libbase",
"libbinder",
diff --git a/services/vr/hardware_composer/aidl/android/dvr/IVrComposer.aidl b/services/vr/hardware_composer/aidl/android/dvr/IVrComposer.aidl
index 5fd5c36..be1ec5b 100644
--- a/services/vr/hardware_composer/aidl/android/dvr/IVrComposer.aidl
+++ b/services/vr/hardware_composer/aidl/android/dvr/IVrComposer.aidl
@@ -17,4 +17,9 @@
* Registers a callback used to receive frame notifications.
*/
void registerObserver(in IVrComposerCallback callback);
+
+ /**
+ * Clears a previously registered frame notification callback.
+ */
+ void clearObserver();
}
diff --git a/services/vr/hardware_composer/impl/vr_composer_client.cpp b/services/vr/hardware_composer/impl/vr_composer_client.cpp
index c31417b..abe571a 100644
--- a/services/vr/hardware_composer/impl/vr_composer_client.cpp
+++ b/services/vr/hardware_composer/impl/vr_composer_client.cpp
@@ -161,6 +161,10 @@
client_->onHotplug(display, connected);
}
+void VrComposerClient::onRefresh(Display display) {
+ client_->onRefresh(display);
+}
+
Return<void> VrComposerClient::registerCallback(
const sp<IComposerCallback>& callback) {
return client_->registerCallback(callback);
diff --git a/services/vr/hardware_composer/impl/vr_composer_client.h b/services/vr/hardware_composer/impl/vr_composer_client.h
index f492230..dfc656a 100644
--- a/services/vr/hardware_composer/impl/vr_composer_client.h
+++ b/services/vr/hardware_composer/impl/vr_composer_client.h
@@ -35,6 +35,7 @@
virtual ~VrComposerClient();
void onHotplug(Display display, IComposerCallback::Connection connected);
+ void onRefresh(Display display);
// IComposerClient
Return<void> registerCallback(const sp<IComposerCallback>& callback) override;
diff --git a/services/vr/hardware_composer/impl/vr_hwc.cpp b/services/vr/hardware_composer/impl/vr_hwc.cpp
index 565e5d3..fd271d0 100644
--- a/services/vr/hardware_composer/impl/vr_hwc.cpp
+++ b/services/vr/hardware_composer/impl/vr_hwc.cpp
@@ -15,6 +15,7 @@
*/
#include "impl/vr_hwc.h"
+#include <cutils/properties.h>
#include <private/dvr/display_client.h>
#include <ui/Fence.h>
@@ -132,13 +133,14 @@
return lhs.info.z_order < rhs.info.z_order;
});
- int first_client_layer = -1, last_client_layer = -1;
+ const size_t no_layer = std::numeric_limits<size_t>::max();
+ size_t first_client_layer = no_layer, last_client_layer = no_layer;
for (size_t i = 0; i < layers_.size(); ++i) {
switch (layers_[i].composition_type) {
case IComposerClient::Composition::SOLID_COLOR:
case IComposerClient::Composition::CURSOR:
case IComposerClient::Composition::SIDEBAND:
- if (first_client_layer < 0)
+ if (first_client_layer == no_layer)
first_client_layer = i;
last_client_layer = i;
@@ -230,7 +232,7 @@
VrHwc::~VrHwc() {}
-bool VrHwc::hasCapability(Capability capability) const { return false; }
+bool VrHwc::hasCapability(Capability /* capability */) const { return false; }
void VrHwc::removeClient() {
std::lock_guard<std::mutex> guard(mutex_);
@@ -304,13 +306,15 @@
return Error::NONE;
}
-Error VrHwc::getClientTargetSupport(Display display, uint32_t width,
- uint32_t height, PixelFormat format,
- Dataspace dataspace) {
+Error VrHwc::getClientTargetSupport(Display /* display */, uint32_t /* width */,
+ uint32_t /* height */,
+ PixelFormat /* format */,
+ Dataspace /* dataspace */) {
return Error::NONE;
}
-Error VrHwc::getColorModes(Display display, hidl_vec<ColorMode>* outModes) {
+Error VrHwc::getColorModes(Display /* display */,
+ hidl_vec<ColorMode>* outModes) {
std::vector<ColorMode> color_modes(1, ColorMode::NATIVE);
*outModes = hidl_vec<ColorMode>(color_modes);
return Error::NONE;
@@ -336,11 +340,30 @@
*outValue = display_ptr->height();
break;
case IComposerClient::Attribute::VSYNC_PERIOD:
- *outValue = 1000 * 1000 * 1000 / 30; // 30fps
+ {
+ int error = 0;
+ auto display_client = display::DisplayClient::Create(&error);
+ if (!display_client) {
+ ALOGE("Could not connect to display service : %s(%d)",
+ strerror(error), error);
+ // Return a default value of 30 fps
+ *outValue = 1000 * 1000 * 1000 / 30;
+ } else {
+ auto metrics = display_client->GetDisplayMetrics();
+ *outValue = metrics.get().vsync_period_ns;
+ }
+ }
break;
case IComposerClient::Attribute::DPI_X:
case IComposerClient::Attribute::DPI_Y:
- *outValue = 300 * 1000; // 300dpi
+ {
+ constexpr int32_t kDefaultDPI = 300;
+ int32_t dpi = property_get_int32("ro.vr.hwc.dpi", kDefaultDPI);
+ if (dpi <= 0) {
+ dpi = kDefaultDPI;
+ }
+ *outValue = 1000 * dpi;
+ }
break;
default:
return Error::BAD_PARAMETER;
@@ -358,7 +381,7 @@
return Error::NONE;
}
-Error VrHwc::getDisplayName(Display display, hidl_string* outName) {
+Error VrHwc::getDisplayName(Display /* display */, hidl_string* outName) {
*outName = hidl_string();
return Error::NONE;
}
@@ -388,7 +411,8 @@
return Error::NONE;
}
-Error VrHwc::getHdrCapabilities(Display display, hidl_vec<Hdr>* outTypes,
+Error VrHwc::getHdrCapabilities(Display /* display */,
+ hidl_vec<Hdr>* /* outTypes */,
float* outMaxLuminance,
float* outMaxAverageLuminance,
float* outMinLuminance) {
@@ -452,8 +476,8 @@
}
Error VrHwc::setClientTarget(Display display, buffer_handle_t target,
- int32_t acquireFence, int32_t dataspace,
- const std::vector<hwc_rect_t>& damage) {
+ int32_t acquireFence, int32_t /* dataspace */,
+ const std::vector<hwc_rect_t>& /* damage */) {
base::unique_fd fence(acquireFence);
std::lock_guard<std::mutex> guard(mutex_);
auto display_ptr = FindDisplay(display);
@@ -469,7 +493,7 @@
return Error::NONE;
}
-Error VrHwc::setOutputBuffer(Display display, buffer_handle_t buffer,
+Error VrHwc::setOutputBuffer(Display display, buffer_handle_t /* buffer */,
int32_t releaseFence) {
base::unique_fd fence(releaseFence);
std::lock_guard<std::mutex> guard(mutex_);
@@ -484,8 +508,9 @@
Error VrHwc::validateDisplay(
Display display, std::vector<Layer>* outChangedLayers,
std::vector<IComposerClient::Composition>* outCompositionTypes,
- uint32_t* outDisplayRequestMask, std::vector<Layer>* outRequestedLayers,
- std::vector<uint32_t>* outRequestMasks) {
+ uint32_t* /* outDisplayRequestMask */,
+ std::vector<Layer>* /* outRequestedLayers */,
+ std::vector<uint32_t>* /* outRequestMasks */) {
std::lock_guard<std::mutex> guard(mutex_);
auto display_ptr = FindDisplay(display);
if (!display_ptr)
@@ -496,7 +521,7 @@
return Error::NONE;
}
-Error VrHwc::acceptDisplayChanges(Display display) { return Error::NONE; }
+Error VrHwc::acceptDisplayChanges(Display /* display */) { return Error::NONE; }
Error VrHwc::presentDisplay(Display display, int32_t* outPresentFence,
std::vector<Layer>* outLayers,
@@ -688,8 +713,8 @@
return Error::NONE;
}
-Error VrHwc::setLayerSidebandStream(Display display, Layer layer,
- buffer_handle_t stream) {
+Error VrHwc::setLayerSidebandStream(Display display, Layer /* layer */,
+ buffer_handle_t /* stream */) {
std::lock_guard<std::mutex> guard(mutex_);
if (!FindDisplay(display))
return Error::BAD_DISPLAY;
@@ -830,6 +855,14 @@
return Void();
}
+void VrHwc::ForceDisplaysRefresh() {
+ std::lock_guard<std::mutex> guard(mutex_);
+ if (client_ != nullptr) {
+ for (const auto& pair : displays_)
+ client_.promote()->onRefresh(pair.first);
+ }
+}
+
void VrHwc::RegisterObserver(Observer* observer) {
std::lock_guard<std::mutex> guard(mutex_);
if (observer_)
diff --git a/services/vr/hardware_composer/impl/vr_hwc.h b/services/vr/hardware_composer/impl/vr_hwc.h
index 523cda3..fce9a06 100644
--- a/services/vr/hardware_composer/impl/vr_hwc.h
+++ b/services/vr/hardware_composer/impl/vr_hwc.h
@@ -103,6 +103,7 @@
virtual ~ComposerView() {}
+ virtual void ForceDisplaysRefresh() = 0;
virtual void RegisterObserver(Observer* observer) = 0;
virtual void UnregisterObserver(Observer* observer) = 0;
};
@@ -288,6 +289,7 @@
Return<void> createClient(createClient_cb hidl_cb) override;
// ComposerView:
+ void ForceDisplaysRefresh() override;
void RegisterObserver(Observer* observer) override;
void UnregisterObserver(Observer* observer) override;
@@ -295,7 +297,6 @@
HwcDisplay* FindDisplay(Display display);
wp<VrComposerClient> client_;
- sp<IComposerCallback> callbacks_;
// Guard access to internal state from binder threads.
std::mutex mutex_;
diff --git a/services/vr/hardware_composer/tests/vr_composer_test.cpp b/services/vr/hardware_composer/tests/vr_composer_test.cpp
index d082f4b..2e70928 100644
--- a/services/vr/hardware_composer/tests/vr_composer_test.cpp
+++ b/services/vr/hardware_composer/tests/vr_composer_test.cpp
@@ -10,6 +10,24 @@
const char kVrDisplayName[] = "VrDisplay_Test";
+class TestComposerView : public ComposerView {
+ public:
+ TestComposerView() {}
+ ~TestComposerView() override = default;
+
+ size_t display_refresh_count() const { return display_refresh_count_; }
+
+ void ForceDisplaysRefresh() override { display_refresh_count_++; }
+ void RegisterObserver(Observer* observer) override {}
+ void UnregisterObserver(Observer* observer) override {}
+
+ TestComposerView(const TestComposerView&) = delete;
+ void operator=(const TestComposerView&) = delete;
+
+ private:
+ size_t display_refresh_count_ = 0;
+};
+
class TestComposerCallback : public BnVrComposerCallback {
public:
TestComposerCallback() {}
@@ -57,7 +75,7 @@
class VrComposerTest : public testing::Test {
public:
- VrComposerTest() : composer_(new VrComposer()) {}
+ VrComposerTest() : composer_(new VrComposer(&composer_view_)) {}
~VrComposerTest() override = default;
sp<IVrComposer> GetComposerProxy() const {
@@ -72,6 +90,7 @@
}
protected:
+ TestComposerView composer_view_;
sp<VrComposer> composer_;
VrComposerTest(const VrComposerTest&) = delete;
@@ -89,7 +108,9 @@
TEST_F(VrComposerTest, TestWithObserver) {
sp<IVrComposer> composer = GetComposerProxy();
sp<TestComposerCallback> callback = new TestComposerCallback();
+ ASSERT_EQ(0, composer_view_.display_refresh_count());
ASSERT_TRUE(composer->registerObserver(callback).isOk());
+ ASSERT_EQ(1, composer_view_.display_refresh_count());
ComposerView::Frame frame;
base::unique_fd fence = composer_->OnNewFrame(frame);
diff --git a/services/vr/hardware_composer/vr_composer.cpp b/services/vr/hardware_composer/vr_composer.cpp
index c45fbf4..d93f370 100644
--- a/services/vr/hardware_composer/vr_composer.cpp
+++ b/services/vr/hardware_composer/vr_composer.cpp
@@ -21,24 +21,42 @@
} // namespace
-VrComposer::VrComposer() {}
+VrComposer::VrComposer(ComposerView* composer_view)
+ : composer_view_(composer_view) {
+ composer_view_->RegisterObserver(this);
+}
-VrComposer::~VrComposer() {}
+VrComposer::~VrComposer() {
+ composer_view_->UnregisterObserver(this);
+}
binder::Status VrComposer::registerObserver(
const sp<IVrComposerCallback>& callback) {
- std::lock_guard<std::mutex> guard(mutex_);
+ {
+ std::lock_guard<std::mutex> guard(mutex_);
- if (!CheckPermission())
- return binder::Status::fromStatusT(PERMISSION_DENIED);
+ if (!CheckPermission())
+ return binder::Status::fromStatusT(PERMISSION_DENIED);
- if (callback_.get()) {
- ALOGE("Failed to register callback, already registered");
- return binder::Status::fromStatusT(ALREADY_EXISTS);
+ if (callback_.get()) {
+ ALOGE("Failed to register callback, already registered");
+ return binder::Status::fromStatusT(ALREADY_EXISTS);
+ }
+
+ callback_ = callback;
+ IInterface::asBinder(callback_)->linkToDeath(this);
}
- callback_ = callback;
- IInterface::asBinder(callback_)->linkToDeath(this);
+ // Don't take the lock to force display refresh otherwise it could end in a
+ // deadlock since HWC calls this with new frames and it has a lock of its own
+ // to serialize access to the display information.
+ composer_view_->ForceDisplaysRefresh();
+ return binder::Status::ok();
+}
+
+binder::Status VrComposer::clearObserver() {
+ std::lock_guard<std::mutex> guard(mutex_);
+ callback_ = nullptr;
return binder::Status::ok();
}
diff --git a/services/vr/hardware_composer/vr_composer.h b/services/vr/hardware_composer/vr_composer.h
index 93d1f2b..1273352 100644
--- a/services/vr/hardware_composer/vr_composer.h
+++ b/services/vr/hardware_composer/vr_composer.h
@@ -20,13 +20,15 @@
public ComposerView::Observer,
public IBinder::DeathRecipient {
public:
- VrComposer();
+ explicit VrComposer(ComposerView* composer_view);
~VrComposer() override;
// BnVrComposer:
binder::Status registerObserver(
const sp<IVrComposerCallback>& callback) override;
+ binder::Status clearObserver() override;
+
// ComposerView::Observer:
base::unique_fd OnNewFrame(const ComposerView::Frame& frame) override;
@@ -38,6 +40,8 @@
sp<IVrComposerCallback> callback_;
+ ComposerView* composer_view_; // Not owned.
+
VrComposer(const VrComposer&) = delete;
void operator=(const VrComposer&) = delete;
};
diff --git a/services/vr/hardware_composer/vr_hardware_composer_service.cpp b/services/vr/hardware_composer/vr_hardware_composer_service.cpp
index e36b0ae..7701847 100644
--- a/services/vr/hardware_composer/vr_hardware_composer_service.cpp
+++ b/services/vr/hardware_composer/vr_hardware_composer_service.cpp
@@ -36,8 +36,7 @@
"Failed to register service");
android::sp<android::dvr::VrComposer> composer =
- new android::dvr::VrComposer();
- service->RegisterObserver(composer.get());
+ new android::dvr::VrComposer(service.get());
android::sp<android::IServiceManager> sm(android::defaultServiceManager());
@@ -52,7 +51,5 @@
android::hardware::ProcessState::self()->startThreadPool();
android::hardware::IPCThreadState::self()->joinThreadPool();
- service->UnregisterObserver(composer.get());
-
return 0;
}
diff --git a/services/vr/performanced/Android.mk b/services/vr/performanced/Android.mk
index 6256e90..1470234 100644
--- a/services/vr/performanced/Android.mk
+++ b/services/vr/performanced/Android.mk
@@ -23,8 +23,10 @@
staticLibraries := \
libperformance \
libpdx_default_transport \
+ libvr_manager
sharedLibraries := \
+ libbinder \
libbase \
libcutils \
liblog \
@@ -34,6 +36,7 @@
LOCAL_SRC_FILES := $(sourceFiles)
LOCAL_CFLAGS := -DLOG_TAG=\"performanced\"
LOCAL_CFLAGS += -DTRACE=0
+LOCAL_CFLAGS += -Wall -Werror
LOCAL_STATIC_LIBRARIES := $(staticLibraries)
LOCAL_SHARED_LIBRARIES := $(sharedLibraries)
LOCAL_MODULE := performanced
diff --git a/services/vr/performanced/cpu_set.cpp b/services/vr/performanced/cpu_set.cpp
index 1a3723f..1a7264c 100644
--- a/services/vr/performanced/cpu_set.cpp
+++ b/services/vr/performanced/cpu_set.cpp
@@ -15,6 +15,9 @@
#include "task.h"
#include "unique_file.h"
+using android::pdx::ErrorStatus;
+using android::pdx::Status;
+
namespace {
constexpr int kDirectoryFlags = O_RDONLY | O_DIRECTORY | O_CLOEXEC;
@@ -176,11 +179,11 @@
task_id, task.name().c_str(), target_set.c_str(),
task.thread_group_id(), task.parent_process_id());
- const int ret = target->AttachTask(task_id);
- ALOGW_IF(ret < 0 && ret != -EINVAL,
+ auto status = target->AttachTask(task_id);
+ ALOGW_IF(!status && status.error() != EINVAL,
"CpuSetManager::MoveUnboundTasks: Failed to attach task_id=%d "
"to cpuset=%s: %s",
- task_id, target_set.c_str(), strerror(-ret));
+ task_id, target_set.c_str(), status.GetErrorMessage().c_str());
} else {
ALOGD_IF(TRACE,
"CpuSet::MoveUnboundTasks: Skipping task_id=%d name=%s cpus=%s.",
@@ -233,7 +236,7 @@
return fp;
}
-int CpuSet::AttachTask(pid_t task_id) const {
+Status<void> CpuSet::AttachTask(pid_t task_id) const {
auto file = OpenFile("tasks", O_RDWR);
if (file.get() >= 0) {
std::ostringstream stream;
@@ -241,11 +244,15 @@
std::string value = stream.str();
const bool ret = base::WriteStringToFd(value, file.get());
- return !ret ? -errno : 0;
+ if (!ret)
+ return ErrorStatus(errno);
+ else
+ return {};
} else {
+ const int error = errno;
ALOGE("CpuSet::AttachTask: Failed to open %s/tasks: %s", path_.c_str(),
- strerror(errno));
- return -errno;
+ strerror(error));
+ return ErrorStatus(error);
}
}
diff --git a/services/vr/performanced/cpu_set.h b/services/vr/performanced/cpu_set.h
index fcf280a..6879272d 100644
--- a/services/vr/performanced/cpu_set.h
+++ b/services/vr/performanced/cpu_set.h
@@ -11,6 +11,8 @@
#include <android-base/unique_fd.h>
+#include <pdx/status.h>
+
#include "unique_file.h"
namespace android {
@@ -28,7 +30,7 @@
std::string GetCpuList() const;
- int AttachTask(pid_t task_id) const;
+ pdx::Status<void> AttachTask(pid_t task_id) const;
std::vector<pid_t> GetTasks() const;
private:
diff --git a/services/vr/performanced/directory_reader.h b/services/vr/performanced/directory_reader.h
index 7d7ecc5..b9d27c3 100644
--- a/services/vr/performanced/directory_reader.h
+++ b/services/vr/performanced/directory_reader.h
@@ -19,7 +19,7 @@
directory_ = fdopendir(directory_fd.get());
error_ = errno;
if (directory_ != nullptr)
- directory_fd.release();
+ (void) directory_fd.release(); // ignore return result?
}
~DirectoryReader() {
diff --git a/services/vr/performanced/main.cpp b/services/vr/performanced/main.cpp
index ca66c71..d7dc8f6 100644
--- a/services/vr/performanced/main.cpp
+++ b/services/vr/performanced/main.cpp
@@ -9,7 +9,7 @@
#include <sys/resource.h>
#include <utils/threads.h>
-#include <pdx/default_transport/service_dispatcher.h>
+#include <pdx/service_dispatcher.h>
#include <private/android_filesystem_config.h>
#include "performance_service.h"
@@ -58,7 +58,7 @@
CHECK_ERROR(ret < 0, error, "Could not set capabilities: %s",
strerror(errno));
- dispatcher = android::pdx::default_transport::ServiceDispatcher::Create();
+ dispatcher = android::pdx::ServiceDispatcher::Create();
CHECK_ERROR(!dispatcher, error, "Failed to create service dispatcher.");
service = android::dvr::PerformanceService::Create();
diff --git a/services/vr/performanced/performance_service.cpp b/services/vr/performanced/performance_service.cpp
index 955c661..4c26671 100644
--- a/services/vr/performanced/performance_service.cpp
+++ b/services/vr/performanced/performance_service.cpp
@@ -8,24 +8,94 @@
#include <pdx/rpc/argument_encoder.h>
#include <pdx/rpc/message_buffer.h>
#include <pdx/rpc/remote_method.h>
+#include <private/android_filesystem_config.h>
#include <private/dvr/performance_rpc.h>
+#include <private/dvr/trusted_uids.h>
#include "task.h"
// This prctl is only available in Android kernels.
#define PR_SET_TIMERSLACK_PID 41
+using android::dvr::IsTrustedUid;
+using android::dvr::Task;
+using android::pdx::ErrorStatus;
using android::pdx::Message;
-using android::pdx::rpc::DispatchRemoteMethod;
+using android::pdx::Status;
using android::pdx::default_transport::Endpoint;
+using android::pdx::rpc::DispatchRemoteMethod;
namespace {
const char kCpuSetBasePath[] = "/dev/cpuset";
+const char kRootCpuSet[] = "/";
+
constexpr unsigned long kTimerSlackForegroundNs = 50000;
constexpr unsigned long kTimerSlackBackgroundNs = 40000000;
+// Expands the given parameter pack expression using an initializer list to
+// guarantee ordering and a comma expression to guarantee even void expressions
+// are valid elements of the initializer list.
+#define EXPAND_PACK(...) \
+ std::initializer_list<int> { (__VA_ARGS__, 0)... }
+
+// Returns true if the sender's euid matches any of the uids in |UIDs|.
+template <uid_t... UIDs>
+struct UserId {
+ static bool Check(const Message& sender, const Task&) {
+ const uid_t uid = sender.GetEffectiveUserId();
+ bool allow = false;
+ EXPAND_PACK(allow |= (uid == UIDs));
+ return allow;
+ }
+};
+
+// Returns true if the sender's egid matches any of the gids in |GIDs|.
+template <gid_t... GIDs>
+struct GroupId {
+ static bool Check(const Message& sender, const Task&) {
+ const gid_t gid = sender.GetEffectiveGroupId();
+ bool allow = false;
+ EXPAND_PACK(allow |= (gid == GIDs));
+ return allow;
+ }
+};
+
+// Returns true if the sender's euid is trusted according to VR manager service.
+struct Trusted {
+ static bool Check(const Message& sender, const Task&) {
+ return IsTrustedUid(sender.GetEffectiveUserId());
+ }
+};
+
+// Returns returns true if the task belongs to the sending process.
+struct SameProcess {
+ static bool Check(const Message& sender, const Task& task) {
+ return sender.GetProcessId() == task.thread_group_id();
+ }
+};
+
+// Returns true if any of the checks in |Allows| pass, false otherwise.
+template <typename... Allows>
+struct CheckOr {
+ static bool Check(const Message& sender, const Task& task) {
+ bool allow = false;
+ EXPAND_PACK(allow |= Allows::Check(sender, task));
+ return allow;
+ }
+};
+
+// Returns true if all of the checks in |Allows| pass, false otherwise.
+template <typename... Allows>
+struct CheckAnd {
+ static bool Check(const Message& sender, const Task& task) {
+ bool allow = true;
+ EXPAND_PACK(allow &= Allows::Check(sender, task));
+ return allow;
+ }
+};
+
} // anonymous namespace
namespace android {
@@ -48,43 +118,81 @@
const int fifo_low = sched_fifo_min_priority_;
const int fifo_medium = sched_fifo_min_priority_ + fifo_range / 5;
- // TODO(eieio): Make this configurable on the command line.
+ // TODO(eieio): Make this configurable on the command line or config file.
cpuset_.MoveUnboundTasks("/kernel");
+ // TODO(eieio): Replace this witha device-specific config file. This is just a
+ // hack for now to put some form of permission logic in place while a longer
+ // term solution is developed.
+ using AllowRootSystem =
+ CheckAnd<SameProcess,
+ CheckOr<UserId<AID_ROOT, AID_SYSTEM>, GroupId<AID_SYSTEM>>>;
+ using AllowRootSystemGraphics =
+ CheckAnd<SameProcess, CheckOr<UserId<AID_ROOT, AID_SYSTEM, AID_GRAPHICS>,
+ GroupId<AID_SYSTEM, AID_GRAPHICS>>>;
+ using AllowRootSystemAudio =
+ CheckAnd<SameProcess, CheckOr<UserId<AID_ROOT, AID_SYSTEM, AID_AUDIO>,
+ GroupId<AID_SYSTEM, AID_AUDIO>>>;
+ using AllowRootSystemTrusted =
+ CheckOr<Trusted, UserId<AID_ROOT, AID_SYSTEM>, GroupId<AID_SYSTEM>>;
+
+ partition_permission_check_ = AllowRootSystemTrusted::Check;
+
// Setup the scheduler classes.
- scheduler_classes_ = {
+ // TODO(eieio): Replace this with a device-specific config file.
+ scheduler_policies_ = {
{"audio:low",
{.timer_slack = kTimerSlackForegroundNs,
.scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK,
- .priority = fifo_medium}},
+ .priority = fifo_medium,
+ .permission_check = AllowRootSystemAudio::Check}},
{"audio:high",
{.timer_slack = kTimerSlackForegroundNs,
.scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK,
- .priority = fifo_medium + 3}},
+ .priority = fifo_medium + 3,
+ .permission_check = AllowRootSystemAudio::Check}},
{"graphics",
{.timer_slack = kTimerSlackForegroundNs,
.scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK,
- .priority = fifo_medium}},
+ .priority = fifo_medium,
+ .permission_check = AllowRootSystemGraphics::Check}},
{"graphics:low",
{.timer_slack = kTimerSlackForegroundNs,
.scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK,
- .priority = fifo_medium}},
+ .priority = fifo_medium,
+ .permission_check = AllowRootSystemGraphics::Check}},
{"graphics:high",
{.timer_slack = kTimerSlackForegroundNs,
.scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK,
- .priority = fifo_medium + 2}},
+ .priority = fifo_medium + 2,
+ .permission_check = AllowRootSystemGraphics::Check}},
{"sensors",
{.timer_slack = kTimerSlackForegroundNs,
.scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK,
- .priority = fifo_low}},
+ .priority = fifo_low,
+ .permission_check = AllowRootSystem::Check}},
{"sensors:low",
{.timer_slack = kTimerSlackForegroundNs,
.scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK,
- .priority = fifo_low}},
+ .priority = fifo_low,
+ .permission_check = AllowRootSystem::Check}},
{"sensors:high",
{.timer_slack = kTimerSlackForegroundNs,
.scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK,
- .priority = fifo_low + 1}},
+ .priority = fifo_low + 1,
+ .permission_check = AllowRootSystem::Check}},
+ {"vr:system:arp",
+ {.timer_slack = kTimerSlackForegroundNs,
+ .scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK,
+ .priority = fifo_medium + 2,
+ .permission_check = AllowRootSystemTrusted::Check,
+ "/system/performance"}},
+ {"vr:app:render",
+ {.timer_slack = kTimerSlackForegroundNs,
+ .scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK,
+ .priority = fifo_medium + 1,
+ .permission_check = AllowRootSystemTrusted::Check,
+ "/application/performance"}},
{"normal",
{.timer_slack = kTimerSlackForegroundNs,
.scheduler_policy = SCHED_NORMAL,
@@ -113,67 +221,160 @@
return cpuset_.DumpState();
}
-int PerformanceService::OnSetCpuPartition(Message& message, pid_t task_id,
- const std::string& partition) {
+Status<void> PerformanceService::OnSetSchedulerPolicy(
+ Message& message, pid_t task_id, const std::string& scheduler_policy) {
+ ALOGI(
+ "PerformanceService::OnSetSchedulerPolicy: task_id=%d "
+ "scheduler_policy=%s",
+ task_id, scheduler_policy.c_str());
+
+ Task task(task_id);
+ if (!task) {
+ ALOGE(
+ "PerformanceService::OnSetSchedulerPolicy: Unable to access /proc/%d "
+ "to gather task information.",
+ task_id);
+ return ErrorStatus(EINVAL);
+ }
+
+ auto search = scheduler_policies_.find(scheduler_policy);
+ if (search != scheduler_policies_.end()) {
+ auto config = search->second;
+
+ // Make sure the sending process is allowed to make the requested change to
+ // this task.
+ if (!config.IsAllowed(message, task))
+ return ErrorStatus(EINVAL);
+
+ // Get the thread group's cpu set. Policies that do not specify a cpuset
+ // should default to this cpuset.
+ std::string thread_group_cpuset;
+ Task thread_group{task.thread_group_id()};
+ if (thread_group) {
+ thread_group_cpuset = thread_group.GetCpuSetPath();
+ } else {
+ ALOGE(
+ "PerformanceService::OnSetSchedulerPolicy: Failed to get thread "
+ "group tgid=%d for task_id=%d",
+ task.thread_group_id(), task_id);
+ thread_group_cpuset = kRootCpuSet;
+ }
+
+ std::string target_cpuset;
+ if (config.cpuset.empty()) {
+ target_cpuset = thread_group_cpuset;
+ } else {
+ target_cpuset = config.cpuset;
+ }
+ ALOGI("PerformanceService::OnSetSchedulerPolicy: Using cpuset=%s",
+ target_cpuset.c_str());
+
+ auto target_set = cpuset_.Lookup(target_cpuset);
+ if (target_set) {
+ auto attach_status = target_set->AttachTask(task_id);
+ ALOGW_IF(!attach_status,
+ "PerformanceService::OnSetSchedulerPolicy: Failed to attach "
+ "task=%d to cpuset=%s: %s",
+ task_id, target_cpuset.c_str(),
+ attach_status.GetErrorMessage().c_str());
+ } else {
+ ALOGW(
+ "PerformanceService::OnSetSchedulerPolicy: Failed to lookup "
+ "cpuset=%s",
+ target_cpuset.c_str());
+ }
+
+ struct sched_param param;
+ param.sched_priority = config.priority;
+
+ sched_setscheduler(task_id, config.scheduler_policy, ¶m);
+ prctl(PR_SET_TIMERSLACK_PID, config.timer_slack, task_id);
+ return {};
+ } else {
+ ALOGE(
+ "PerformanceService::OnSetSchedulerPolicy: Invalid scheduler_policy=%s "
+ "requested by task=%d.",
+ scheduler_policy.c_str(), task_id);
+ return ErrorStatus(EINVAL);
+ }
+}
+
+Status<void> PerformanceService::OnSetCpuPartition(
+ Message& message, pid_t task_id, const std::string& partition) {
Task task(task_id);
if (!task || task.thread_group_id() != message.GetProcessId())
- return -EINVAL;
+ return ErrorStatus(EINVAL);
+
+ // Temporary permission check.
+ // TODO(eieio): Replace this with a configuration file.
+ if (partition_permission_check_ &&
+ !partition_permission_check_(message, task)) {
+ return ErrorStatus(EINVAL);
+ }
auto target_set = cpuset_.Lookup(partition);
if (!target_set)
- return -ENOENT;
+ return ErrorStatus(ENOENT);
- const auto attach_error = target_set->AttachTask(task_id);
- if (attach_error)
- return attach_error;
+ auto attach_status = target_set->AttachTask(task_id);
+ if (!attach_status)
+ return attach_status;
- return 0;
+ return {};
}
-int PerformanceService::OnSetSchedulerClass(
+Status<void> PerformanceService::OnSetSchedulerClass(
Message& message, pid_t task_id, const std::string& scheduler_class) {
- // Make sure the task id is valid and belongs to the sending process.
Task task(task_id);
- if (!task || task.thread_group_id() != message.GetProcessId())
- return -EINVAL;
+ if (!task)
+ return ErrorStatus(EINVAL);
- struct sched_param param;
-
- // TODO(eieio): Apply rules based on the requesting process. Applications are
- // only allowed one audio thread that runs at SCHED_FIFO. System services can
- // have more than one.
- auto search = scheduler_classes_.find(scheduler_class);
- if (search != scheduler_classes_.end()) {
+ auto search = scheduler_policies_.find(scheduler_class);
+ if (search != scheduler_policies_.end()) {
auto config = search->second;
+
+ // Make sure the sending process is allowed to make the requested change to
+ // this task.
+ if (!config.IsAllowed(message, task))
+ return ErrorStatus(EINVAL);
+
+ struct sched_param param;
param.sched_priority = config.priority;
+
sched_setscheduler(task_id, config.scheduler_policy, ¶m);
prctl(PR_SET_TIMERSLACK_PID, config.timer_slack, task_id);
ALOGI("PerformanceService::OnSetSchedulerClass: Set task=%d to class=%s.",
task_id, scheduler_class.c_str());
- return 0;
+ return {};
} else {
ALOGE(
"PerformanceService::OnSetSchedulerClass: Invalid class=%s requested "
"by task=%d.",
scheduler_class.c_str(), task_id);
- return -EINVAL;
+ return ErrorStatus(EINVAL);
}
}
-std::string PerformanceService::OnGetCpuPartition(Message& message,
- pid_t task_id) {
+Status<std::string> PerformanceService::OnGetCpuPartition(Message& message,
+ pid_t task_id) {
// Make sure the task id is valid and belongs to the sending process.
Task task(task_id);
if (!task || task.thread_group_id() != message.GetProcessId())
- REPLY_ERROR_RETURN(message, EINVAL, "");
+ return ErrorStatus(EINVAL);
return task.GetCpuSetPath();
}
-pdx::Status<void> PerformanceService::HandleMessage(Message& message) {
+Status<void> PerformanceService::HandleMessage(Message& message) {
+ ALOGD_IF(TRACE, "PerformanceService::HandleMessage: op=%d", message.GetOp());
switch (message.GetOp()) {
+ case PerformanceRPC::SetSchedulerPolicy::Opcode:
+ DispatchRemoteMethod<PerformanceRPC::SetSchedulerPolicy>(
+ *this, &PerformanceService::OnSetSchedulerPolicy, message);
+ return {};
+
case PerformanceRPC::SetCpuPartition::Opcode:
- DispatchRemoteMethod<PerformanceRPC::SetSchedulerClass>(
+ DispatchRemoteMethod<PerformanceRPC::SetCpuPartition>(
*this, &PerformanceService::OnSetCpuPartition, message);
return {};
diff --git a/services/vr/performanced/performance_service.h b/services/vr/performanced/performance_service.h
index 34abba7..6b519ab 100644
--- a/services/vr/performanced/performance_service.h
+++ b/services/vr/performanced/performance_service.h
@@ -1,12 +1,14 @@
#ifndef ANDROID_DVR_PERFORMANCED_PERFORMANCE_SERVICE_H_
#define ANDROID_DVR_PERFORMANCED_PERFORMANCE_SERVICE_H_
+#include <functional>
#include <string>
#include <unordered_map>
#include <pdx/service.h>
#include "cpu_set.h"
+#include "task.h"
namespace android {
namespace dvr {
@@ -27,25 +29,46 @@
PerformanceService();
- int OnSetCpuPartition(pdx::Message& message, pid_t task_id,
- const std::string& partition);
- int OnSetSchedulerClass(pdx::Message& message, pid_t task_id,
- const std::string& scheduler_class);
- std::string OnGetCpuPartition(pdx::Message& message, pid_t task_id);
+ pdx::Status<void> OnSetSchedulerPolicy(pdx::Message& message, pid_t task_id,
+ const std::string& scheduler_class);
+
+ pdx::Status<void> OnSetCpuPartition(pdx::Message& message, pid_t task_id,
+ const std::string& partition);
+ pdx::Status<void> OnSetSchedulerClass(pdx::Message& message, pid_t task_id,
+ const std::string& scheduler_class);
+ pdx::Status<std::string> OnGetCpuPartition(pdx::Message& message,
+ pid_t task_id);
CpuSetManager cpuset_;
int sched_fifo_min_priority_;
int sched_fifo_max_priority_;
- // Scheduler class config type.
- struct SchedulerClassConfig {
+ struct SchedulerPolicyConfig {
unsigned long timer_slack;
int scheduler_policy;
int priority;
+ std::function<bool(const pdx::Message& message, const Task& task)>
+ permission_check;
+ std::string cpuset;
+
+ // Check the permisison of the given task to use this scheduler class. If a
+ // permission check function is not set then operations are only allowed on
+ // tasks in the sender's process.
+ bool IsAllowed(const pdx::Message& sender, const Task& task) const {
+ if (permission_check)
+ return permission_check(sender, task);
+ else if (!task || task.thread_group_id() != sender.GetProcessId())
+ return false;
+ else
+ return true;
+ }
};
- std::unordered_map<std::string, SchedulerClassConfig> scheduler_classes_;
+ std::unordered_map<std::string, SchedulerPolicyConfig> scheduler_policies_;
+
+ std::function<bool(const pdx::Message& message, const Task& task)>
+ partition_permission_check_;
PerformanceService(const PerformanceService&) = delete;
void operator=(const PerformanceService&) = delete;
diff --git a/services/vr/performanced/performance_service_tests.cpp b/services/vr/performanced/performance_service_tests.cpp
index b526082..4065785 100644
--- a/services/vr/performanced/performance_service_tests.cpp
+++ b/services/vr/performanced/performance_service_tests.cpp
@@ -1,14 +1,65 @@
#include <errno.h>
#include <sched.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <unistd.h>
#include <condition_variable>
+#include <cstdlib>
+#include <iostream>
#include <mutex>
+#include <sstream>
#include <thread>
+#include <utility>
+#include <android-base/unique_fd.h>
#include <dvr/performance_client_api.h>
#include <gtest/gtest.h>
+#include <private/android_filesystem_config.h>
-TEST(DISABLED_PerformanceTest, SetCpuPartition) {
+#include "stdio_filebuf.h"
+#include "string_trim.h"
+#include "unique_file.h"
+
+using android::dvr::Trim;
+using android::dvr::UniqueFile;
+using android::dvr::stdio_filebuf;
+
+namespace {
+
+const char kTrustedUidEnvironmentVariable[] = "GTEST_TRUSTED_UID";
+
+const char kProcBase[] = "/proc";
+
+std::pair<UniqueFile, int> OpenTaskFile(pid_t task_id,
+ const std::string& name) {
+ std::ostringstream stream;
+ stream << kProcBase << "/" << task_id << "/" << name;
+
+ UniqueFile file{fopen(stream.str().c_str(), "r")};
+ const int error = file ? 0 : errno;
+ return {std::move(file), error};
+}
+
+std::string GetTaskCpuSet(pid_t task_id) {
+ int error;
+ UniqueFile file;
+
+ std::tie(file, error) = OpenTaskFile(task_id, "cpuset");
+ if (!file)
+ return std::string("errno:") + strerror(error);
+
+ stdio_filebuf<char> filebuf(file.get());
+ std::istream file_stream(&filebuf);
+
+ std::string line;
+ std::getline(file_stream, line);
+ return Trim(line);
+}
+
+} // anonymous namespace
+
+TEST(PerformanceTest, SetCpuPartition) {
int error;
// Test setting the the partition for the current task.
@@ -49,13 +100,6 @@
}
thread.join();
- // Test setting the partition for a task that isn't valid using
- // the task id of the thread that we just joined. Technically the
- // id could wrap around by the time we get here, but this is
- // extremely unlikely.
- error = dvrSetCpuPartition(task_id, "/application");
- EXPECT_EQ(-EINVAL, error);
-
// Test setting the partition for a task that doesn't belong to us.
error = dvrSetCpuPartition(1, "/application");
EXPECT_EQ(-EINVAL, error);
@@ -63,6 +107,10 @@
// Test setting the partition to one that doesn't exist.
error = dvrSetCpuPartition(0, "/foobar");
EXPECT_EQ(-ENOENT, error);
+
+ // Set the test back to the root partition.
+ error = dvrSetCpuPartition(0, "/");
+ EXPECT_EQ(0, error);
}
TEST(PerformanceTest, SetSchedulerClass) {
@@ -86,6 +134,69 @@
EXPECT_EQ(-EINVAL, error);
}
+TEST(PerformanceTest, SetSchedulerPolicy) {
+ int error;
+
+ error = dvrSetSchedulerPolicy(0, "background");
+ EXPECT_EQ(0, error);
+ EXPECT_EQ(SCHED_BATCH, sched_getscheduler(0));
+
+ error = dvrSetSchedulerPolicy(0, "audio:low");
+ EXPECT_EQ(0, error);
+ EXPECT_EQ(SCHED_FIFO | SCHED_RESET_ON_FORK, sched_getscheduler(0));
+
+ error = dvrSetSchedulerPolicy(0, "normal");
+ EXPECT_EQ(0, error);
+ EXPECT_EQ(SCHED_NORMAL, sched_getscheduler(0));
+
+ error = dvrSetSchedulerPolicy(0, "foobar");
+ EXPECT_EQ(-EINVAL, error);
+
+ // Set the test back to the root partition.
+ error = dvrSetCpuPartition(0, "/");
+ EXPECT_EQ(0, error);
+
+ const std::string original_cpuset = GetTaskCpuSet(gettid());
+ EXPECT_EQ("/", original_cpuset);
+
+ error = dvrSetSchedulerPolicy(0, "vr:system:arp");
+ EXPECT_EQ(0, error);
+ EXPECT_EQ(SCHED_FIFO | SCHED_RESET_ON_FORK, sched_getscheduler(0));
+
+ const std::string new_cpuset = GetTaskCpuSet(gettid());
+ EXPECT_NE(original_cpuset, new_cpuset);
+
+ // The cpuset for the thread group is now new_cpuset. Scheduler profiles that
+ // do not specify a cpuset should not change the cpuset of a thread, except to
+ // restore it to the thread group cpuset.
+ std::string thread_original_cpuset;
+ std::string thread_new_cpuset;
+ std::string thread_final_cpuset;
+
+ std::thread thread{
+ [&thread_original_cpuset, &thread_new_cpuset, &thread_final_cpuset]() {
+ thread_original_cpuset = GetTaskCpuSet(gettid());
+
+ int error = dvrSetSchedulerPolicy(0, "vr:app:render");
+ EXPECT_EQ(0, error);
+
+ thread_new_cpuset = GetTaskCpuSet(gettid());
+
+ error = dvrSetSchedulerPolicy(0, "normal");
+ EXPECT_EQ(0, error);
+
+ thread_final_cpuset = GetTaskCpuSet(gettid());
+ }};
+ thread.join();
+
+ EXPECT_EQ(new_cpuset, thread_original_cpuset);
+ EXPECT_NE(new_cpuset, thread_new_cpuset);
+ EXPECT_EQ(new_cpuset, thread_final_cpuset);
+
+ error = dvrSetCpuPartition(0, original_cpuset.c_str());
+ EXPECT_EQ(0, error);
+}
+
TEST(PerformanceTest, SchedulerClassResetOnFork) {
int error;
@@ -135,3 +246,284 @@
error = dvrGetCpuPartition(0, nullptr, sizeof(partition));
EXPECT_EQ(-EINVAL, error);
}
+
+TEST(PerformanceTest, Permissions) {
+ int error;
+
+ const int original_uid = getuid();
+ const int original_gid = getgid();
+ int trusted_uid = -1;
+
+ // See if the environment variable GTEST_TRUSTED_UID is set. If it is enable
+ // testing the ActivityManager trusted uid permission checks using that uid.
+ const char* trusted_uid_env = std::getenv(kTrustedUidEnvironmentVariable);
+ if (trusted_uid_env)
+ trusted_uid = std::atoi(trusted_uid_env);
+
+ ASSERT_EQ(AID_ROOT, original_uid)
+ << "This test must run as root to function correctly!";
+
+ // Test unprivileged policies on a task that does not belong to this process.
+ // Use the init process (task_id=1) as the target.
+ error = dvrSetSchedulerPolicy(1, "batch");
+ EXPECT_EQ(-EINVAL, error);
+ error = dvrSetSchedulerPolicy(1, "background");
+ EXPECT_EQ(-EINVAL, error);
+ error = dvrSetSchedulerPolicy(1, "foreground");
+ EXPECT_EQ(-EINVAL, error);
+ error = dvrSetSchedulerPolicy(1, "normal");
+ EXPECT_EQ(-EINVAL, error);
+
+ // Switch the uid/gid to an id that should not have permission to access any
+ // privileged actions.
+ ASSERT_EQ(0, setresgid(AID_NOBODY, AID_NOBODY, -1))
+ << "Failed to set gid: " << strerror(errno);
+ ASSERT_EQ(0, setresuid(AID_NOBODY, AID_NOBODY, -1))
+ << "Failed to set uid: " << strerror(errno);
+
+ // Unprivileged policies.
+ error = dvrSetSchedulerPolicy(0, "batch");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "background");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "foreground");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "normal");
+ EXPECT_EQ(0, error);
+
+ // Privileged policies.
+ error = dvrSetSchedulerPolicy(0, "audio:low");
+ EXPECT_EQ(-EINVAL, error);
+ error = dvrSetSchedulerPolicy(0, "audio:high");
+ EXPECT_EQ(-EINVAL, error);
+ error = dvrSetSchedulerPolicy(0, "graphics");
+ EXPECT_EQ(-EINVAL, error);
+ error = dvrSetSchedulerPolicy(0, "graphics:low");
+ EXPECT_EQ(-EINVAL, error);
+ error = dvrSetSchedulerPolicy(0, "graphics:high");
+ EXPECT_EQ(-EINVAL, error);
+ error = dvrSetSchedulerPolicy(0, "sensors");
+ EXPECT_EQ(-EINVAL, error);
+ error = dvrSetSchedulerPolicy(0, "sensors:low");
+ EXPECT_EQ(-EINVAL, error);
+ error = dvrSetSchedulerPolicy(0, "sensors:high");
+ EXPECT_EQ(-EINVAL, error);
+ error = dvrSetSchedulerPolicy(0, "vr:system:arp");
+ EXPECT_EQ(-EINVAL, error);
+ error = dvrSetSchedulerPolicy(0, "vr:app:render");
+ EXPECT_EQ(-EINVAL, error);
+
+ // uid=AID_SYSTEM / gid=AID_NOBODY
+ ASSERT_EQ(0, setresuid(original_uid, original_uid, -1))
+ << "Failed to restore uid: " << strerror(errno);
+ ASSERT_EQ(0, setresuid(AID_SYSTEM, AID_SYSTEM, -1))
+ << "Failed to set uid: " << strerror(errno);
+
+ // Unprivileged policies.
+ error = dvrSetSchedulerPolicy(0, "batch");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "background");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "foreground");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "normal");
+ EXPECT_EQ(0, error);
+
+ // Privileged policies.
+ error = dvrSetSchedulerPolicy(0, "audio:low");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "audio:high");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "graphics");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "graphics:low");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "graphics:high");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "sensors");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "sensors:low");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "sensors:high");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "vr:system:arp");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "vr:app:render");
+ EXPECT_EQ(0, error);
+
+ // uid=AID_NOBODY / gid=AID_SYSTEM
+ ASSERT_EQ(0, setresuid(original_uid, original_uid, -1))
+ << "Failed to restore uid: " << strerror(errno);
+ ASSERT_EQ(0, setresgid(original_gid, original_gid, -1))
+ << "Failed to restore gid: " << strerror(errno);
+ ASSERT_EQ(0, setresgid(AID_SYSTEM, AID_SYSTEM, -1))
+ << "Failed to set gid: " << strerror(errno);
+ ASSERT_EQ(0, setresuid(AID_SYSTEM, AID_NOBODY, -1))
+ << "Failed to set uid: " << strerror(errno);
+
+ // Unprivileged policies.
+ error = dvrSetSchedulerPolicy(0, "batch");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "background");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "foreground");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "normal");
+ EXPECT_EQ(0, error);
+
+ // Privileged policies.
+ error = dvrSetSchedulerPolicy(0, "audio:low");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "audio:high");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "graphics");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "graphics:low");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "graphics:high");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "sensors");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "sensors:low");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "sensors:high");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "vr:system:arp");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "vr:app:render");
+ EXPECT_EQ(0, error);
+
+ // uid=AID_GRAPHICS / gid=AID_NOBODY
+ ASSERT_EQ(0, setresuid(original_uid, original_uid, -1))
+ << "Failed to restore uid: " << strerror(errno);
+ ASSERT_EQ(0, setresgid(original_gid, original_gid, -1))
+ << "Failed to restore gid: " << strerror(errno);
+ ASSERT_EQ(0, setresgid(AID_NOBODY, AID_NOBODY, -1))
+ << "Failed to set gid: " << strerror(errno);
+ ASSERT_EQ(0, setresuid(AID_GRAPHICS, AID_GRAPHICS, -1))
+ << "Failed to set uid: " << strerror(errno);
+
+ // Unprivileged policies.
+ error = dvrSetSchedulerPolicy(0, "batch");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "background");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "foreground");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "normal");
+ EXPECT_EQ(0, error);
+
+ // Privileged policies.
+ error = dvrSetSchedulerPolicy(0, "audio:low");
+ EXPECT_EQ(-EINVAL, error);
+ error = dvrSetSchedulerPolicy(0, "audio:high");
+ EXPECT_EQ(-EINVAL, error);
+ error = dvrSetSchedulerPolicy(0, "graphics");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "graphics:low");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "graphics:high");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "sensors");
+ EXPECT_EQ(-EINVAL, error);
+ error = dvrSetSchedulerPolicy(0, "sensors:low");
+ EXPECT_EQ(-EINVAL, error);
+ error = dvrSetSchedulerPolicy(0, "sensors:high");
+ EXPECT_EQ(-EINVAL, error);
+ error = dvrSetSchedulerPolicy(0, "vr:system:arp");
+ EXPECT_EQ(-EINVAL, error);
+ error = dvrSetSchedulerPolicy(0, "vr:app:render");
+ EXPECT_EQ(-EINVAL, error);
+
+ // uid=AID_NOBODY / gid=AID_GRAPHICS
+ ASSERT_EQ(0, setresuid(original_uid, original_uid, -1))
+ << "Failed to restore uid: " << strerror(errno);
+ ASSERT_EQ(0, setresgid(original_gid, original_gid, -1))
+ << "Failed to restore gid: " << strerror(errno);
+ ASSERT_EQ(0, setresgid(AID_GRAPHICS, AID_GRAPHICS, -1))
+ << "Failed to set gid: " << strerror(errno);
+ ASSERT_EQ(0, setresuid(AID_NOBODY, AID_NOBODY, -1))
+ << "Failed to set uid: " << strerror(errno);
+
+ // Unprivileged policies.
+ error = dvrSetSchedulerPolicy(0, "batch");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "background");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "foreground");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "normal");
+ EXPECT_EQ(0, error);
+
+ // Privileged policies.
+ error = dvrSetSchedulerPolicy(0, "audio:low");
+ EXPECT_EQ(-EINVAL, error);
+ error = dvrSetSchedulerPolicy(0, "audio:high");
+ EXPECT_EQ(-EINVAL, error);
+ error = dvrSetSchedulerPolicy(0, "graphics");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "graphics:low");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "graphics:high");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "sensors");
+ EXPECT_EQ(-EINVAL, error);
+ error = dvrSetSchedulerPolicy(0, "sensors:low");
+ EXPECT_EQ(-EINVAL, error);
+ error = dvrSetSchedulerPolicy(0, "sensors:high");
+ EXPECT_EQ(-EINVAL, error);
+ error = dvrSetSchedulerPolicy(0, "vr:system:arp");
+ EXPECT_EQ(-EINVAL, error);
+ error = dvrSetSchedulerPolicy(0, "vr:app:render");
+ EXPECT_EQ(-EINVAL, error);
+
+ if (trusted_uid != -1) {
+ // uid=<trusted uid> / gid=AID_NOBODY
+ ASSERT_EQ(0, setresuid(original_uid, original_uid, -1))
+ << "Failed to restore uid: " << strerror(errno);
+ ASSERT_EQ(0, setresgid(original_gid, original_gid, -1))
+ << "Failed to restore gid: " << strerror(errno);
+ ASSERT_EQ(0, setresgid(AID_NOBODY, AID_NOBODY, -1))
+ << "Failed to set gid: " << strerror(errno);
+ ASSERT_EQ(0, setresuid(trusted_uid, trusted_uid, -1))
+ << "Failed to set uid: " << strerror(errno);
+
+ // Unprivileged policies.
+ error = dvrSetSchedulerPolicy(0, "batch");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "background");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "foreground");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "normal");
+ EXPECT_EQ(0, error);
+
+ // Privileged policies.
+ error = dvrSetSchedulerPolicy(0, "audio:low");
+ EXPECT_EQ(-EINVAL, error);
+ error = dvrSetSchedulerPolicy(0, "audio:high");
+ EXPECT_EQ(-EINVAL, error);
+ error = dvrSetSchedulerPolicy(0, "graphics");
+ EXPECT_EQ(-EINVAL, error);
+ error = dvrSetSchedulerPolicy(0, "graphics:low");
+ EXPECT_EQ(-EINVAL, error);
+ error = dvrSetSchedulerPolicy(0, "graphics:high");
+ EXPECT_EQ(-EINVAL, error);
+ error = dvrSetSchedulerPolicy(0, "sensors");
+ EXPECT_EQ(-EINVAL, error);
+ error = dvrSetSchedulerPolicy(0, "sensors:low");
+ EXPECT_EQ(-EINVAL, error);
+ error = dvrSetSchedulerPolicy(0, "sensors:high");
+ EXPECT_EQ(-EINVAL, error);
+ error = dvrSetSchedulerPolicy(0, "vr:system:arp");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "vr:app:render");
+ EXPECT_EQ(0, error);
+ }
+
+ // Restore original effective uid/gid.
+ ASSERT_EQ(0, setresgid(original_gid, original_gid, -1))
+ << "Failed to restore gid: " << strerror(errno);
+ ASSERT_EQ(0, setresuid(original_uid, original_uid, -1))
+ << "Failed to restore uid: " << strerror(errno);
+}
diff --git a/services/vr/performanced/task.cpp b/services/vr/performanced/task.cpp
index 1175a7b..c2f078e 100644
--- a/services/vr/performanced/task.cpp
+++ b/services/vr/performanced/task.cpp
@@ -48,15 +48,18 @@
thread_count_(0),
cpus_allowed_mask_(0) {
task_fd_ = OpenTaskDirectory(task_id_);
- ALOGE_IF(task_fd_.get() < 0,
+ const int error = errno;
+ ALOGE_IF(task_fd_.get() < 0 && error != EACCES,
"Task::Task: Failed to open task directory for task_id=%d: %s",
- task_id, strerror(errno));
+ task_id, strerror(error));
- ReadStatusFields();
-
- ALOGD_IF(TRACE, "Task::Task: task_id=%d name=%s tgid=%d ppid=%d cpu_mask=%x",
- task_id_, name_.c_str(), thread_group_id_, parent_process_id_,
- cpus_allowed_mask_);
+ if (IsValid()) {
+ ReadStatusFields();
+ ALOGD_IF(TRACE,
+ "Task::Task: task_id=%d name=%s tgid=%d ppid=%d cpu_mask=%x",
+ task_id_, name_.c_str(), thread_group_id_, parent_process_id_,
+ cpus_allowed_mask_);
+ }
}
base::unique_fd Task::OpenTaskFile(const std::string& name) const {
diff --git a/services/vr/virtual_touchpad/Android.bp b/services/vr/virtual_touchpad/Android.bp
index b9aa8fe..7196b2b 100644
--- a/services/vr/virtual_touchpad/Android.bp
+++ b/services/vr/virtual_touchpad/Android.bp
@@ -23,7 +23,11 @@
shared_libs: shared_libs,
header_libs: header_libraries,
cppflags: ["-std=c++11"],
- cflags: ["-DLOG_TAG=\"VrVirtualTouchpad\""],
+ cflags: [
+ "-DLOG_TAG=\"VrVirtualTouchpad\"",
+ "-Wall",
+ "-Werror",
+ ],
name: "libvirtualtouchpad",
tags: ["optional"],
}
@@ -33,9 +37,6 @@
test_static_libs = [
"libcutils",
"libvirtualtouchpad",
-]
-
-test_shared_libs = [
"libbase",
"liblog",
"libutils",
@@ -46,8 +47,11 @@
cc_test {
srcs: test_src_files,
static_libs: test_static_libs,
- shared_libs: test_shared_libs,
header_libs: header_libraries,
+ cflags = [
+ "-Wall",
+ "-Werror",
+ ],
cppflags = [
"-std=c++11",
],
@@ -87,6 +91,8 @@
cppflags: ["-std=c++11"],
cflags: [
"-DLOG_TAG=\"VrVirtualTouchpad\"",
+ "-Wall",
+ "-Werror",
],
host_ldlibs: ["-llog"],
name: "virtual_touchpad",
@@ -116,7 +122,11 @@
shared_libs: client_shared_libs,
header_libs: header_libraries,
cppflags: ["-std=c++11"],
- cflags: ["-DLOG_TAG=\"VirtualTouchpadClient\""],
+ cflags: [
+ "-DLOG_TAG=\"VirtualTouchpadClient\"",
+ "-Wall",
+ "-Werror",
+ ],
host_ldlibs: ["-llog"],
name: "libvirtualtouchpadclient",
tags: ["optional"],
diff --git a/services/vr/virtual_touchpad/DvrVirtualTouchpadClient.cpp b/services/vr/virtual_touchpad/DvrVirtualTouchpadClient.cpp
index eb152ed..3ab77a7 100644
--- a/services/vr/virtual_touchpad/DvrVirtualTouchpadClient.cpp
+++ b/services/vr/virtual_touchpad/DvrVirtualTouchpadClient.cpp
@@ -40,6 +40,11 @@
return FromC(client)->ButtonState(touchpad, buttons);
}
+int dvrVirtualTouchpadScroll(DvrVirtualTouchpad* client, int touchpad, float x,
+ float y) {
+ return FromC(client)->Scroll(touchpad, x, y);
+}
+
#ifdef __cplusplus
} // extern "C"
#endif
diff --git a/services/vr/virtual_touchpad/EvdevInjector.cpp b/services/vr/virtual_touchpad/EvdevInjector.cpp
index a4ccdd0..7fad379 100644
--- a/services/vr/virtual_touchpad/EvdevInjector.cpp
+++ b/services/vr/virtual_touchpad/EvdevInjector.cpp
@@ -168,6 +168,25 @@
return ConfigureAbs(ABS_MT_SLOT, 0, slots, 0, 0);
}
+int EvdevInjector::ConfigureRel(uint16_t rel_type) {
+ ALOGV("ConfigureRel 0x%" PRIX16 "", rel_type);
+ if (rel_type < 0 || rel_type >= REL_CNT) {
+ ALOGE("EV_REL type 0x%" PRIX16 " out of range [0,0x%X)", rel_type, REL_CNT);
+ return Error(ERROR_REL_RANGE);
+ }
+ if (const int status = RequireState(State::CONFIGURING)) {
+ return status;
+ }
+ if (const int status = EnableEventType(EV_REL)) {
+ return status;
+ }
+ if (const int status = uinput_->IoctlSetInt(UI_SET_RELBIT, rel_type)) {
+ ALOGE("failed to enable EV_REL 0x%" PRIX16 "", rel_type);
+ return Error(status);
+ }
+ return 0;
+}
+
int EvdevInjector::ConfigureEnd() {
ALOGV("ConfigureEnd:");
ALOGV(" name=\"%s\"", uidev_.name);
@@ -236,6 +255,10 @@
return Send(EV_ABS, code, value);
}
+int EvdevInjector::SendRel(uint16_t code, int32_t value) {
+ return Send(EV_REL, code, value);
+}
+
int EvdevInjector::SendMultiTouchSlot(int32_t slot) {
if (latest_slot_ != slot) {
if (const int status = SendAbs(ABS_MT_SLOT, slot)) {
diff --git a/services/vr/virtual_touchpad/EvdevInjector.h b/services/vr/virtual_touchpad/EvdevInjector.h
index c69dbef..e87c959 100644
--- a/services/vr/virtual_touchpad/EvdevInjector.h
+++ b/services/vr/virtual_touchpad/EvdevInjector.h
@@ -30,6 +30,7 @@
ERROR_KEY_RANGE = -3, // |KEY_*|/|BTN_*| code out of range.
ERROR_ABS_RANGE = -4, // |ABS_*| code out of range.
ERROR_SEQUENCING = -5, // Configure/Send out of order.
+ ERROR_REL_RANGE = -6, // |REL_*| code out of range.
};
// Key event |value| is not defined in <linux/input.h>.
@@ -87,6 +88,10 @@
// Configure multitouch coordinate range.
int ConfigureMultiTouchXY(int32_t x0, int32_t y0, int32_t x1, int32_t y1);
+ // Configure a relative axis.
+ // @param rel_type One of the |REL_*| constants from <linux/input.h>.
+ int ConfigureRel(uint16_t rel_type);
+
// Complete configuration and create the input device.
int ConfigureEnd();
@@ -96,6 +101,7 @@
int SendSynReport();
int SendKey(uint16_t code, int32_t value);
int SendAbs(uint16_t code, int32_t value);
+ int SendRel(uint16_t code, int32_t value);
int SendMultiTouchSlot(int32_t slot);
int SendMultiTouchXY(int32_t slot, int32_t id, int32_t x, int32_t y);
int SendMultiTouchLift(int32_t slot);
diff --git a/services/vr/virtual_touchpad/VirtualTouchpadClient.cpp b/services/vr/virtual_touchpad/VirtualTouchpadClient.cpp
index c7c8184..00e4ce6 100644
--- a/services/vr/virtual_touchpad/VirtualTouchpadClient.cpp
+++ b/services/vr/virtual_touchpad/VirtualTouchpadClient.cpp
@@ -60,6 +60,13 @@
return service_->buttonState(touchpad, buttons).transactionError();
}
+ status_t Scroll(int touchpad, float x, float y) override {
+ if (service_ == nullptr) {
+ return NO_INIT;
+ }
+ return service_->scroll(touchpad, x, y).transactionError();
+ }
+
void dumpInternal(String8& result) override {
result.append("[virtual touchpad]\n");
result.appendFormat("connected = %s\n\n",
diff --git a/services/vr/virtual_touchpad/VirtualTouchpadEvdev.cpp b/services/vr/virtual_touchpad/VirtualTouchpadEvdev.cpp
index f0bdcd9..bcfdad3 100644
--- a/services/vr/virtual_touchpad/VirtualTouchpadEvdev.cpp
+++ b/services/vr/virtual_touchpad/VirtualTouchpadEvdev.cpp
@@ -28,6 +28,12 @@
static constexpr int32_t kHeight = 0x10000;
static constexpr int32_t kSlots = 2;
+static constexpr float kScrollScale = 100.0f;
+
+int32_t scale_relative_scroll(float x) {
+ return kScrollScale * x;
+}
+
} // anonymous namespace
std::unique_ptr<VirtualTouchpad> VirtualTouchpadEvdev::Create() {
@@ -66,6 +72,8 @@
touchpad.injector->ConfigureInputProperty(INPUT_PROP_DIRECT);
touchpad.injector->ConfigureMultiTouchXY(0, 0, kWidth - 1, kHeight - 1);
touchpad.injector->ConfigureAbsSlots(kSlots);
+ touchpad.injector->ConfigureRel(REL_WHEEL);
+ touchpad.injector->ConfigureRel(REL_HWHEEL);
touchpad.injector->ConfigureKey(BTN_TOUCH);
touchpad.injector->ConfigureKey(BTN_BACK);
touchpad.injector->ConfigureEnd();
@@ -86,9 +94,6 @@
if (touchpad_id < 0 || touchpad_id >= kTouchpads) {
return EINVAL;
}
- if ((x < 0.0f) || (x >= 1.0f) || (y < 0.0f) || (y >= 1.0f)) {
- return EINVAL;
- }
int32_t device_x = x * kWidth;
int32_t device_y = y * kHeight;
Touchpad& touchpad = touchpad_[touchpad_id];
@@ -162,6 +167,33 @@
return touchpad.injector->GetError();
}
+int VirtualTouchpadEvdev::Scroll(int touchpad_id, float x, float y) {
+ if (touchpad_id < 0 || touchpad_id >= kTouchpads) {
+ return EINVAL;
+ }
+ if ((x < -1.0f) || (x > 1.0f) || (y < -1.0f) || (y > 1.0f)) {
+ return EINVAL;
+ }
+ Touchpad& touchpad = touchpad_[touchpad_id];
+ if (!touchpad.injector) {
+ return EvdevInjector::ERROR_SEQUENCING;
+ }
+ touchpad.injector->ResetError();
+ const int32_t scaled_x = scale_relative_scroll(x);
+ const int32_t scaled_y = scale_relative_scroll(y);
+ ALOGV("(%f,%f) -> (%" PRId32 ",%" PRId32 ")", x, y, scaled_x, scaled_y);
+ if (scaled_x) {
+ touchpad.injector->SendRel(REL_HWHEEL, scaled_x);
+ }
+ if (scaled_y) {
+ touchpad.injector->SendRel(REL_WHEEL, scaled_y);
+ }
+ if (scaled_x || scaled_y) {
+ touchpad.injector->SendSynReport();
+ }
+ return touchpad.injector->GetError();
+}
+
void VirtualTouchpadEvdev::dumpInternal(String8& result) {
for (int i = 0; i < kTouchpads; ++i) {
const auto& touchpad = touchpad_[i];
diff --git a/services/vr/virtual_touchpad/VirtualTouchpadEvdev.h b/services/vr/virtual_touchpad/VirtualTouchpadEvdev.h
index 2fb8ff3..c9578bf 100644
--- a/services/vr/virtual_touchpad/VirtualTouchpadEvdev.h
+++ b/services/vr/virtual_touchpad/VirtualTouchpadEvdev.h
@@ -21,6 +21,7 @@
status_t Detach() override;
status_t Touch(int touchpad, float x, float y, float pressure) override;
status_t ButtonState(int touchpad, int buttons) override;
+ status_t Scroll(int touchpad, float x, float y) override;
void dumpInternal(String8& result) override;
protected:
diff --git a/services/vr/virtual_touchpad/VirtualTouchpadService.cpp b/services/vr/virtual_touchpad/VirtualTouchpadService.cpp
index 81edd32..523f890 100644
--- a/services/vr/virtual_touchpad/VirtualTouchpadService.cpp
+++ b/services/vr/virtual_touchpad/VirtualTouchpadService.cpp
@@ -87,6 +87,16 @@
return binder::Status::ok();
}
+binder::Status VirtualTouchpadService::scroll(int touchpad, float x, float y) {
+ if (!CheckPermissions()) {
+ return binder::Status::fromStatusT(PERMISSION_DENIED);
+ }
+ if (const status_t error = touchpad_->Scroll(touchpad, x, y)) {
+ return binder::Status::fromStatusT(error);
+ }
+ return binder::Status::ok();
+}
+
status_t VirtualTouchpadService::dump(
int fd, const Vector<String16>& args[[gnu::unused]]) {
String8 result;
diff --git a/services/vr/virtual_touchpad/VirtualTouchpadService.h b/services/vr/virtual_touchpad/VirtualTouchpadService.h
index cf236f9..2c46209 100644
--- a/services/vr/virtual_touchpad/VirtualTouchpadService.h
+++ b/services/vr/virtual_touchpad/VirtualTouchpadService.h
@@ -23,6 +23,7 @@
binder::Status detach() override;
binder::Status touch(int touchpad, float x, float y, float pressure) override;
binder::Status buttonState(int touchpad, int buttons) override;
+ binder::Status scroll(int touchpad, float x, float y) override;
// Implements BBinder::dump().
status_t dump(int fd, const Vector<String16>& args) override;
diff --git a/services/vr/virtual_touchpad/aidl/android/dvr/VirtualTouchpadService.aidl b/services/vr/virtual_touchpad/aidl/android/dvr/VirtualTouchpadService.aidl
index 9cfb186..256203c 100644
--- a/services/vr/virtual_touchpad/aidl/android/dvr/VirtualTouchpadService.aidl
+++ b/services/vr/virtual_touchpad/aidl/android/dvr/VirtualTouchpadService.aidl
@@ -34,4 +34,15 @@
* @param buttons A union of MotionEvent BUTTON_* values.
*/
void buttonState(int touchpad, int buttons) = 3;
+
+ /**
+ * Generate a simulated scroll event.
+ *
+ * @param touchpad Selects touchpad.
+ * @param x Horizontal scroll increment.
+ * @param y Vertical scroll increment.
+ *
+ * Scroll values are in the range [-1.0, 1.0].
+ */
+ void scroll(int touchpad, float x, float y) = 4;
}
diff --git a/services/vr/virtual_touchpad/idc/vr-virtual-touchpad-0.idc b/services/vr/virtual_touchpad/idc/vr-virtual-touchpad-0.idc
new file mode 100644
index 0000000..205e8b9
--- /dev/null
+++ b/services/vr/virtual_touchpad/idc/vr-virtual-touchpad-0.idc
@@ -0,0 +1,26 @@
+# Copyright (C) 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.
+
+#
+# Virtual touchpad for the primary display
+device.internal = 1
+
+touch.deviceType = touchScreen
+
+# Have input flinger treat injected scroll events like a G1 ball
+# rather than the default mouse wheel, because the latter requires
+# a visible pointer for targeting.
+device.type = rotaryEncoder
+device.res = 1.0e+2
+device.scalingFactor = 1.0e-2
diff --git a/services/vr/virtual_touchpad/idc/vr-virtual-touchpad-1.idc b/services/vr/virtual_touchpad/idc/vr-virtual-touchpad-1.idc
index 3728ef0..d9714e0 100644
--- a/services/vr/virtual_touchpad/idc/vr-virtual-touchpad-1.idc
+++ b/services/vr/virtual_touchpad/idc/vr-virtual-touchpad-1.idc
@@ -18,6 +18,13 @@
touch.deviceType = touchScreen
+# Have input flinger treat injected scroll events like a G1 ball
+# rather than the default mouse wheel, because the latter requires
+# a visible pointer for targeting.
+device.type = rotaryEncoder
+device.res = 1.0e+2
+device.scalingFactor = 1.0e-2
+
# This displayID matches the unique ID of the virtual display created for VR.
# This will indicate to input flinger than it should link this input device
# with the virtual display.
diff --git a/services/vr/virtual_touchpad/include/VirtualTouchpad.h b/services/vr/virtual_touchpad/include/VirtualTouchpad.h
index da3a0b7..99b72fc 100644
--- a/services/vr/virtual_touchpad/include/VirtualTouchpad.h
+++ b/services/vr/virtual_touchpad/include/VirtualTouchpad.h
@@ -61,6 +61,16 @@
//
virtual status_t ButtonState(int touchpad, int buttons) = 0;
+ // Generate a simulated scroll event.
+ //
+ // @param touchpad Touchpad selector index.
+ // @param x Horizontal scroll increment.
+ // @param y Vertical scroll increment.
+ // Values must be in the range [-1.0, 1.0].
+ // @returns OK on success.
+ //
+ virtual status_t Scroll(int touchpad, float x, float y) = 0;
+
// Report state for 'dumpsys'.
virtual void dumpInternal(String8& result) = 0;
diff --git a/services/vr/virtual_touchpad/include/VirtualTouchpadClient.h b/services/vr/virtual_touchpad/include/VirtualTouchpadClient.h
index 23fb9f8..7d73f06 100644
--- a/services/vr/virtual_touchpad/include/VirtualTouchpadClient.h
+++ b/services/vr/virtual_touchpad/include/VirtualTouchpadClient.h
@@ -17,6 +17,7 @@
status_t Detach() override;
status_t Touch(int touchpad, float x, float y, float pressure) override;
status_t ButtonState(int touchpad, int buttons) override;
+ status_t Scroll(int touchpad, float x, float y) override;
void dumpInternal(String8& result) override;
protected:
diff --git a/services/vr/virtual_touchpad/include/dvr/virtual_touchpad_client.h b/services/vr/virtual_touchpad/include/dvr/virtual_touchpad_client.h
index 15e6687..09fb1cc 100644
--- a/services/vr/virtual_touchpad/include/dvr/virtual_touchpad_client.h
+++ b/services/vr/virtual_touchpad/include/dvr/virtual_touchpad_client.h
@@ -61,6 +61,17 @@
int dvrVirtualTouchpadButtonState(DvrVirtualTouchpad* client, int touchpad,
int buttons);
+// Generate a simulated scroll event.
+//
+// @param client Pointer to the virtual touchpad client.
+// @param touchpad Selects touchpad.
+// @param x Horizontal scroll increment.
+// @param y Vertical scroll increment.
+// @return Zero on success, status_t-style error code on failure.
+//
+int dvrVirtualTouchpadScroll(DvrVirtualTouchpad* client, int touchpad, float x,
+ float y);
+
#ifdef __cplusplus
} // extern "C"
#endif
diff --git a/services/vr/virtual_touchpad/tests/VirtualTouchpad_test.cpp b/services/vr/virtual_touchpad/tests/VirtualTouchpad_test.cpp
index 564bcd7..198ed06 100644
--- a/services/vr/virtual_touchpad/tests/VirtualTouchpad_test.cpp
+++ b/services/vr/virtual_touchpad/tests/VirtualTouchpad_test.cpp
@@ -110,17 +110,6 @@
EvdevInjectorForTesting injector[kTouchpads];
};
-void DumpDifference(const char* expect, const char* actual) {
- printf(" common: ");
- while (*expect && *expect == *actual) {
- putchar(*expect);
- ++expect;
- ++actual;
- }
- printf("\n expect: %s\n", expect);
- printf(" actual: %s\n", actual);
-}
-
} // anonymous namespace
class VirtualTouchpadTest : public testing::Test {};
@@ -153,7 +142,6 @@
}
const int32_t width = 1 + uidev->absmax[ABS_MT_POSITION_X];
const int32_t height = 1 + uidev->absmax[ABS_MT_POSITION_Y];
- const int32_t slots = uidev->absmax[ABS_MT_SLOT];
for (int t = 0; t < touchpad->GetTouchpadCount(); ++t) {
SCOPED_TRACE(t);
@@ -169,6 +157,11 @@
expect.IoctlSetInt(UI_SET_ABSBIT, ABS_MT_POSITION_Y);
// From ConfigureAbsSlots(kSlots):
expect.IoctlSetInt(UI_SET_ABSBIT, ABS_MT_SLOT);
+ // From ConfigureRel(REL_WHEEL):
+ expect.IoctlSetInt(UI_SET_EVBIT, EV_REL);
+ expect.IoctlSetInt(UI_SET_RELBIT, REL_WHEEL);
+ // From ConfigureRel(REL_HWHEEL):
+ expect.IoctlSetInt(UI_SET_RELBIT, REL_HWHEEL);
// From ConfigureKey(BTN_TOUCH):
expect.IoctlSetInt(UI_SET_EVBIT, EV_KEY);
expect.IoctlSetInt(UI_SET_KEYBIT, BTN_TOUCH);
diff --git a/vulkan/Android.bp b/vulkan/Android.bp
index 91c270e..6107088 100644
--- a/vulkan/Android.bp
+++ b/vulkan/Android.bp
@@ -25,8 +25,22 @@
cc_library_headers {
name: "vulkan_headers",
- export_include_dirs: ["include"],
vendor_available: true,
+ header_libs: [
+ "libcutils_headers",
+ "libhardware_headers",
+ ],
+ export_header_lib_headers: [
+ "libcutils_headers",
+ "libhardware_headers",
+ ],
+ export_include_dirs: ["include"],
+}
+
+cc_library_headers {
+ name: "vulkan_headers_ndk",
+ export_include_dirs: ["include"],
+ sdk_version: "24",
}
subdirs = [
diff --git a/vulkan/api/vulkan.api b/vulkan/api/vulkan.api
index 3efc131..2bbe5e6 100644
--- a/vulkan/api/vulkan.api
+++ b/vulkan/api/vulkan.api
@@ -27,8 +27,8 @@
// API version (major.minor.patch)
define VERSION_MAJOR 1
-define VERSION_MINOR 0
-define VERSION_PATCH 49
+define VERSION_MINOR 1
+define VERSION_PATCH 61
// API limits
define VK_MAX_PHYSICAL_DEVICE_NAME_SIZE 256
@@ -37,9 +37,10 @@
define VK_MAX_DESCRIPTION_SIZE 256
define VK_MAX_MEMORY_TYPES 32
define VK_MAX_MEMORY_HEAPS 16 /// The maximum number of unique memory heaps, each of which supporting 1 or more memory types.
-define VK_MAX_DEVICE_GROUP_SIZE_KHX 32
-define VK_LUID_SIZE_KHX 8
-define VK_QUEUE_FAMILY_EXTERNAL_KHX -2
+@vulkan1_1
+define VK_MAX_DEVICE_GROUP_SIZE 32
+define VK_LUID_SIZE 8
+define VK_QUEUE_FAMILY_EXTERNAL -2
// API keywords
define VK_TRUE 1
@@ -53,7 +54,7 @@
@extension("VK_KHR_surface") define VK_KHR_SURFACE_EXTENSION_NAME "VK_KHR_surface"
// 2
-@extension("VK_KHR_swapchain") define VK_KHR_SWAPCHAIN_SPEC_VERSION 68
+@extension("VK_KHR_swapchain") define VK_KHR_SWAPCHAIN_SPEC_VERSION 70
@extension("VK_KHR_swapchain") define VK_KHR_SWAPCHAIN_EXTENSION_NAME "VK_KHR_swapchain"
// 3
@@ -85,7 +86,7 @@
@extension("VK_KHR_android_surface") define VK_KHR_ANDROID_SURFACE_NAME "VK_KHR_android_surface"
// 10
-@extension("VK_KHR_win32_surface") define VK_KHR_WIN32_SURFACE_SPEC_VERSION 5
+@extension("VK_KHR_win32_surface") define VK_KHR_WIN32_SURFACE_SPEC_VERSION 6
@extension("VK_KHR_win32_surface") define VK_KHR_WIN32_SURFACE_NAME "VK_KHR_win32_surface"
// 11
@@ -93,13 +94,17 @@
@extension("VK_ANDROID_native_buffer") define VK_ANDROID_NATIVE_BUFFER_NAME "VK_ANDROID_native_buffer"
// 12
-@extension("VK_EXT_debug_report") define VK_EXT_DEBUG_REPORT_SPEC_VERSION 6
+@extension("VK_EXT_debug_report") define VK_EXT_DEBUG_REPORT_SPEC_VERSION 9
@extension("VK_EXT_debug_report") define VK_EXT_DEBUG_REPORT_NAME "VK_EXT_debug_report"
// 13
@extension("VK_NV_glsl_shader") define VK_NV_GLSL_SHADER_SPEC_VERSION 1
@extension("VK_NV_glsl_shader") define VK_NV_GLSL_SHADER_NAME "VK_NV_glsl_shader"
+// 14
+@extension("VK_EXT_depth_range_unrestricted") define VK_EXT_DEPTH_RANGE_UNRESTRICTED_SPEC_VERSION 1
+@extension("VK_EXT_depth_range_unrestricted") define VK_EXT_DEPTH_RANGE_UNRESTRICTED_NAME "VK_EXT_depth_range_unrestricted"
+
// 15
@extension("VK_KHR_sampler_mirror_clamp_to_edge") define VK_KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE_SPEC_VERSION 1
@extension("VK_KHR_sampler_mirror_clamp_to_edge") define VK_KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE_NAME "VK_KHR_sampler_mirror_clamp_to_edge"
@@ -152,9 +157,13 @@
@extension("VK_AMD_shader_ballot") define VK_AMD_SHADER_BALLOT_SPEC_VERSION 1
@extension("VK_AMD_shader_ballot") define VK_AMD_SHADER_BALLOT_EXTENSION_NAME "VK_AMD_shader_ballot"
+// 42
+@extension("VK_AMD_texture_gather_bias_lod") define VK_AMD_TEXTURE_GATHER_BIAS_LOD_SPEC_VERSION 1
+@extension("VK_AMD_texture_gather_bias_lod") define VK_AMD_TEXTURE_GATHER_BIAS_LOD_EXTENSION_NAME "VK_AMD_texture_gather_bias_lod"
+
// 54
-@extension("VK_KHX_multiview") define VK_KHX_MULTIVIEW_SPEC_VERSION 1
-@extension("VK_KHX_multiview") define VK_KHX_MULTIVIEW_EXTENSION_NAME "VK_KHX_multiview"
+@extension("VK_KHR_multiview") define VK_KHR_MULTIVIEW_SPEC_VERSION 1
+@extension("VK_KHR_multiview") define VK_KHR_MULTIVIEW_EXTENSION_NAME "VK_KHR_multiview"
// 56
@extension("VK_NV_external_memory_capabilities") define VK_NV_EXTERNAL_MEMORY_CAPABILITIES_SPEC_VERSION 1
@@ -177,8 +186,8 @@
@extension("VK_KHR_get_physical_device_properties2") define VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME "VK_KHR_get_physical_device_properties2"
// 61
-@extension("VK_KHX_device_group") define VK_KHX_DEVICE_GROUP_SPEC_VERSION 1
-@extension("VK_KHX_device_group") define VK_KHX_DEVICE_GROUP_EXTENSION_NAME "VK_KHX_device_group"
+@extension("VK_KHR_device_group") define VK_KHR_DEVICE_GROUP_SPEC_VERSION 3
+@extension("VK_KHR_device_group") define VK_KHR_DEVICE_GROUP_EXTENSION_NAME "VK_KHR_device_group"
// 62
@extension("VK_EXT_validation_flags") define VK_EXT_VALIDATION_FLAGS_SPEC_VERSION 1
@@ -205,49 +214,53 @@
@extension("VK_KHR_maintenance1") define VK_KHR_MAINTENANCE1_EXTENSION_NAME "VK_KHR_maintenance1"
// 71
-@extension("VK_KHX_device_group_creation") define VK_KHX_DEVICE_GROUP_CREATION_SPEC_VERSION 1
-@extension("VK_KHX_device_group_creation") define VK_KHX_DEVICE_GROUP_CREATION_EXTENSION_NAME "VK_KHX_device_group_creation"
+@extension("VK_KHR_device_group_creation") define VK_KHR_DEVICE_GROUP_CREATION_SPEC_VERSION 1
+@extension("VK_KHR_device_group_creation") define VK_KHR_DEVICE_GROUP_CREATION_EXTENSION_NAME "VK_KHR_device_group_creation"
// 72
-@extension("VK_KHX_external_memory_capabilities") define VK_KHX_EXTERNAL_MEMORY_CAPABILITIES_SPEC_VERSION 1
-@extension("VK_KHX_external_memory_capabilities") define VK_KHX_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME "VK_KHX_external_memory_capabilities"
+@extension("VK_KHR_external_memory_capabilities") define VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_SPEC_VERSION 1
+@extension("VK_KHR_external_memory_capabilities") define VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME "VK_KHR_external_memory_capabilities"
// 73
-@extension("VK_KHX_external_memory") define VK_KHX_EXTERNAL_MEMORY_SPEC_VERSION 1
-@extension("VK_KHX_external_memory") define VK_KHX_EXTERNAL_MEMORY_EXTENSION_NAME "VK_KHX_external_memory"
+@extension("VK_KHR_external_memory") define VK_KHR_EXTERNAL_MEMORY_SPEC_VERSION 1
+@extension("VK_KHR_external_memory") define VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME "VK_KHR_external_memory"
// 74
-@extension("VK_KHX_external_memory_win32") define VK_KHX_EXTERNAL_MEMORY_WIN32_SPEC_VERSION 1
-@extension("VK_KHX_external_memory_win32") define VK_KHX_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME "VK_KHX_external_memory_win32"
+@extension("VK_KHR_external_memory_win32") define VK_KHR_EXTERNAL_MEMORY_WIN32_SPEC_VERSION 1
+@extension("VK_KHR_external_memory_win32") define VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME "VK_KHR_external_memory_win32"
// 75
-@extension("VK_KHX_external_memory_fd") define VK_KHX_EXTERNAL_MEMORY_FD_SPEC_VERSION 1
-@extension("VK_KHX_external_memory_fd") define VK_KHX_EXTERNAL_MEMORY_FD_EXTENSION_NAME "VK_KHX_external_memory_fd"
+@extension("VK_KHR_external_memory_fd") define VK_KHR_EXTERNAL_MEMORY_FD_SPEC_VERSION 1
+@extension("VK_KHR_external_memory_fd") define VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME "VK_KHR_external_memory_fd"
// 76
-@extension("VK_KHX_win32_keyed_mutex") define VK_KHX_WIN32_KEYED_MUTEX_SPEC_VERSION 1
-@extension("VK_KHX_win32_keyed_mutex") define VK_KHX_WIN32_KEYED_MUTEX_EXTENSION_NAME "VK_KHX_win32_keyed_mutex"
+@extension("VK_KHR_win32_keyed_mutex") define VK_KHR_WIN32_KEYED_MUTEX_SPEC_VERSION 1
+@extension("VK_KHR_win32_keyed_mutex") define VK_KHR_WIN32_KEYED_MUTEX_EXTENSION_NAME "VK_KHR_win32_keyed_mutex"
// 77
-@extension("VK_KHX_external_semaphore_capabilities") define VK_KHX_EXTERNAL_SEMAPHORE_CAPABILITIES_SPEC_VERSION 1
-@extension("VK_KHX_external_semaphore_capabilities") define VK_KHX_EXTERNAL_SEMAPHORE_CAPABILITIES_EXTENSION_NAME "VK_KHX_external_semaphore_capabilities"
+@extension("VK_KHR_external_semaphore_capabilities") define VK_KHR_EXTERNAL_SEMAPHORE_CAPABILITIES_SPEC_VERSION 1
+@extension("VK_KHR_external_semaphore_capabilities") define VK_KHR_EXTERNAL_SEMAPHORE_CAPABILITIES_EXTENSION_NAME "VK_KHR_external_semaphore_capabilities"
// 78
-@extension("VK_KHX_external_semaphore") define VK_KHX_EXTERNAL_SEMAPHORE_SPEC_VERSION 1
-@extension("VK_KHX_external_semaphore") define VK_KHX_EXTERNAL_SEMAPHORE_EXTENSION_NAME "VK_KHX_external_semaphore"
+@extension("VK_KHR_external_semaphore") define VK_KHR_EXTERNAL_SEMAPHORE_SPEC_VERSION 1
+@extension("VK_KHR_external_semaphore") define VK_KHR_EXTERNAL_SEMAPHORE_EXTENSION_NAME "VK_KHR_external_semaphore"
// 79
-@extension("VK_KHX_external_semaphore_win32") define VK_KHX_EXTERNAL_SEMAPHORE_WIN32_SPEC_VERSION 1
-@extension("VK_KHX_external_semaphore_win32") define VK_KHX_EXTERNAL_SEMAPHORE_WIN32_EXTENSION_NAME "VK_KHX_external_semaphore_win32"
+@extension("VK_KHR_external_semaphore_win32") define VK_KHR_EXTERNAL_SEMAPHORE_WIN32_SPEC_VERSION 1
+@extension("VK_KHR_external_semaphore_win32") define VK_KHR_EXTERNAL_SEMAPHORE_WIN32_EXTENSION_NAME "VK_KHR_external_semaphore_win32"
// 80
-@extension("VK_KHX_external_semaphore_fd") define VK_KHX_EXTERNAL_SEMAPHORE_FD_SPEC_VERSION 1
-@extension("VK_KHX_external_semaphore_fd") define VK_KHX_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME "VK_KHX_external_semaphore_fd"
+@extension("VK_KHR_external_semaphore_fd") define VK_KHR_EXTERNAL_SEMAPHORE_FD_SPEC_VERSION 1
+@extension("VK_KHR_external_semaphore_fd") define VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME "VK_KHR_external_semaphore_fd"
// 81
-@extension("VK_KHR_push_descriptor") define VK_KHR_PUSH_DESCRIPTOR_SPEC_VERSION 1
+@extension("VK_KHR_push_descriptor") define VK_KHR_PUSH_DESCRIPTOR_SPEC_VERSION 2
@extension("VK_KHR_push_descriptor") define VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME "VK_KHR_push_descriptor"
+// 84
+@extension("VK_KHR_16bit_storage") define VK_KHR_16BIT_STORAGE_SPEC_VERSION 1
+@extension("VK_KHR_16bit_storage") define VK_KHR_16BIT_STORAGE_EXTENSION_NAME "VK_KHR_16bit_storage"
+
// 85
@extension("VK_KHR_incremental_present") define VK_KHR_INCREMENTAL_PRESENT_SPEC_VERSION 1
@extension("VK_KHR_incremental_present") define VK_KHR_INCREMENTAL_PRESENT_EXTENSION_NAME "VK_KHR_incremental_present"
@@ -257,7 +270,7 @@
@extension("VK_KHR_descriptor_update_template") define VK_KHR_DESCRIPTOR_UPDATE_TEMPLATE_EXTENSION_NAME "VK_KHR_descriptor_update_template"
// 87
-@extension("VK_NVX_device_generated_commands") define VK_NVX_DEVICE_GENERATED_COMMANDS_SPEC_VERSION 1
+@extension("VK_NVX_device_generated_commands") define VK_NVX_DEVICE_GENERATED_COMMANDS_SPEC_VERSION 3
@extension("VK_NVX_device_generated_commands") define VK_NVX_DEVICE_GENERATED_COMMANDS_EXTENSION_NAME "VK_NVX_device_generated_commands"
// 88
@@ -309,7 +322,7 @@
@extension("VK_EXT_discard_rectangles") define VK_EXT_DISCARD_RECTANGLES_EXTENSION_NAME "VK_EXT_discard_rectangles"
// 105
-@extension("VK_EXT_swapchain_colorspace") define VK_EXT_SWAPCHAIN_COLORSPACE_SPEC_VERSION 2
+@extension("VK_EXT_swapchain_colorspace") define VK_EXT_SWAPCHAIN_COLORSPACE_SPEC_VERSION 3
@extension("VK_EXT_swapchain_colorspace") define VK_EXT_SWAPCHAIN_COLORSPACE_EXTENSION_NAME "VK_EXT_swapchain_colorspace"
// 106
@@ -320,10 +333,34 @@
@extension("VK_KHR_shared_presentable_image") define VK_KHR_SHARED_PRESENTABLE_IMAGE_SPEC_VERSION 1
@extension("VK_KHR_shared_presentable_image") define VK_KHR_SHARED_PRESENTABLE_IMAGE_EXTENSION_NAME "VK_KHR_shared_presentable_image"
+// 113
+@extension("VK_KHR_external_fence_capabilities") define VK_KHR_EXTERNAL_FENCE_CAPABILITIES_SPEC_VERSION 1
+@extension("VK_KHR_external_fence_capabilities") define VK_KHR_EXTERNAL_FENCE_CAPABILITIES_EXTENSION_NAME "VK_KHR_external_fence_capabilities"
+
+// 114
+@extension("VK_KHR_external_fence") define VK_KHR_EXTERNAL_FENCE_SPEC_VERSION 1
+@extension("VK_KHR_external_fence") define VK_KHR_EXTERNAL_FENCE_EXTENSION_NAME "VK_KHR_external_fence"
+
+// 115
+@extension("VK_KHR_external_fence_win32") define VK_KHR_EXTERNAL_FENCE_WIN32_SPEC_VERSION 1
+@extension("VK_KHR_external_fence_win32") define VK_KHR_EXTERNAL_FENCE_WIN32_EXTENSION_NAME "VK_KHR_external_fence_win32"
+
+// 116
+@extension("VK_KHR_external_fence_fd") define VK_KHR_EXTERNAL_FENCE_FD_SPEC_VERSION 1
+@extension("VK_KHR_external_fence_fd") define VK_KHR_EXTERNAL_FENCE_FD_EXTENSION_NAME "VK_KHR_external_fence_fd"
+
+// 118
+@extension("VK_KHR_maintenance2") define VK_KHR_MAINTENANCE2_SPEC_VERSION 1
+@extension("VK_KHR_maintenance2") define VK_KHR_MAINTENANCE2_EXTENSION_NAME "VK_KHR_maintenance2"
+
// 120
@extension("VK_KHR_get_surface_capabilities2") define VK_KHR_GET_SURFACE_CAPABILITIES_2_SPEC_VERSION 1
@extension("VK_KHR_get_surface_capabilities2") define VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME "VK_KHR_get_surface_capabilities2"
+// 121
+@extension("VK_KHR_variable_pointers") define VK_KHR_VARIABLE_POINTERS_SPEC_VERSION 1
+@extension("VK_KHR_variable_pointers") define VK_KHR_VARIABLE_POINTERS_EXTENSION_NAME "VK_KHR_variable_pointers"
+
// 123
@extension("VK_MVK_ios_surface") define VK_MVK_IOS_SURFACE_SPEC_VERSION 1
@extension("VK_MVK_ios_surface") define VK_MVK_IOS_SURFACE_EXTENSION_NAME "VK_MVK_ios_surface"
@@ -332,6 +369,90 @@
@extension("VK_MVK_macos_surface") define VK_MVK_MACOS_SURFACE_SPEC_VERSION 1
@extension("VK_MVK_macos_surface") define VK_MVK_MACOS_SURFACE_EXTENSION_NAME "VK_MVK_macos_surface"
+// 128
+@extension("VK_KHR_dedicated_allocation") define VK_KHR_DEDICATED_ALLOCATION_SPEC_VERSION 3
+@extension("VK_KHR_dedicated_allocation") define VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME "VK_KHR_dedicated_allocation"
+
+// 131
+@extension("VK_EXT_sampler_filter_minmax") define VK_EXT_SAMPLER_FILTER_MINMAX_SPEC_VERSION 1
+@extension("VK_EXT_sampler_filter_minmax") define VK_EXT_SAMPLER_FILTER_MINMAX_EXTENSION_NAME "VK_EXT_sampler_filter_minmax"
+
+// 132
+@extension("VK_KHR_storage_buffer_storage_class") define VK_KHR_STORAGE_BUFFER_STORAGE_CLASS_SPEC_VERSION 1
+@extension("VK_KHR_storage_buffer_storage_class") define VK_KHR_STORAGE_BUFFER_STORAGE_CLASS_EXTENSION_NAME "VK_KHR_storage_buffer_storage_class"
+
+// 133
+@extension("VK_AMD_gpu_shader_int16") define VK_AMD_GPU_SHADER_INT16_SPEC_VERSION 1
+@extension("VK_AMD_gpu_shader_int16") define VK_AMD_GPU_SHADER_INT16_EXTENSION_NAME "VK_AMD_gpu_shader_int16"
+
+// 137
+@extension("VK_AMD_mixed_attachment_samples") define VK_AMD_MIXED_ATTACHMENT_SAMPLES_SPEC_VERSION 1
+@extension("VK_AMD_mixed_attachment_samples") define VK_AMD_MIXED_ATTACHMENT_SAMPLES_EXTENSION_NAME "VK_AMD_mixed_attachment_samples"
+
+// 138
+@extension("VK_AMD_shader_fragment_mask") define VK_AMD_SHADER_FRAGMENT_MASK_SPEC_VERSION 1
+@extension("VK_AMD_shader_fragment_mask") define VK_AMD_SHADER_FRAGMENT_MASK_EXTENSION_NAME "VK_AMD_shader_fragment_mask"
+
+// 141
+@extension("VK_EXT_shader_stencil_export") define VK_EXT_SHADER_STENCIL_EXPORT_SPEC_VERSION 1
+@extension("VK_EXT_shader_stencil_export") define VK_EXT_SHADER_STENCIL_EXPORT_EXTENSION_NAME "VK_EXT_shader_stencil_export"
+
+// 144
+@extension("VK_EXT_sample_locations") define VK_EXT_SAMPLE_LOCATIONS_SPEC_VERSION 1
+@extension("VK_EXT_sample_locations") define VK_EXT_SAMPLE_LOCATIONS_EXTENSION_NAME "VK_EXT_sample_locations"
+
+// 145
+@extension("VK_KHR_relaxed_block_layout") define VK_KHR_RELAXED_BLOCK_LAYOUT_SPEC_VERSION 1
+@extension("VK_KHR_relaxed_block_layout") define VK_KHR_RELAXED_BLOCK_LAYOUT_EXTENSION_NAME "VK_KHR_relaxed_block_layout"
+
+// 147
+@extension("VK_KHR_get_memory_requirements2") define VK_KHR_GET_MEMORY_REQUIREMENTS2_SPEC_VERSION 1
+@extension("VK_KHR_get_memory_requirements2") define VK_KHR_GET_MEMORY_REQUIREMENTS2_EXTENSION_NAME "VK_KHR_get_memory_requirements2"
+
+// 148
+@extension("VK_KHR_image_format_list") define VK_KHR_IMAGE_FORMAT_LIST_SPEC_VERSION 1
+@extension("VK_KHR_image_format_list") define VK_KHR_IMAGE_FORMAT_LIST_EXTENSION_NAME "VK_KHR_image_format_list"
+
+// 149
+@extension("VK_EXT_blend_operation_advanced") define VK_EXT_BLEND_OPERATION_ADVANCED_SPEC_VERSION 2
+@extension("VK_EXT_blend_operation_advanced") define VK_EXT_BLEND_OPERATION_ADVANCED_EXTENSION_NAME "VK_EXT_blend_operation_advanced"
+
+// 150
+@extension("VK_NV_fragment_coverage_to_color") define VK_NV_FRAGMENT_COVERAGE_TO_COLOR_SPEC_VERSION 1
+@extension("VK_NV_fragment_coverage_to_color") define VK_NV_FRAGMENT_COVERAGE_TO_COLOR_EXTENSION_NAME "VK_NV_fragment_coverage_to_color"
+
+// 153
+@extension("VK_NV_framebuffer_mixed_samples") define VK_NV_FRAMEBUFFER_MIXED_SAMPLES_SPEC_VERSION 1
+@extension("VK_NV_framebuffer_mixed_samples") define VK_NV_FRAMEBUFFER_MIXED_SAMPLES_EXTENSION_NAME "VK_NV_framebuffer_mixed_samples"
+
+// 154
+@extension("VK_NV_fill_rectangle") define VK_NV_FILL_RECTANGLE_SPEC_VERSION 1
+@extension("VK_NV_fill_rectangle") define VK_NV_FILL_RECTANGLE_EXTENSION_NAME "VK_NV_fill_rectangle"
+
+// 156
+@extension("VK_EXT_post_depth_coverage") define VK_EXT_POST_DEPTH_COVERAGE_SPEC_VERSION 1
+@extension("VK_EXT_post_depth_coverage") define VK_EXT_POST_DEPTH_COVERAGE_EXTENSION_NAME "VK_EXT_post_depth_coverage"
+
+// 157
+@extension("VK_KHR_sampler_ycbcr_conversion") define VK_KHR_SAMPLER_YCBCR_CONVERSION_SPEC_VERSION 1
+@extension("VK_KHR_sampler_ycbcr_conversion") define VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME "VK_KHR_sampler_ycbcr_conversion"
+
+// 158
+@extension("VK_KHR_bind_memory2") define VK_KHR_BIND_MEMORY2_SPEC_VERSION 1
+@extension("VK_KHR_bind_memory2") define VK_KHR_BIND_MEMORY2_EXTENSION_NAME "VK_KHR_bind_memory2"
+
+// 161
+@extension("VK_EXT_validation_cache") define VK_EXT_VALIDATION_CACHE_SPEC_VERSION 1
+@extension("VK_EXT_validation_cache") define VK_EXT_VALIDATION_CACHE_EXTENSION_NAME "VK_EXT_validation_cache"
+
+// 165
+@extension("VK_EXT_shader_viewport_index_layer") define VK_EXT_SHADER_VIEWPORT_INDEX_LAYER_SPEC_VERSION 1
+@extension("VK_EXT_shader_viewport_index_layer") define VK_EXT_SHADER_VIEWPORT_INDEX_LAYER_EXTENSION_NAME "VK_EXT_shader_viewport_index_layer"
+
+// 169
+@extension("VK_KHR_maintenance3") define VK_KHR_MAINTENANCE3_SPEC_VERSION 1
+@extension("VK_KHR_maintenance3") define VK_KHR_MAINTENANCE3_EXTENSION_NAME "VK_KHR_maintenance3"
+
/////////////
// Types //
/////////////
@@ -370,6 +491,10 @@
@nonDispatchHandle type u64 VkRenderPass
@nonDispatchHandle type u64 VkPipelineCache
+@vulkan1_1
+@nonDispatchHandle type u64 VkSamplerYcbcrConversion
+@nonDispatchHandle type u64 VkDescriptorUpdateTemplate
+
// 1
@extension("VK_KHR_surface") @nonDispatchHandle type u64 VkSurfaceKHR
@@ -390,6 +515,11 @@
@extension("VK_NVX_device_generated_commands") @nonDispatchHandle type u64 VkObjectTableNVX
@extension("VK_NVX_device_generated_commands") @nonDispatchHandle type u64 VkIndirectCommandsLayoutNVX
+// 157
+@extension("VK_KHR_sampler_ycbcr_conversion") @nonDispatchHandle type u64 VkSamplerYcbcrConversionKHR
+
+// 161
+@extension("VK_EXT_validation_cache") @nonDispatchHandle type u64 VkValidationCacheEXT
/////////////
// Enums //
@@ -406,11 +536,19 @@
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL = 0x00000007, /// Optimal layout when image is used only as destination of transfer operations
VK_IMAGE_LAYOUT_PREINITIALIZED = 0x00000008, /// Initial layout used when the data is populated by the CPU
+ //@vulkan1_1
+ VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL = 1000117000,
+ VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL = 1000117001,
+
//@extension("VK_KHR_swapchain") // 2
VK_IMAGE_LAYOUT_PRESENT_SRC_KHR = 1000001002,
//@extension("VK_KHR_shared_presentable_image") // 112
VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR = 1000111000,
+
+ //@extension("VK_KHR_maintenance2") // 118
+ VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL_KHR = 1000117000,
+ VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL_KHR = 1000117001,
}
enum VkAttachmentLoadOp {
@@ -554,6 +692,9 @@
VK_POLYGON_MODE_FILL = 0x00000000,
VK_POLYGON_MODE_LINE = 0x00000001,
VK_POLYGON_MODE_POINT = 0x00000002,
+
+ //@extension("VK_NV_fill_rectangle") // 154
+ VK_POLYGON_MODE_FILL_RECTANGLE_NV = 1000153000,
}
enum VkFrontFace {
@@ -589,6 +730,54 @@
VK_BLEND_OP_REVERSE_SUBTRACT = 0x00000002,
VK_BLEND_OP_MIN = 0x00000003,
VK_BLEND_OP_MAX = 0x00000004,
+
+ //@extension("VK_EXT_blend_operation_advanced") // 149
+ VK_BLEND_OP_ZERO_EXT = 1000148000,
+ VK_BLEND_OP_SRC_EXT = 1000148001,
+ VK_BLEND_OP_DST_EXT = 1000148002,
+ VK_BLEND_OP_SRC_OVER_EXT = 1000148003,
+ VK_BLEND_OP_DST_OVER_EXT = 1000148004,
+ VK_BLEND_OP_SRC_IN_EXT = 1000148005,
+ VK_BLEND_OP_DST_IN_EXT = 1000148006,
+ VK_BLEND_OP_SRC_OUT_EXT = 1000148007,
+ VK_BLEND_OP_DST_OUT_EXT = 1000148008,
+ VK_BLEND_OP_SRC_ATOP_EXT = 1000148009,
+ VK_BLEND_OP_DST_ATOP_EXT = 1000148010,
+ VK_BLEND_OP_XOR_EXT = 1000148011,
+ VK_BLEND_OP_MULTIPLY_EXT = 1000148012,
+ VK_BLEND_OP_SCREEN_EXT = 1000148013,
+ VK_BLEND_OP_OVERLAY_EXT = 1000148014,
+ VK_BLEND_OP_DARKEN_EXT = 1000148015,
+ VK_BLEND_OP_LIGHTEN_EXT = 1000148016,
+ VK_BLEND_OP_COLORDODGE_EXT = 1000148017,
+ VK_BLEND_OP_COLORBURN_EXT = 1000148018,
+ VK_BLEND_OP_HARDLIGHT_EXT = 1000148019,
+ VK_BLEND_OP_SOFTLIGHT_EXT = 1000148020,
+ VK_BLEND_OP_DIFFERENCE_EXT = 1000148021,
+ VK_BLEND_OP_EXCLUSION_EXT = 1000148022,
+ VK_BLEND_OP_INVERT_EXT = 1000148023,
+ VK_BLEND_OP_INVERT_RGB_EXT = 1000148024,
+ VK_BLEND_OP_LINEARDODGE_EXT = 1000148025,
+ VK_BLEND_OP_LINEARBURN_EXT = 1000148026,
+ VK_BLEND_OP_VIVIDLIGHT_EXT = 1000148027,
+ VK_BLEND_OP_LINEARLIGHT_EXT = 1000148028,
+ VK_BLEND_OP_PINLIGHT_EXT = 1000148029,
+ VK_BLEND_OP_HARDMIX_EXT = 1000148030,
+ VK_BLEND_OP_HSL_HUE_EXT = 1000148031,
+ VK_BLEND_OP_HSL_SATURATION_EXT = 1000148032,
+ VK_BLEND_OP_HSL_COLOR_EXT = 1000148033,
+ VK_BLEND_OP_HSL_LUMINOSITY_EXT = 1000148034,
+ VK_BLEND_OP_PLUS_EXT = 1000148035,
+ VK_BLEND_OP_PLUS_CLAMPED_EXT = 1000148036,
+ VK_BLEND_OP_PLUS_CLAMPED_ALPHA_EXT = 1000148037,
+ VK_BLEND_OP_PLUS_DARKER_EXT = 1000148038,
+ VK_BLEND_OP_MINUS_EXT = 1000148039,
+ VK_BLEND_OP_MINUS_CLAMPED_EXT = 1000148040,
+ VK_BLEND_OP_CONTRAST_EXT = 1000148041,
+ VK_BLEND_OP_INVERT_OVG_EXT = 1000148042,
+ VK_BLEND_OP_RED_EXT = 1000148043,
+ VK_BLEND_OP_GREEN_EXT = 1000148044,
+ VK_BLEND_OP_BLUE_EXT = 1000148045,
}
enum VkStencilOp {
@@ -834,6 +1023,42 @@
VK_FORMAT_ASTC_12x12_UNORM_BLOCK = 183,
VK_FORMAT_ASTC_12x12_SRGB_BLOCK = 184,
+ //@vulkan1_1
+ VK_FORMAT_G8B8G8R8_422_UNORM = 1000156000,
+ VK_FORMAT_B8G8R8G8_422_UNORM = 1000156001,
+ VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM = 1000156002,
+ VK_FORMAT_G8_B8R8_2PLANE_420_UNORM = 1000156003,
+ VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM = 1000156004,
+ VK_FORMAT_G8_B8R8_2PLANE_422_UNORM = 1000156005,
+ VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM = 1000156006,
+ VK_FORMAT_R10X6_UNORM_PACK16 = 1000156007,
+ VK_FORMAT_R10X6G10X6_UNORM_2PACK16 = 1000156008,
+ VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16 = 1000156009,
+ VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16 = 1000156010,
+ VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16 = 1000156011,
+ VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16 = 1000156012,
+ VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16 = 1000156013,
+ VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16 = 1000156014,
+ VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16 = 1000156015,
+ VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16 = 1000156016,
+ VK_FORMAT_R12X4_UNORM_PACK16 = 1000156017,
+ VK_FORMAT_R12X4G12X4_UNORM_2PACK16 = 1000156018,
+ VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16 = 1000156019,
+ VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16 = 1000156020,
+ VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16 = 1000156021,
+ VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16 = 1000156022,
+ VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16 = 1000156023,
+ VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16 = 1000156024,
+ VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16 = 1000156025,
+ VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16 = 1000156026,
+ VK_FORMAT_G16B16G16R16_422_UNORM = 1000156027,
+ VK_FORMAT_B16G16R16G16_422_UNORM = 1000156028,
+ VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM = 1000156029,
+ VK_FORMAT_G16_B16R16_2PLANE_420_UNORM = 1000156030,
+ VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM = 1000156031,
+ VK_FORMAT_G16_B16R16_2PLANE_422_UNORM = 1000156032,
+ VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM = 1000156033,
+
//@extension("VK_IMG_format_pvrtc") // 28
VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG = 1000054000,
VK_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG = 1000054001,
@@ -843,6 +1068,42 @@
VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG = 1000054005,
VK_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG = 1000054006,
VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG = 1000054007,
+
+ //@extension("VK_KHR_sampler_ycbcr_conversion") // 157
+ VK_FORMAT_G8B8G8R8_422_UNORM_KHR = 1000156000,
+ VK_FORMAT_B8G8R8G8_422_UNORM_KHR = 1000156001,
+ VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM_KHR = 1000156002,
+ VK_FORMAT_G8_B8R8_2PLANE_420_UNORM_KHR = 1000156003,
+ VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM_KHR = 1000156004,
+ VK_FORMAT_G8_B8R8_2PLANE_422_UNORM_KHR = 1000156005,
+ VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM_KHR = 1000156006,
+ VK_FORMAT_R10X6_UNORM_PACK16_KHR = 1000156007,
+ VK_FORMAT_R10X6G10X6_UNORM_2PACK16_KHR = 1000156008,
+ VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16_KHR = 1000156009,
+ VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16_KHR = 1000156010,
+ VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16_KHR = 1000156011,
+ VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16_KHR = 1000156012,
+ VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16_KHR = 1000156013,
+ VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16_KHR = 1000156014,
+ VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16_KHR = 1000156015,
+ VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16_KHR = 1000156016,
+ VK_FORMAT_R12X4_UNORM_PACK16_KHR = 1000156017,
+ VK_FORMAT_R12X4G12X4_UNORM_2PACK16_KHR = 1000156018,
+ VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16_KHR = 1000156019,
+ VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16_KHR = 1000156020,
+ VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16_KHR = 1000156021,
+ VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16_KHR = 1000156022,
+ VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16_KHR = 1000156023,
+ VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16_KHR = 1000156024,
+ VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16_KHR = 1000156025,
+ VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16_KHR = 1000156026,
+ VK_FORMAT_G16B16G16R16_422_UNORM_KHR = 1000156027,
+ VK_FORMAT_B16G16R16G16_422_UNORM_KHR = 1000156028,
+ VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM_KHR = 1000156029,
+ VK_FORMAT_G16_B16R16_2PLANE_420_UNORM_KHR = 1000156030,
+ VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM_KHR = 1000156031,
+ VK_FORMAT_G16_B16R16_2PLANE_422_UNORM_KHR = 1000156032,
+ VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM_KHR = 1000156033,
}
/// Structure type enumerant
@@ -897,9 +1158,83 @@
VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO = 47,
VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO = 48,
+ //@vulkan1_1
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES = 1000094000,
+ VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_INFO = 1000157000,
+ VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO = 1000157001,
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES = 1000083000,
+ VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS = 1000127000,
+ VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO = 1000127001,
+ VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO = 1000060000,
+ VK_STRUCTURE_TYPE_DEVICE_GROUP_RENDER_PASS_BEGIN_INFO = 1000060003,
+ VK_STRUCTURE_TYPE_DEVICE_GROUP_COMMAND_BUFFER_BEGIN_INFO = 1000060004,
+ VK_STRUCTURE_TYPE_DEVICE_GROUP_SUBMIT_INFO = 1000060005,
+ VK_STRUCTURE_TYPE_DEVICE_GROUP_BIND_SPARSE_INFO = 1000060006,
+ VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_DEVICE_GROUP_INFO = 1000060013,
+ VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_DEVICE_GROUP_INFO = 1000060014,
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES = 1000070000,
+ VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO = 1000070001,
+ VK_STRUCTURE_TYPE_BUFFER_MEMORY_REQUIREMENTS_INFO_2 = 1000146000,
+ VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2 = 1000146001,
+ VK_STRUCTURE_TYPE_IMAGE_SPARSE_MEMORY_REQUIREMENTS_INFO_2 = 1000146002,
+ VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2 = 1000146003,
+ VK_STRUCTURE_TYPE_SPARSE_IMAGE_MEMORY_REQUIREMENTS_2 = 1000146004,
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2 = 1000059000,
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2 = 1000059001,
+ VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2 = 1000059002,
+ VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2 = 1000059003,
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2 = 1000059004,
+ VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2 = 1000059005,
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2 = 1000059006,
+ VK_STRUCTURE_TYPE_SPARSE_IMAGE_FORMAT_PROPERTIES_2 = 1000059007,
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SPARSE_IMAGE_FORMAT_INFO_2 = 1000059008,
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_POINT_CLIPPING_PROPERTIES = 1000117000,
+ VK_STRUCTURE_TYPE_RENDER_PASS_INPUT_ATTACHMENT_ASPECT_CREATE_INFO = 1000117001,
+ VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO = 1000117002,
+ VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_DOMAIN_ORIGIN_STATE_CREATE_INFO = 1000117003,
+ VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO = 1000053000,
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES = 1000053001,
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES = 1000053002,
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTER_FEATURES = 1000120000,
+ VK_STRUCTURE_TYPE_PROTECTED_SUBMIT_INFO = 1000145000,
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_FEATURES = 1000145001,
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_PROPERTIES = 1000145002,
+ VK_STRUCTURE_TYPE_DEVICE_QUEUE_INFO_2 = 1000145003,
+ VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO = 1000156000,
+ VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO = 1000156001,
+ VK_STRUCTURE_TYPE_BIND_IMAGE_PLANE_MEMORY_INFO = 1000156002,
+ VK_STRUCTURE_TYPE_IMAGE_PLANE_MEMORY_REQUIREMENTS_INFO = 1000156003,
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES = 1000156004,
+ VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_IMAGE_FORMAT_PROPERTIES = 1000156005,
+ VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO = 1000085000,
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO = 1000071000,
+ VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES = 1000071001,
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_BUFFER_INFO = 1000071002,
+ VK_STRUCTURE_TYPE_EXTERNAL_BUFFER_PROPERTIES = 1000071003,
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES = 1000071004,
+ VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO = 1000072000,
+ VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO = 1000072001,
+ VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO = 1000072002,
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_FENCE_INFO = 1000112000,
+ VK_STRUCTURE_TYPE_EXTERNAL_FENCE_PROPERTIES = 1000112001,
+ VK_STRUCTURE_TYPE_EXPORT_FENCE_CREATE_INFO = 1000113000,
+ VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO = 1000077000,
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO = 1000076000,
+ VK_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_PROPERTIES = 1000076001,
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES = 1000168000,
+ VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_SUPPORT = 1000168001,
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETER_FEATURES = 1000063000,
+ VK_STRUCTURE_TYPE_DEVICE_GROUP_PRESENT_CAPABILITIES_KHR = 1000060007,
+
//@extension("VK_KHR_swapchain") // 2
VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR = 1000001000,
VK_STRUCTURE_TYPE_PRESENT_INFO_KHR = 1000001001,
+ // added as interaction from VK_KHR_device_group / VK 1.1
+ VK_STRUCTURE_TYPE_IMAGE_SWAPCHAIN_CREATE_INFO_KHR = 1000060008,
+ VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_SWAPCHAIN_INFO_KHR = 1000060009,
+ VK_STRUCTURE_TYPE_ACQUIRE_NEXT_IMAGE_INFO_KHR = 1000060010,
+ VK_STRUCTURE_TYPE_DEVICE_GROUP_PRESENT_INFO_KHR = 1000060011,
+ VK_STRUCTURE_TYPE_DEVICE_GROUP_SWAPCHAIN_CREATE_INFO_KHR = 1000060012,
//@extension("VK_KHR_display") // 3
VK_STRUCTURE_TYPE_DISPLAY_MODE_CREATE_INFO_KHR = 1000002000,
@@ -947,10 +1282,13 @@
VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_BUFFER_CREATE_INFO_NV = 1000026001,
VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_MEMORY_ALLOCATE_INFO_NV = 1000026002,
- //@extension("VK_KHX_multiview") // 54
- VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO_KHX = 1000053000,
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES_KHX = 1000053001,
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES_KHX = 1000053002,
+ //@extension("VK_AMD_texture_gather_bias_lod") // 42
+ VK_STRUCTURE_TYPE_TEXTURE_LOD_GATHER_FORMAT_PROPERTIES_AMD = 1000041000,
+
+ //@extension("VK_KHR_multiview") // 54
+ VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO_KHR = 1000053000,
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES_KHR = 1000053001,
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES_KHR = 1000053002,
//@extension("VK_NV_external_memory") // 57
VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO_NV = 1000056000,
@@ -974,20 +1312,16 @@
VK_STRUCTURE_TYPE_SPARSE_IMAGE_FORMAT_PROPERTIES_2_KHR = 1000059007,
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SPARSE_IMAGE_FORMAT_INFO_2_KHR = 1000059008,
- //@extension("VK_KHX_device_group") // 61
- VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO_KHX = 1000060000,
- VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_INFO_KHX = 1000060001,
- VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO_KHX = 1000060002,
- VK_STRUCTURE_TYPE_DEVICE_GROUP_RENDER_PASS_BEGIN_INFO_KHX = 1000060003,
- VK_STRUCTURE_TYPE_DEVICE_GROUP_COMMAND_BUFFER_BEGIN_INFO_KHX = 1000060004,
- VK_STRUCTURE_TYPE_DEVICE_GROUP_SUBMIT_INFO_KHX = 1000060005,
- VK_STRUCTURE_TYPE_DEVICE_GROUP_BIND_SPARSE_INFO_KHX = 1000060006,
- VK_STRUCTURE_TYPE_DEVICE_GROUP_PRESENT_CAPABILITIES_KHX = 1000060007,
- VK_STRUCTURE_TYPE_IMAGE_SWAPCHAIN_CREATE_INFO_KHX = 1000060008,
- VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_SWAPCHAIN_INFO_KHX = 1000060009,
- VK_STRUCTURE_TYPE_ACQUIRE_NEXT_IMAGE_INFO_KHX = 1000060010,
- VK_STRUCTURE_TYPE_DEVICE_GROUP_PRESENT_INFO_KHX = 1000060011,
- VK_STRUCTURE_TYPE_DEVICE_GROUP_SWAPCHAIN_CREATE_INFO_KHX = 1000060012,
+ //@extension("VK_KHR_device_group") // 61
+ VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO_KHR = 1000060000,
+ VK_STRUCTURE_TYPE_DEVICE_GROUP_RENDER_PASS_BEGIN_INFO_KHR = 1000060003,
+ VK_STRUCTURE_TYPE_DEVICE_GROUP_COMMAND_BUFFER_BEGIN_INFO_KHR = 1000060004,
+ VK_STRUCTURE_TYPE_DEVICE_GROUP_SUBMIT_INFO_KHR = 1000060005,
+ VK_STRUCTURE_TYPE_DEVICE_GROUP_BIND_SPARSE_INFO_KHR = 1000060006,
+ VK_STRUCTURE_TYPE_DEVICE_GROUP_PRESENT_CAPABILITIES_KHR = 1000060007,
+ // tokens 08-12 are listed with VK_KHR_swapchain
+ VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_DEVICE_GROUP_INFO_KHR = 1000060013,
+ VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_DEVICE_GROUP_INFO_KHR = 1000060014,
//@extension("VK_EXT_validation_flags") // 62
VK_STRUCTURE_TYPE_VALIDATION_FLAGS_EXT = 1000061000,
@@ -995,52 +1329,56 @@
//@extension("VK_NN_vi_surface") // 63
VK_STRUCTURE_TYPE_VI_SURFACE_CREATE_INFO_NN = 1000062000,
- //@extension("VK_KHX_device_group_creation") // 71
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES_KHX = 1000070000,
- VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO_KHX = 1000070001,
+ //@extension("VK_KHR_device_group_creation") // 71
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES_KHR = 1000070000,
+ VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO_KHR = 1000070001,
- //@extension("VK_KHX_external_memory_capabilities") // 72
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO_KHX = 1000071000,
- VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES_KHX = 1000071001,
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_BUFFER_INFO_KHX = 1000071002,
- VK_STRUCTURE_TYPE_EXTERNAL_BUFFER_PROPERTIES_KHX = 1000071003,
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES_KHX = 1000071004,
+ //@extension("VK_KHR_external_memory_capabilities") // 72
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO_KHR = 1000071000,
+ VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES_KHR = 1000071001,
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_BUFFER_INFO_KHR = 1000071002,
+ VK_STRUCTURE_TYPE_EXTERNAL_BUFFER_PROPERTIES_KHR = 1000071003,
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES_KHR = 1000071004,
- //@extension("VK_KHX_external_memory") // 73
- VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO_KHX = 1000072000,
- VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO_KHX = 1000072001,
- VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_KHX = 1000072002,
+ //@extension("VK_KHR_external_memory") // 73
+ VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO_KHR = 1000072000,
+ VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO_KHR = 1000072001,
+ VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_KHR = 1000072002,
- //@extension("VK_KHX_external_memory_win32") // 74
- VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_KHX = 1000073000,
- VK_STRUCTURE_TYPE_EXPORT_MEMORY_WIN32_HANDLE_INFO_KHX = 1000073001,
- VK_STRUCTURE_TYPE_MEMORY_WIN32_HANDLE_PROPERTIES_KHX = 1000073002,
+ //@extension("VK_KHR_external_memory_win32") // 74
+ VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_KHR = 1000073000,
+ VK_STRUCTURE_TYPE_EXPORT_MEMORY_WIN32_HANDLE_INFO_KHR = 1000073001,
+ VK_STRUCTURE_TYPE_MEMORY_WIN32_HANDLE_PROPERTIES_KHR = 1000073002,
- //@extension("VK_KHX_external_memory_fd") // 75
- VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHX = 1000074000,
- VK_STRUCTURE_TYPE_MEMORY_FD_PROPERTIES_KHX = 1000074001,
+ //@extension("VK_KHR_external_memory_fd") // 75
+ VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR = 1000074000,
+ VK_STRUCTURE_TYPE_MEMORY_FD_PROPERTIES_KHR = 1000074001,
- //@extension("VK_KHX_win32_keyed_mutex") // 76
- VK_STRUCTURE_TYPE_WIN32_KEYED_MUTEX_ACQUIRE_RELEASE_INFO_KHX = 1000075000,
+ //@extension("VK_KHR_win32_keyed_mutex") // 76
+ VK_STRUCTURE_TYPE_WIN32_KEYED_MUTEX_ACQUIRE_RELEASE_INFO_KHR = 1000075000,
- //@extension("VK_KHX_external_semaphore_capabilities") // 77
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO_KHX = 1000076000,
- VK_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_PROPERTIES_KHX = 1000076001,
+ //@extension("VK_KHR_external_semaphore_capabilities") // 77
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO_KHR = 1000076000,
+ VK_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_PROPERTIES_KHR = 1000076001,
- //@extension("VK_KHX_external_semaphore") // 78
- VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO_KHX = 1000077000,
+ //@extension("VK_KHR_external_semaphore") // 78
+ VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO_KHR = 1000077000,
- //@extension("VK_KHX_external_semaphore_win32") // 79
- VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_WIN32_HANDLE_INFO_KHX = 1000078000,
- VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_WIN32_HANDLE_INFO_KHX = 1000078001,
- VK_STRUCTURE_TYPE_D3D12_FENCE_SUBMIT_INFO_KHX = 1000078002,
+ //@extension("VK_KHR_external_semaphore_win32") // 79
+ VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_WIN32_HANDLE_INFO_KHR = 1000078000,
+ VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_WIN32_HANDLE_INFO_KHR = 1000078001,
+ VK_STRUCTURE_TYPE_D3D12_FENCE_SUBMIT_INFO_KHR = 1000078002,
- //@extension("VK_KHX_external_semaphore_fd") // 80
- VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_FD_INFO_KHX = 1000079000,
+ //@extension("VK_KHR_external_semaphore_fd") // 80
+ VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_FD_INFO_KHR = 1000079000,
+ VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR = 1000079001,
//@extension("VK_KHR_push_descriptor") // 81
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PUSH_DESCRIPTOR_PROPERTIES_KHR = 1000080000,
+ //@extension("VK_KHR_16bit_storage") // 84
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES_KHR = 1000083000,
+
//@extension("VK_KHR_incremental_present") // 85
VK_STRUCTURE_TYPE_PRESENT_REGIONS_KHR = 1000084000,
@@ -1059,7 +1397,7 @@
VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_W_SCALING_STATE_CREATE_INFO_NV = 1000087000,
//@extension("VK_EXT_display_surface_counter") // 91
- VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES2_EXT = 1000090000,
+ VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_EXT = 1000090000,
//@extension("VK_EXT_display_control") // 92
VK_STRUCTURE_TYPE_DISPLAY_POWER_INFO_EXT = 1000091000,
@@ -1086,16 +1424,97 @@
//@extension("VK_KHR_shared_presentable_image") // 112
VK_STRUCTURE_TYPE_SHARED_PRESENT_SURFACE_CAPABILITIES_KHR = 1000111000,
+ //@extension("VK_KHR_external_fence_capabilities") // 113
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_FENCE_INFO_KHR = 1000112000,
+ VK_STRUCTURE_TYPE_EXTERNAL_FENCE_PROPERTIES_KHR = 1000112001,
+
+ //@extension("VK_KHR_external_fence") // 114
+ VK_STRUCTURE_TYPE_EXPORT_FENCE_CREATE_INFO_KHR = 1000113000,
+
+ //@extension("VK_KHR_external_fence_win32") // 115
+ VK_STRUCTURE_TYPE_IMPORT_FENCE_WIN32_HANDLE_INFO_KHR = 1000114000,
+ VK_STRUCTURE_TYPE_EXPORT_FENCE_WIN32_HANDLE_INFO_KHR = 1000114001,
+ VK_STRUCTURE_TYPE_FENCE_GET_WIN32_HANDLE_INFO_KHR = 1000114002,
+
+ //@extension("VK_KHR_external_fence_fd") // 117
+ VK_STRUCTURE_TYPE_IMPORT_FENCE_FD_INFO_KHR = 1000115000,
+ VK_STRUCTURE_TYPE_FENCE_GET_FD_INFO_KHR = 1000115001,
+
+ //@extension("VK_KHR_maintenance2") // 118
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_POINT_CLIPPING_PROPERTIES_KHR = 1000117000,
+ VK_STRUCTURE_TYPE_RENDER_PASS_INPUT_ATTACHMENT_ASPECT_CREATE_INFO_KHR = 1000117001,
+ VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO_KHR = 1000117002,
+ VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_DOMAIN_ORIGIN_STATE_CREATE_INFO_KHR = 1000117003,
+
//@extension("VK_KHR_get_surface_capabilities2") // 120
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR = 1000119000,
VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR = 1000119001,
VK_STRUCTURE_TYPE_SURFACE_FORMAT_2_KHR = 1000119002,
+ //@extension("VK_KHR_variable_pointers") // 121
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTER_FEATURES_KHR = 1000120000,
+
//@extension("VK_MVK_ios_surface") // 123
VK_STRUCTURE_TYPE_IOS_SURFACE_CREATE_INFO_MVK = 1000122000,
//@extension("VK_MVK_macos_surface") // 124
VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK = 1000123000,
+
+ //@extension("VK_KHR_dedicated_allocation") // 128
+ VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS_KHR = 1000127000,
+ VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR = 1000127001,
+
+ //@extension("VK_EXT_sampler_filter_minmax") // 131
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_FILTER_MINMAX_PROPERTIES_EXT = 1000130000,
+ VK_STRUCTURE_TYPE_SAMPLER_REDUCTION_MODE_CREATE_INFO_EXT = 1000130001,
+
+ //@extension("VK_EXT_sample_locations") // 144
+ VK_STRUCTURE_TYPE_SAMPLE_LOCATIONS_INFO_EXT = 1000143000,
+ VK_STRUCTURE_TYPE_RENDER_PASS_SAMPLE_LOCATIONS_BEGIN_INFO_EXT = 1000143001,
+ VK_STRUCTURE_TYPE_PIPELINE_SAMPLE_LOCATIONS_STATE_CREATE_INFO_EXT = 1000143002,
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLE_LOCATIONS_PROPERTIES_EXT = 1000143003,
+ VK_STRUCTURE_TYPE_MULTISAMPLE_PROPERTIES_EXT = 1000143004,
+
+ //@extension("VK_KHR_get_memory_requirements2") // 147
+ VK_STRUCTURE_TYPE_BUFFER_MEMORY_REQUIREMENTS_INFO_2_KHR = 1000146000,
+ VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2_KHR = 1000146001,
+ VK_STRUCTURE_TYPE_IMAGE_SPARSE_MEMORY_REQUIREMENTS_INFO_2_KHR = 1000146002,
+ VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2_KHR = 1000146003,
+ VK_STRUCTURE_TYPE_SPARSE_IMAGE_MEMORY_REQUIREMENTS_2_KHR = 1000146004,
+
+ //@extension("VK_KHR_image_format_list") // 148
+ VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO_KHR = 1000147000,
+
+ //@extension("VK_EXT_blend_operation_advanced") // 149
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_FEATURES_EXT = 1000148000,
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_PROPERTIES_EXT = 1000148001,
+ VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_ADVANCED_STATE_CREATE_INFO_EXT = 1000148002,
+
+ //@extension("VK_NV_fragment_coverage_to_color") // 150
+ VK_STRUCTURE_TYPE_PIPELINE_COVERAGE_TO_COLOR_STATE_CREATE_INFO_NV = 1000149000,
+
+ //@extension("VK_NV_framebuffer_mixed_samples") // 153
+ VK_STRUCTURE_TYPE_PIPELINE_COVERAGE_MODULATION_STATE_CREATE_INFO_NV = 1000152000,
+
+ //@extension("VK_KHR_sampler_ycbcr_conversion") // 157
+ VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO_KHR = 1000156000,
+ VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO_KHR = 1000156001,
+ VK_STRUCTURE_TYPE_BIND_IMAGE_PLANE_MEMORY_INFO_KHR = 1000156002,
+ VK_STRUCTURE_TYPE_IMAGE_PLANE_MEMORY_REQUIREMENTS_INFO_KHR = 1000156003,
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES_KHR = 1000156004,
+ VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_IMAGE_FORMAT_PROPERTIES_KHR = 1000156005,
+
+ //@extension("VK_KHR_bind_memory2") // 158
+ VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_INFO_KHR = 1000157000,
+ VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO_KHR = 1000157001,
+
+ //@extension("VK_EXT_validation_cache") // 161
+ VK_STRUCTURE_TYPE_VALIDATION_CACHE_CREATE_INFO_EXT = 1000160000,
+ VK_STRUCTURE_TYPE_SHADER_MODULE_VALIDATION_CACHE_CREATE_INFO_EXT = 1000160001,
+
+ //@extension("VK_KHR_maintenance3") // 169
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES_KHR = 1000168000,
+ VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_SUPPORT_KHR = 1000168001,
}
enum VkSubpassContents {
@@ -1135,6 +1554,10 @@
VK_ERROR_FORMAT_NOT_SUPPORTED = 0xFFFFFFF5, // -11
VK_ERROR_FRAGMENTED_POOL = 0xFFFFFFF4, // -12
+ //@vulkan1_1
+ VK_ERROR_OUT_OF_POOL_MEMORY = 0xC4642878, // -1000069000
+ VK_ERROR_INVALID_EXTERNAL_HANDLE = 0xC4641CBD, // -1000072003
+
//@extension("VK_KHR_surface") // 1
VK_ERROR_SURFACE_LOST_KHR = 0xC4653600, // -1000000000
VK_ERROR_NATIVE_WINDOW_IN_USE_KHR = 0xC46535FF, // -1000000001
@@ -1154,8 +1577,8 @@
//@extension("VK_KHR_maintenance1") // 70
VK_ERROR_OUT_OF_POOL_MEMORY_KHR = 0xC4642878, // -1000069000
- //@extension("VK_KHX_external_memory") // 73
- VK_ERROR_INVALID_EXTERNAL_HANDLE_KHX = 0xC4641CBD, // -1000072003
+ //@extension("VK_KHR_external_memory") // 73
+ VK_ERROR_INVALID_EXTERNAL_HANDLE_KHR = 0xC4641CBD, // -1000072003
}
enum VkDynamicState {
@@ -1174,6 +1597,9 @@
//@extension("VK_EXT_discard_rectangles") // 100
VK_DYNAMIC_STATE_DISCARD_RECTANGLE_EXT = 1000099000,
+
+ //@extension("VK_EXT_sample_locations") // 144
+ VK_DYNAMIC_STATE_SAMPLE_LOCATIONS_EXT = 1000143000,
}
enum VkObjectType {
@@ -1204,6 +1630,10 @@
VK_OBJECT_TYPE_FRAMEBUFFER = 24,
VK_OBJECT_TYPE_COMMAND_POOL = 25,
+ //@vulkan1_1
+ VK_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION = 1000156000,
+ VK_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE = 1000085000,
+
//@extension("VK_KHR_surface") // 1
VK_OBJECT_TYPE_SURFACE_KHR = 1000000000,
@@ -1223,6 +1653,48 @@
//@extension("VK_NVX_device_generated_commands") // 87
VK_OBJECT_TYPE_OBJECT_TABLE_NVX = 1000086000,
VK_OBJECT_TYPE_INDIRECT_COMMANDS_LAYOUT_NVX = 1000086001,
+
+ //@extension("VK_KHR_sampler_ycbcr_conversion") // 157
+ VK_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION_KHR = 1000156000,
+
+ //@extension("VK_EXT_validation_cache") // 161
+ VK_OBJECT_TYPE_VALIDATION_CACHE_EXT = 1000160000,
+}
+
+
+//@vulkan1_1 enums
+
+enum VkPointClippingBehavior {
+ VK_POINT_CLIPPING_BEHAVIOR_ALL_CLIP_PLANES = 0,
+ VK_POINT_CLIPPING_BEHAVIOR_USER_CLIP_PLANES_ONLY = 1,
+}
+
+enum VkTessellationDomainOrigin {
+ VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT = 0,
+ VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT = 1,
+}
+
+enum VkSamplerYcbcrModelConversion {
+ VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY = 0,
+ VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_IDENTITY = 1,
+ VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_709 = 2,
+ VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601 = 3,
+ VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020 = 4,
+}
+
+enum VkSamplerYcbcrRange {
+ VK_SAMPLER_YCBCR_RANGE_ITU_FULL = 0,
+ VK_SAMPLER_YCBCR_RANGE_ITU_NARROW = 1,
+}
+
+enum VkChromaLocation {
+ VK_CHROMA_LOCATION_COSITED_EVEN = 0,
+ VK_CHROMA_LOCATION_MIDPOINT = 1,
+}
+
+enum VkDescriptorUpdateTemplateType {
+ VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET = 0,
+ VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_PUSH_DESCRIPTORS_KHR = 1,
}
@extension("VK_KHR_surface") // 1
@@ -1239,7 +1711,7 @@
@extension("VK_KHR_surface") // 1
enum VkColorSpaceKHR {
- VK_COLORSPACE_SRGB_NONLINEAR_KHR = 0x00000000,
+ VK_COLOR_SPACE_SRGB_NONLINEAR_KHR = 0x00000000,
//@extension("VK_EXT_swapchain_colorspace") // 105
VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT = 1000104001,
@@ -1255,6 +1727,7 @@
VK_COLOR_SPACE_ADOBERGB_LINEAR_EXT = 1000104011,
VK_COLOR_SPACE_ADOBERGB_NONLINEAR_EXT = 1000104012,
VK_COLOR_SPACE_PASS_THROUGH_EXT = 1000104013,
+ VK_COLOR_SPACE_EXTENDED_SRGB_NONLINEAR_EXT = 1000104014,
}
@extension("VK_EXT_debug_report") // 12
@@ -1287,20 +1760,20 @@
VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_POOL_EXT = 25,
VK_DEBUG_REPORT_OBJECT_TYPE_SURFACE_KHR_EXT = 26,
VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT = 27,
- VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT = 28,
+ VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_CALLBACK_EXT_EXT = 28,
VK_DEBUG_REPORT_OBJECT_TYPE_DISPLAY_KHR_EXT = 29,
VK_DEBUG_REPORT_OBJECT_TYPE_DISPLAY_MODE_KHR_EXT = 30,
VK_DEBUG_REPORT_OBJECT_TYPE_OBJECT_TABLE_NVX_EXT = 31,
VK_DEBUG_REPORT_OBJECT_TYPE_INDIRECT_COMMANDS_LAYOUT_NVX_EXT = 32,
+ //extension("VK_EXT_validation_cache") // 161
+ VK_DEBUG_REPORT_OBJECT_TYPE_VALIDATION_CACHE_EXT = 33,
+
//extension("VK_KHR_descriptor_update_template") // 86
VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_KHR_EXT = 1000085000,
-}
-@extension("VK_EXT_debug_report") // 12
-enum VkDebugReportErrorEXT {
- VK_DEBUG_REPORT_ERROR_NONE_EXT = 0,
- VK_DEBUG_REPORT_ERROR_CALLBACK_REF_EXT = 1,
+ //@extension("VK_KHR_sampler_ycbcr_conversion") // 157
+ VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION_KHR_EXT = 1000156000,
}
@extension("VK_AMD_rasterization_order") // 19
@@ -1312,6 +1785,7 @@
@extension("VK_EXT_validation_flags") // 62
enum VkValidationCheckEXT {
VK_VALIDATION_CHECK_ALL_EXT = 0,
+ VK_VALIDATION_CHECK_SHADERS_EXT = 1,
}
@extension("VK_KHR_descriptor_update_template") // 86
@@ -1322,23 +1796,23 @@
@extension("VK_NVX_device_generated_commands") // 87
enum VkIndirectCommandsTokenTypeNVX {
- VK_INDIRECT_COMMANDS_TOKEN_PIPELINE_NVX = 0,
- VK_INDIRECT_COMMANDS_TOKEN_DESCRIPTOR_SET_NVX = 1,
- VK_INDIRECT_COMMANDS_TOKEN_INDEX_BUFFER_NVX = 2,
- VK_INDIRECT_COMMANDS_TOKEN_VERTEX_BUFFER_NVX = 3,
- VK_INDIRECT_COMMANDS_TOKEN_PUSH_CONSTANT_NVX = 4,
- VK_INDIRECT_COMMANDS_TOKEN_DRAW_INDEXED_NVX = 5,
- VK_INDIRECT_COMMANDS_TOKEN_DRAW_NVX = 6,
- VK_INDIRECT_COMMANDS_TOKEN_DISPATCH_NVX = 7,
+ VK_INDIRECT_COMMANDS_TOKEN_TYPE_PIPELINE_NVX = 0,
+ VK_INDIRECT_COMMANDS_TOKEN_TYPE_DESCRIPTOR_SET_NVX = 1,
+ VK_INDIRECT_COMMANDS_TOKEN_TYPE_INDEX_BUFFER_NVX = 2,
+ VK_INDIRECT_COMMANDS_TOKEN_TYPE_VERTEX_BUFFER_NVX = 3,
+ VK_INDIRECT_COMMANDS_TOKEN_TYPE_PUSH_CONSTANT_NVX = 4,
+ VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_INDEXED_NVX = 5,
+ VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_NVX = 6,
+ VK_INDIRECT_COMMANDS_TOKEN_TYPE_DISPATCH_NVX = 7,
}
@extension("VK_NVX_device_generated_commands") // 87
enum VkObjectEntryTypeNVX {
- VK_OBJECT_ENTRY_DESCRIPTOR_SET_NVX = 0,
- VK_OBJECT_ENTRY_PIPELINE_NVX = 1,
- VK_OBJECT_ENTRY_INDEX_BUFFER_NVX = 2,
- VK_OBJECT_ENTRY_VERTEX_BUFFER_NVX = 3,
- VK_OBJECT_ENTRY_PUSH_CONSTANT_NVX = 4,
+ VK_OBJECT_ENTRY_TYPE_DESCRIPTOR_SET_NVX = 0,
+ VK_OBJECT_ENTRY_TYPE_PIPELINE_NVX = 1,
+ VK_OBJECT_ENTRY_TYPE_INDEX_BUFFER_NVX = 2,
+ VK_OBJECT_ENTRY_TYPE_VERTEX_BUFFER_NVX = 3,
+ VK_OBJECT_ENTRY_TYPE_PUSH_CONSTANT_NVX = 4,
}
@extension("VK_EXT_display_control") // 92
@@ -1376,6 +1850,66 @@
VK_DISCARD_RECTANGLE_MODE_EXCLUSIVE_EXT = 1,
}
+@extension("VK_KHR_maintenance2") // 118
+enum VkPointClippingBehaviorKHR {
+ VK_POINT_CLIPPING_BEHAVIOR_ALL_CLIP_PLANES_KHR = 0,
+ VK_POINT_CLIPPING_BEHAVIOR_USER_CLIP_PLANES_ONLY_KHR = 1,
+}
+
+@extension("VK_KHR_maintenance2") // 118
+enum VkTessellationDomainOriginKHR {
+ VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT_KHR = 0,
+ VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT_KHR = 1,
+}
+
+@extension("VK_EXT_sampler_filter_minmax") // 131
+enum VkSamplerReductionModeEXT {
+ VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE_EXT = 0,
+ VK_SAMPLER_REDUCTION_MODE_MIN_EXT = 1,
+ VK_SAMPLER_REDUCTION_MODE_MAX_EXT = 2,
+}
+
+@extension("VK_EXT_blend_operation_advanced") // 149
+enum VkBlendOverlapEXT {
+ VK_BLEND_OVERLAP_UNCORRELATED_EXT = 0,
+ VK_BLEND_OVERLAP_DISJOINT_EXT = 1,
+ VK_BLEND_OVERLAP_CONJOINT_EXT = 2,
+}
+
+@extension("VK_NV_framebuffer_mixed_samples") // 153
+enum VkCoverageModulationModeNV {
+ VK_COVERAGE_MODULATION_MODE_NONE_NV = 0,
+ VK_COVERAGE_MODULATION_MODE_RGB_NV = 1,
+ VK_COVERAGE_MODULATION_MODE_ALPHA_NV = 2,
+ VK_COVERAGE_MODULATION_MODE_RGBA_NV = 3,
+}
+
+@extension("VK_KHR_sampler_ycbcr_conversion") // 157
+enum VkSamplerYcbcrModelConversionKHR {
+ VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY_KHR = 0,
+ VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_IDENTITY_KHR = 1,
+ VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_709_KHR = 2,
+ VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601_KHR = 3,
+ VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020_KHR = 4,
+}
+
+@extension("VK_KHR_sampler_ycbcr_conversion") // 157
+enum VkSamplerYcbcrRangeKHR {
+ VK_SAMPLER_YCBCR_RANGE_ITU_FULL_KHR = 0,
+ VK_SAMPLER_YCBCR_RANGE_ITU_NARROW_KHR = 1,
+}
+
+@extension("VK_KHR_sampler_ycbcr_conversion") // 157
+enum VkChromaLocationKHR {
+ VK_CHROMA_LOCATION_COSITED_EVEN_KHR = 0,
+ VK_CHROMA_LOCATION_MIDPOINT_KHR = 1,
+}
+
+@extension("VK_EXT_validation_cache") // 161
+enum VkValidationCacheHeaderVersionEXT {
+ VK_VALIDATION_CACHE_HEADER_VERSION_ONE_EXT = 1,
+}
+
/////////////////
// Bitfields //
/////////////////
@@ -1387,6 +1921,9 @@
VK_QUEUE_COMPUTE_BIT = 0x00000002, /// Queue supports compute operations
VK_QUEUE_TRANSFER_BIT = 0x00000004, /// Queue supports transfer operations
VK_QUEUE_SPARSE_BINDING_BIT = 0x00000008, /// Queue supports sparse resource memory management operations
+
+ //@vulkan1_1
+ VK_QUEUE_PROTECTED_BIT = 0x00000010,
}
/// Memory properties passed into vkAllocMemory().
@@ -1397,6 +1934,9 @@
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT = 0x00000004,
VK_MEMORY_PROPERTY_HOST_CACHED_BIT = 0x00000008,
VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT = 0x00000010,
+
+ //@vulkan1_1
+ VK_MEMORY_PROPERTY_PROTECTED_BIT = 0x00000020,
}
/// Memory heap flags
@@ -1404,8 +1944,11 @@
bitfield VkMemoryHeapFlagBits {
VK_MEMORY_HEAP_DEVICE_LOCAL_BIT = 0x00000001,
- //@extension("VK_KHX_device_group_creation") // 71
- VK_MEMORY_HEAP_MULTI_INSTANCE_BIT_KHX = 0x00000002,
+ //@vulkan1_1
+ VK_MEMORY_HEAP_MULTI_INSTANCE_BIT = 0x00000002,
+
+ //@extension("VK_KHR_device_group_creation") // 71
+ VK_MEMORY_HEAP_MULTI_INSTANCE_BIT_KHR = 0x00000002,
}
/// Access flags
@@ -1432,6 +1975,9 @@
//@extension("VK_NVX_device_generated_commands") // 87
VK_ACCESS_COMMAND_PROCESS_READ_BIT_NVX = 0x00020000,
VK_ACCESS_COMMAND_PROCESS_WRITE_BIT_NVX = 0x00040000,
+
+ //@extension("VK_EXT_blend_operation_advanced") // 149
+ VK_ACCESS_COLOR_ATTACHMENT_READ_NONCOHERENT_BIT_EXT = 0x00080000,
}
/// Buffer usage flags
@@ -1454,6 +2000,9 @@
VK_BUFFER_CREATE_SPARSE_BINDING_BIT = 0x00000001, /// Buffer should support sparse backing
VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT = 0x00000002, /// Buffer should support sparse backing with partial residency
VK_BUFFER_CREATE_SPARSE_ALIASED_BIT = 0x00000004, /// Buffer should support constent data access to physical memory blocks mapped into multiple locations of sparse buffers
+
+ //@vulkan1_1
+ VK_BUFFER_CREATE_PROTECTED_BIT = 0x00000008,
}
/// Shader stage flags
@@ -1503,11 +2052,33 @@
VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT = 0x00000008, /// Allows image views to have different format than the base image
VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT = 0x00000010, /// Allows creating image views with cube type from the created image
+ //@vulkan1_1
+ VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT = 0x00000020,
+ VK_IMAGE_CREATE_BIND_SFR_BIT = 0x00000040,
+ VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT = 0x00000080,
+ VK_IMAGE_CREATE_EXTENDED_USAGE_BIT = 0x00000100,
+ VK_IMAGE_CREATE_DISJOINT_BIT = 0x00000200,
+ VK_IMAGE_CREATE_ALIAS_BIT = 0x00000400,
+ VK_IMAGE_CREATE_PROTECTED_BIT = 0x00000800,
+
//@extension("VK_KHR_maintenance1") // 70
VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT_KHR = 0x00000020,
- //@extension("VK_KHX_device_group") // 61
- VK_IMAGE_CREATE_BIND_SFR_BIT_KHX = 0x00000040,
+ //@extension("VK_KHR_device_group") // 61
+ VK_IMAGE_CREATE_BIND_SFR_BIT_KHR = 0x00000040,
+
+ //@extension("VK_KHR_maintenance2") // 118
+ VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT_KHR = 0x00000080,
+ VK_IMAGE_CREATE_EXTENDED_USAGE_BIT_KHR = 0x00000100,
+
+ //@extension("VK_KHR_sampler_ycbcr_conversion") // 157
+ VK_IMAGE_CREATE_DISJOINT_BIT_KHR = 0x00000200,
+
+ //@extension("VK_KHR_bind_memory2") // 158
+ VK_IMAGE_CREATE_ALIAS_BIT_KHR = 0x00000400,
+
+ //@extension("VK_EXT_sample_locations") // 144
+ VK_IMAGE_CREATE_SAMPLE_LOCATIONS_COMPATIBLE_DEPTH_BIT_EXT = 0x00001000,
}
/// Image view creation flags
@@ -1522,9 +2093,13 @@
VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT = 0x00000002,
VK_PIPELINE_CREATE_DERIVATIVE_BIT = 0x00000004,
- //@extension("VK_KHX_device_group") // 61
- VK_PIPELINE_CREATE_VIEW_INDEX_FROM_DEVICE_INDEX_BIT_KHX = 0x00000008,
- VK_PIPELINE_CREATE_DISPATCH_BASE_KHX = 0x00000010,
+ //@vulkan1_1
+ VK_PIPELINE_CREATE_VIEW_INDEX_FROM_DEVICE_INDEX_BIT = 0x00000008,
+ VK_PIPELINE_CREATE_DISPATCH_BASE = 0x00000010,
+
+ //@extension("VK_KHR_device_group") // 61
+ VK_PIPELINE_CREATE_VIEW_INDEX_FROM_DEVICE_INDEX_BIT_KHR = 0x00000008,
+ VK_PIPELINE_CREATE_DISPATCH_BASE_KHR = 0x00000010,
}
/// Color component flags
@@ -1564,12 +2139,35 @@
VK_FORMAT_FEATURE_BLIT_DST_BIT = 0x00000800, /// Format can be used as the destination image of blits with vkCommandBlitImage
VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT = 0x00001000,
+ //@vulkan1_1
+ VK_FORMAT_FEATURE_TRANSFER_SRC_BIT = 0x00004000,
+ VK_FORMAT_FEATURE_TRANSFER_DST_BIT = 0x00008000,
+ VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT = 0x00020000,
+ VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT = 0x00040000,
+ VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER_BIT = 0x00080000,
+ VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_BIT = 0x00100000,
+ VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE_BIT = 0x00200000,
+ VK_FORMAT_FEATURE_DISJOINT_BIT = 0x00400000,
+ VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT = 0x00800000,
+
//@extension("VK_IMG_filter_cubic") // 16
VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_IMG = 0x00002000,
//@extension("VK_KHR_maintenance1") // 70
VK_FORMAT_FEATURE_TRANSFER_SRC_BIT_KHR = 0x00004000,
VK_FORMAT_FEATURE_TRANSFER_DST_BIT_KHR = 0x00008000,
+
+ //@extension("VK_EXT_sampler_filter_minmax") // 131
+ VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_MINMAX_BIT_EXT = 0x00010000,
+
+ //@extension("VK_KHR_sampler_ycbcr_conversion") // 157
+ VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT_KHR = 0x00020000,
+ VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT_KHR = 0x00040000,
+ VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER_BIT_KHR = 0x00080000,
+ VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_BIT_KHR = 0x00100000,
+ VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE_BIT_KHR = 0x00200000,
+ VK_FORMAT_FEATURE_DISJOINT_BIT_KHR = 0x00400000,
+ VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT_KHR = 0x00800000,
}
/// Query control flags
@@ -1633,6 +2231,16 @@
VK_IMAGE_ASPECT_DEPTH_BIT = 0x00000002,
VK_IMAGE_ASPECT_STENCIL_BIT = 0x00000004,
VK_IMAGE_ASPECT_METADATA_BIT = 0x00000008,
+
+ //@vulkan1_1
+ VK_IMAGE_ASPECT_PLANE_0_BIT = 0x00000010,
+ VK_IMAGE_ASPECT_PLANE_1_BIT = 0x00000020,
+ VK_IMAGE_ASPECT_PLANE_2_BIT = 0x00000040,
+
+ //@extension("VK_KHR_sampler_ycbcr_conversion") // 157
+ VK_IMAGE_ASPECT_PLANE_0_BIT_KHR = 0x00000010,
+ VK_IMAGE_ASPECT_PLANE_1_BIT_KHR = 0x00000020,
+ VK_IMAGE_ASPECT_PLANE_2_BIT_KHR = 0x00000040,
}
/// Sparse memory bind flags
@@ -1694,6 +2302,9 @@
bitfield VkCommandPoolCreateFlagBits {
VK_COMMAND_POOL_CREATE_TRANSIENT_BIT = 0x00000001, /// Command buffers have a short lifetime
VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT = 0x00000002, /// Command buffers may release their memory individually
+
+ //@vulkan1_1
+ VK_COMMAND_POOL_CREATE_PROTECTED_BIT = 0x00000004,
}
/// Command pool reset flags
@@ -1737,8 +2348,10 @@
/// Device queue creation flags
type VkFlags VkDeviceQueueCreateFlags
-//bitfield VkDeviceQueueCreateFlagBits {
-//}
+@vulkan1_1
+bitfield VkDeviceQueueCreateFlagBits {
+ VK_DEVICE_QUEUE_CREATE_PROTECTED_BIT = 0x00000001,
+}
/// Query pool creation flags
type VkFlags VkQueryPoolCreateFlags
@@ -1837,11 +2450,15 @@
bitfield VkDependencyFlagBits {
VK_DEPENDENCY_BY_REGION_BIT = 0x00000001,
- //@extension("VK_KHX_multiview") // 54
- VK_DEPENDENCY_VIEW_LOCAL_BIT_KHX = 0x00000002,
+ //@vulkan1_1
+ VK_DEPENDENCY_DEVICE_GROUP_BIT = 0x00000004,
+ VK_DEPENDENCY_VIEW_LOCAL_BIT = 0x00000002,
- //@extension("VK_KHX_device_group") // 61
- VK_DEPENDENCY_DEVICE_GROUP_BIT_KHX = 0x00000004,
+ //@extension("VK_KHR_multiview") // 54
+ VK_DEPENDENCY_VIEW_LOCAL_BIT_KHR = 0x00000002,
+
+ //@extension("VK_KHR_device_group") // 61
+ VK_DEPENDENCY_DEVICE_GROUP_BIT_KHR = 0x00000004,
}
/// Cull mode flags
@@ -1853,6 +2470,109 @@
VK_CULL_MODE_FRONT_AND_BACK = 0x00000003,
}
+//@vulkan1_1 flags
+
+/// Subgroup feature flags
+type VkFlags VkSubgroupFeatureFlags
+bitfield VkSubgroupFeatureFlagBits {
+ VK_SUBGROUP_FEATURE_BASIC_BIT = 0x00000001,
+ VK_SUBGROUP_FEATURE_VOTE_BIT = 0x00000002,
+ VK_SUBGROUP_FEATURE_ARITHMETIC_BIT = 0x00000004,
+ VK_SUBGROUP_FEATURE_BALLOT_BIT = 0x00000008,
+ VK_SUBGROUP_FEATURE_SHUFFLE_BIT = 0x00000010,
+ VK_SUBGROUP_FEATURE_SHUFFLE_RELATIVE_BIT = 0x00000020,
+ VK_SUBGROUP_FEATURE_CLUSTERED_BIT = 0x00000040,
+ VK_SUBGROUP_FEATURE_QUAD_BIT = 0x00000080,
+}
+
+/// Peer memory feature flags
+type VkFlags VkPeerMemoryFeatureFlags
+bitfield VkPeerMemoryFeatureFlagBits {
+ VK_PEER_MEMORY_FEATURE_COPY_SRC_BIT = 0x00000001,
+ VK_PEER_MEMORY_FEATURE_COPY_DST_BIT = 0x00000002,
+ VK_PEER_MEMORY_FEATURE_GENERIC_SRC_BIT = 0x00000004,
+ VK_PEER_MEMORY_FEATURE_GENERIC_DST_BIT = 0x00000008,
+}
+
+/// Memory allocation flags
+type VkFlags VkMemoryAllocateFlags
+bitfield VkMemoryAllocateFlagBits {
+ VK_MEMORY_ALLOCATE_DEVICE_MASK_BIT = 0x00000001,
+}
+
+type VkFlags VkCommandPoolTrimFlags
+//bitfield VkCommandPoolTrimFlagBits {
+//}
+
+type VkFlags VkDescriptorUpdateTemplateCreateFlags
+//bitfield VkDescriptorUpdateTemplateCreateFlagBits {
+//}
+
+/// External memory handle type flags
+type VkFlags VkExternalMemoryHandleTypeFlags
+bitfield VkExternalMemoryHandleTypeFlagBits {
+ VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT = 0x00000001,
+ VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT = 0x00000002,
+ VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT = 0x00000004,
+ VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT = 0x00000008,
+ VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_KMT_BIT = 0x00000010,
+ VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_HEAP_BIT = 0x00000020,
+ VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_RESOURCE_BIT = 0x00000040,
+}
+
+/// External memory feature flags
+type VkFlags VkExternalMemoryFeatureFlags
+bitfield VkExternalMemoryFeatureFlagBits {
+ VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT = 0x00000001,
+ VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT = 0x00000002,
+ VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT = 0x00000004,
+}
+
+/// External fence handle type flags
+type VkFlags VkExternalFenceHandleTypeFlags
+bitfield VkExternalFenceHandleTypeFlagBits {
+ VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT = 0x00000001,
+ VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_BIT = 0x00000002,
+ VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT = 0x00000004,
+ VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT = 0x00000008,
+}
+
+/// External fence feature flags
+type VkFlags VkExternalFenceFeatureFlags
+bitfield VkExternalFenceFeatureFlagBits {
+ VK_EXTERNAL_FENCE_FEATURE_EXPORTABLE_BIT = 0x00000001,
+ VK_EXTERNAL_FENCE_FEATURE_IMPORTABLE_BIT = 0x00000002,
+}
+
+/// Fence import flags
+type VkFlags VkFenceImportFlags
+bitfield VkFenceImportFlagBits {
+ VK_FENCE_IMPORT_TEMPORARY_BIT = 0x00000001,
+}
+
+/// Semaphore import flags
+type VkFlags VkSemaphoreImportFlags
+bitfield VkSemaphoreImportFlagBits {
+ VK_SEMAPHORE_IMPORT_TEMPORARY_BIT = 0x00000001,
+}
+
+/// External semaphore handle type flags
+type VkFlags VkExternalSemaphoreHandleTypeFlags
+bitfield VkExternalSemaphoreHandleTypeFlagBits {
+ VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT = 0x00000001,
+ VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT = 0x00000002,
+ VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT = 0x00000004,
+ VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT = 0x00000008,
+ VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT = 0x00000010,
+}
+
+/// External semaphore feature flags
+type VkFlags VkExternalSemaphoreFeatureFlags
+bitfield VkExternalSemaphoreFeatureFlagBits {
+ VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT = 0x00000001,
+ VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT = 0x00000002,
+}
+
@extension("VK_KHR_surface") // 1
type VkFlags VkSurfaceTransformFlagsKHR
@extension("VK_KHR_surface") // 1
@@ -1882,8 +2602,21 @@
type VkFlags VkSwapchainCreateFlagsKHR
@extension("VK_KHR_swapchain") // 2
bitfield VkSwapchainCreateFlagBitsKHR {
- //@extension("VK_KHX_device_group") // 61
- VK_SWAPCHAIN_CREATE_BIND_SFR_BIT_KHX = 0x00000001,
+ //@vulkan1_1
+ VK_SWAPCHAIN_CREATE_BIND_SFR_BIT_KHR = 0x00000001,
+ VK_SWAPCHAIN_CREATE_PROTECTED_BIT_KHR = 0x00000002,
+}
+
+@vulkan1_1
+@extension("VK_KHR_swapchain") // 2
+type VkFlags VkDeviceGroupPresentModeFlagsKHR
+@vulkan1_1
+@extension("VK_KHR_swapchain") // 2
+bitfield VkDeviceGroupPresentModeFlagBitsKHR {
+ VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_BIT_KHR = 0x00000001,
+ VK_DEVICE_GROUP_PRESENT_MODE_REMOTE_BIT_KHR = 0x00000002,
+ VK_DEVICE_GROUP_PRESENT_MODE_SUM_BIT_KHR = 0x00000004,
+ VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_MULTI_DEVICE_BIT_KHR = 0x00000008,
}
@extension("VK_KHR_display") // 3
@@ -1981,31 +2714,21 @@
VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT_NV = 0x00000004,
}
-@extension("VK_KHX_device_group") // 61
-type VkFlags VkPeerMemoryFeatureFlagsKHX
-@extension("VK_KHX_device_group") // 61
-bitfield VkPeerMemoryFeatureFlagBitsKHX {
- VK_PEER_MEMORY_FEATURE_COPY_SRC_BIT_KHX = 0x00000001,
- VK_PEER_MEMORY_FEATURE_COPY_DST_BIT_KHX = 0x00000002,
- VK_PEER_MEMORY_FEATURE_GENERIC_SRC_BIT_KHX = 0x00000004,
- VK_PEER_MEMORY_FEATURE_GENERIC_DST_BIT_KHX = 0x00000008,
+@extension("VK_KHR_device_group") // 61
+type VkFlags VkPeerMemoryFeatureFlagsKHR
+@extension("VK_KHR_device_group") // 61
+bitfield VkPeerMemoryFeatureFlagBitsKHR {
+ VK_PEER_MEMORY_FEATURE_COPY_SRC_BIT_KHR = 0x00000001,
+ VK_PEER_MEMORY_FEATURE_COPY_DST_BIT_KHR = 0x00000002,
+ VK_PEER_MEMORY_FEATURE_GENERIC_SRC_BIT_KHR = 0x00000004,
+ VK_PEER_MEMORY_FEATURE_GENERIC_DST_BIT_KHR = 0x00000008,
}
-@extension("VK_KHX_device_group") // 61
-type VkFlags VkMemoryAllocateFlagsKHX
-@extension("VK_KHX_device_group") // 61
-bitfield VkMemoryAllocateFlagBitsKHX {
- VK_MEMORY_ALLOCATE_DEVICE_MASK_BIT_KHX = 0x00000001,
-}
-
-@extension("VK_KHX_device_group") // 61
-type VkFlags VkDeviceGroupPresentModeFlagsKHX
-@extension("VK_KHX_device_group") // 61
-bitfield VkDeviceGroupPresentModeFlagBitsKHX {
- VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_BIT_KHX = 0x00000001,
- VK_DEVICE_GROUP_PRESENT_MODE_REMOTE_BIT_KHX = 0x00000002,
- VK_DEVICE_GROUP_PRESENT_MODE_SUM_BIT_KHX = 0x00000004,
- VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_MULTI_DEVICE_BIT_KHX = 0x00000008,
+@extension("VK_KHR_device_group") // 61
+type VkFlags VkMemoryAllocateFlagsKHR
+@extension("VK_KHR_device_group") // 61
+bitfield VkMemoryAllocateFlagBitsKHR {
+ VK_MEMORY_ALLOCATE_DEVICE_MASK_BIT_KHR = 0x00000001,
}
@extension("VK_NN_vi_surface") // 63
@@ -2020,45 +2743,52 @@
//bitfield VkCommandPoolTrimFlagBitsKHR {
//}
-@extension("VK_KHX_external_memory_capabilities") // 72
-type VkFlags VkExternalMemoryHandleTypeFlagsKHX
-@extension("VK_KHX_external_memory_capabilities") // 72
-bitfield VkExternalMemoryHandleTypeFlagBitsKHX {
- VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHX = 0x00000001,
- VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHX = 0x00000002,
- VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHX = 0x00000004,
- VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT_KHX = 0x00000008,
- VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_KMT_BIT_KHX = 0x00000010,
- VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_HEAP_BIT_KHX = 0x00000020,
- VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_RESOURCE_BIT_KHX = 0x00000040,
+@extension("VK_KHR_external_memory_capabilities") // 72
+type VkFlags VkExternalMemoryHandleTypeFlagsKHR
+@extension("VK_KHR_external_memory_capabilities") // 72
+bitfield VkExternalMemoryHandleTypeFlagBitsKHR {
+ VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR = 0x00000001,
+ VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR = 0x00000002,
+ VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHR = 0x00000004,
+ VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT_KHR = 0x00000008,
+ VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_KMT_BIT_KHR = 0x00000010,
+ VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_HEAP_BIT_KHR = 0x00000020,
+ VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_RESOURCE_BIT_KHR = 0x00000040,
}
-@extension("VK_KHX_external_memory_capabilities") // 72
-type VkFlags VkExternalMemoryFeatureFlagsKHX
-@extension("VK_KHX_external_memory_capabilities") // 72
-bitfield VkExternalMemoryFeatureFlagBitsKHX {
- VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT_KHX = 0x00000001,
- VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT_KHX = 0x00000002,
- VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT_KHX = 0x00000004,
+@extension("VK_KHR_external_memory_capabilities") // 72
+type VkFlags VkExternalMemoryFeatureFlagsKHR
+@extension("VK_KHR_external_memory_capabilities") // 72
+bitfield VkExternalMemoryFeatureFlagBitsKHR {
+ VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT_KHR = 0x00000001,
+ VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT_KHR = 0x00000002,
+ VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT_KHR = 0x00000004,
}
-@extension("VK_KHX_external_semaphore_capabilities") // 77
-type VkFlags VkExternalSemaphoreHandleTypeFlagsKHX
-@extension("VK_KHX_external_semaphore_capabilities") // 77
-bitfield VkExternalSemaphoreHandleTypeFlagBitsKHX {
- VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT_KHX = 0x00000001
- VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHX = 0x00000002
- VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHX = 0x00000004
- VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT_KHX = 0x00000008
- VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_FENCE_FD_BIT_KHX = 0x00000010
+@extension("VK_KHR_external_semaphore_capabilities") // 77
+type VkFlags VkExternalSemaphoreHandleTypeFlagsKHR
+@extension("VK_KHR_external_semaphore_capabilities") // 77
+bitfield VkExternalSemaphoreHandleTypeFlagBitsKHR {
+ VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT_KHR = 0x00000001
+ VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR = 0x00000002
+ VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHR = 0x00000004
+ VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT_KHR = 0x00000008
+ VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_FENCE_FD_BIT_KHR = 0x00000010
}
-@extension("VK_KHX_external_semaphore_capabilities") // 77
-type VkFlags VkExternalSemaphoreFeatureFlagsKHX
-@extension("VK_KHX_external_semaphore_capabilities") // 77
-bitfield VkExternalSemaphoreFeatureFlagBitsKHX {
- VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT_KHX = 0x00000001,
- VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT_KHX = 0x00000002,
+@extension("VK_KHR_external_semaphore_capabilities") // 77
+type VkFlags VkExternalSemaphoreFeatureFlagsKHR
+@extension("VK_KHR_external_semaphore_capabilities") // 77
+bitfield VkExternalSemaphoreFeatureFlagBitsKHR {
+ VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT_KHR = 0x00000001,
+ VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT_KHR = 0x00000002,
+}
+
+@extension("VK_KHR_external_semaphore") // 78
+type VkFlags VkSemaphoreImportFlagsKHR
+@extension("VK_KHR_external_semaphore") // 78
+bitfield VkSemaphoreImportFlagBitsKHR {
+ VK_SEMAPHORE_IMPORT_TEMPORARY_BIT_KHR = 0x00000001,
}
@extension("VK_KHR_descriptor_update_template") // 86
@@ -2104,6 +2834,31 @@
//bitfield VkPipelineDiscardRectangleStateCreateFlagBitsEXT {
//}
+@extension("VK_KHR_external_fence_capabilities") // 113
+type VkFlags VkExternalFenceHandleTypeFlagsKHR
+@extension("VK_KHR_external_fence_capabilities") // 113
+bitfield VkExternalFenceHandleTypeFlagBitsKHR {
+ VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT_KHR = 0x00000001,
+ VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR = 0x00000002,
+ VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHR = 0x00000004,
+ VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT_KHR = 0x00000008,
+}
+
+@extension("VK_KHR_external_fence_capabilities") // 113
+type VkFlags VkExternalFenceFeatureFlagsKHR
+@extension("VK_KHR_external_fence_capabilities") // 113
+bitfield VkExternalFenceFeatureFlagBitsKHR {
+ VK_EXTERNAL_FENCE_FEATURE_EXPORTABLE_BIT_KHR = 0x00000001,
+ VK_EXTERNAL_FENCE_FEATURE_IMPORTABLE_BIT_KHR = 0x00000002,
+}
+
+@extension("VK_KHR_external_fence") // 114
+type VkFlags VkFenceImportFlagsKHR
+@extension("VK_KHR_external_fence") // 114
+bitfield VkFenceImportFlagBitsKHR {
+ VK_FENCE_IMPORT_TEMPORARY_BIT_KHR = 0x00000001,
+}
+
@extension("VK_MVK_ios_surface") // 123
type VkFlags VkIOSSurfaceCreateFlagsMVK
//@extension("VK_MVK_ios_surface") // 123
@@ -2116,6 +2871,24 @@
//bitfield VkMacOSSurfaceCreateFlagBitsMVK {
//}
+@extension("VK_NV_fragment_coverage_to_color") // 150
+type VkFlags VkPipelineCoverageToColorStateCreateFlagsNV
+@extension("VK_NV_fragment_coverage_to_color") // 150
+//bitfield VkPipelineCoverageToColorStateCreateFlagBitsNV {
+//}
+
+@extension("VK_NV_framebuffer_mixed_samples") // 153
+type VkFlags VkPipelineCoverageModulationStateCreateFlagsNV
+@extension("VK_NV_framebuffer_mixed_samples") // 153
+//bitfield VkPipelineCoverageModulationStateCreateFlagBitsNV {
+//}
+
+@extension("VK_EXT_validation_cache") // 161
+type VkFlags VkValidationCacheCreateFlagsEXT
+@extension("VK_EXT_validation_cache") // 161
+//bitfield VkValidationCacheCreateFlagBitsEXT {
+//}
+
//////////////////
// Structures //
//////////////////
@@ -3220,6 +3993,493 @@
u32 z
}
+//@vulkan1_1 structures
+
+class VkPhysicalDeviceSubgroupProperties {
+ VkStructureType sType
+ void* pNext
+ u32 subgroupSize
+ VkShaderStageFlags supportedStages
+ VkSubgroupFeatureFlags supportedOperations
+ VkBool32 quadOperationsInAllStages
+}
+
+class VkBindBufferMemoryInfo {
+ VkStructureType sType
+ const void* pNext
+ VkBuffer buffer
+ VkDeviceMemory memory
+ VkDeviceSize memoryOffset
+}
+
+class VkBindImageMemoryInfo {
+ VkStructureType sType
+ const void* pNext
+ VkImage image
+ VkDeviceMemory memory
+ VkDeviceSize memoryOffset
+}
+
+class VkPhysicalDevice16BitStorageFeatures {
+ VkStructureType sType
+ void* pNext
+ VkBool32 storageBuffer16BitAccess
+ VkBool32 uniformAndStorageBuffer16BitAccess
+ VkBool32 storagePushConstant16
+ VkBool32 storageInputOutput16
+}
+
+class VkMemoryDedicatedRequirements {
+ VkStructureType sType
+ void* pNext
+ VkBool32 prefersDedicatedAllocation
+ VkBool32 requiresDedicatedAllocation
+}
+
+class VkMemoryDedicatedAllocateInfo {
+ VkStructureType sType
+ const void* pNext
+ VkImage image
+ VkBuffer buffer
+}
+
+class VkMemoryAllocateFlagsInfo {
+ VkStructureType sType
+ const void* pNext
+ VkMemoryAllocateFlags flags
+ u32 deviceMask
+}
+
+class VkDeviceGroupRenderPassBeginInfo {
+ VkStructureType sType
+ const void* pNext
+ u32 deviceMask
+ u32 deviceRenderAreaCount
+ const VkRect2D* pDeviceRenderAreas
+}
+
+class VkDeviceGroupCommandBufferBeginInfo {
+ VkStructureType sType
+ const void* pNext
+ u32 deviceMask
+}
+
+class VkDeviceGroupSubmitInfo {
+ VkStructureType sType
+ const void* pNext
+ u32 waitSemaphoreCount
+ const u32* pWaitSemaphoreDeviceIndices
+ u32 commandBufferCount
+ const u32* pCommandBufferDeviceMasks
+ u32 signalSemaphoreCount
+ const u32* pSignalSemaphoreDeviceIndices
+}
+
+class VkDeviceGroupBindSparseInfo {
+ VkStructureType sType
+ const void* pNext
+ u32 resourceDeviceIndex
+ u32 memoryDeviceIndex
+}
+
+class VkBindBufferMemoryDeviceGroupInfo {
+ VkStructureType sType
+ const void* pNext
+ u32 deviceIndexCount
+ const u32* pDeviceIndices
+}
+
+class VkBindImageMemoryDeviceGroupInfo {
+ VkStructureType sType
+ const void* pNext
+ u32 deviceIndexCount
+ const u32* pDeviceIndices
+ u32 SFRRectCount
+ const VkRect2D* pSFRRects
+}
+
+class VkPhysicalDeviceGroupProperties {
+ VkStructureType sType
+ void* pNext
+ u32 physicalDeviceCount
+ VkPhysicalDevice[VK_MAX_DEVICE_GROUP_SIZE] physicalDevices
+ VkBool32 subsetAllocation
+}
+
+class VkDeviceGroupDeviceCreateInfo {
+ VkStructureType sType
+ const void* pNext
+ u32 physicalDeviceCount
+ const VkPhysicalDevice* pPhysicalDevices
+}
+
+class VkBufferMemoryRequirementsInfo2 {
+ VkStructureType sType
+ const void* pNext
+ VkBuffer buffer
+}
+
+class VkImageMemoryRequirementsInfo2 {
+ VkStructureType sType
+ const void* pNext
+ VkImage image
+}
+
+class VkImageSparseMemoryRequirementsInfo2 {
+ VkStructureType sType
+ const void* pNext
+ VkImage image
+}
+
+class VkMemoryRequirements2 {
+ VkStructureType sType
+ void* pNext
+ VkMemoryRequirements memoryRequirements
+}
+
+class VkSparseImageMemoryRequirements2 {
+ VkStructureType sType
+ void* pNext
+ VkSparseImageMemoryRequirements memoryRequirements
+}
+
+class VkPhysicalDeviceFeatures2 {
+ VkStructureType sType
+ void* pNext
+ VkPhysicalDeviceFeatures features
+}
+
+class VkPhysicalDeviceProperties2 {
+ VkStructureType sType
+ void* pNext
+ VkPhysicalDeviceProperties properties
+}
+
+class VkFormatProperties2 {
+ VkStructureType sType
+ void* pNext
+ VkFormatProperties formatProperties
+}
+
+class VkImageFormatProperties2 {
+ VkStructureType sType
+ void* pNext
+ VkImageFormatProperties imageFormatProperties
+}
+
+class VkPhysicalDeviceImageFormatInfo2 {
+ VkStructureType sType
+ const void* pNext
+ VkFormat format
+ VkImageType type
+ VkImageTiling tiling
+ VkImageUsageFlags usage
+ VkImageCreateFlags flags
+}
+
+class VkQueueFamilyProperties2 {
+ VkStructureType sType
+ void* pNext
+ VkQueueFamilyProperties queueFamilyProperties
+}
+
+class VkPhysicalDeviceMemoryProperties2 {
+ VkStructureType sType
+ void* pNext
+ VkPhysicalDeviceMemoryProperties memoryProperties
+}
+
+class VkSparseImageFormatProperties2 {
+ VkStructureType sType
+ void* pNext
+ VkSparseImageFormatProperties properties
+}
+
+class VkPhysicalDeviceSparseImageFormatInfo2 {
+ VkStructureType sType
+ const void* pNext
+ VkFormat format
+ VkImageType type
+ VkSampleCountFlagBits samples
+ VkImageUsageFlags usage
+ VkImageTiling tiling
+}
+
+class VkPhysicalDevicePointClippingProperties {
+ VkStructureType sType
+ void* pNext
+ VkPointClippingBehavior pointClippingBehavior
+}
+
+class VkInputAttachmentAspectReference {
+ u32 subpass
+ u32 inputAttachmentIndex
+ VkImageAspectFlags aspectMask
+}
+
+class VkRenderPassInputAttachmentAspectCreateInfo {
+ VkStructureType sType
+ const void* pNext
+ u32 aspectReferenceCount
+ const VkInputAttachmentAspectReference* pAspectReferences
+}
+
+class VkImageViewUsageCreateInfo {
+ VkStructureType sType
+ const void* pNext
+ VkImageUsageFlags usage
+}
+
+class VkPipelineTessellationDomainOriginStateCreateInfo {
+ VkStructureType sType
+ const void* pNext
+ VkTessellationDomainOrigin domainOrigin
+}
+
+class VkRenderPassMultiviewCreateInfo {
+ VkStructureType sType
+ const void* pNext
+ u32 subpassCount
+ const u32* pViewMasks
+ u32 dependencyCount
+ const s32* pViewOffsets
+ u32 correlationMaskCount
+ const u32* pCorrelationMasks
+}
+
+class VkPhysicalDeviceMultiviewFeatures {
+ VkStructureType sType
+ void* pNext
+ VkBool32 multiview
+ VkBool32 multiviewGeometryShader
+ VkBool32 multiviewTessellationShader
+}
+
+class VkPhysicalDeviceMultiviewProperties {
+ VkStructureType sType
+ void* pNext
+ u32 maxMultiviewViewCount
+ u32 maxMultiviewInstanceIndex
+}
+
+class VkPhysicalDeviceVariablePointerFeatures {
+ VkStructureType sType
+ void* pNext
+ VkBool32 variablePointersStorageBuffer
+ VkBool32 variablePointers
+}
+
+class VkPhysicalDeviceProtectedMemoryFeatures {
+ VkStructureType sType
+ void* pNext
+ VkBool32 protectedMemory
+}
+
+class VkPhysicalDeviceProtectedMemoryProperties {
+ VkStructureType sType
+ void* pNext
+ VkBool32 protectedNoFault
+}
+
+class VkDeviceQueueInfo2 {
+ VkStructureType sType
+ const void* pNext
+ VkDeviceQueueCreateFlags flags
+ u32 queueFamilyIndex
+ u32 queueIndex
+}
+
+class VkProtectedSubmitInfo {
+ VkStructureType sType
+ const void* pNext
+ VkBool32 protectedSubmit
+}
+
+class VkSamplerYcbcrConversionCreateInfo {
+ VkStructureType sType
+ const void* pNext
+ VkFormat format
+ VkSamplerYcbcrModelConversion ycbcrModel
+ VkSamplerYcbcrRange ycbcrRange
+ VkComponentMapping components
+ VkChromaLocation xChromaOffset
+ VkChromaLocation yChromaOffset
+ VkFilter chromaFilter
+ VkBool32 forceExplicitReconstruction
+}
+
+class VkSamplerYcbcrConversionInfo {
+ VkStructureType sType
+ const void* pNext
+ VkSamplerYcbcrConversion conversion
+}
+
+class VkBindImagePlaneMemoryInfo {
+ VkStructureType sType
+ const void* pNext
+ VkImageAspectFlagBits planeAspect
+}
+
+class VkImagePlaneMemoryRequirementsInfo {
+ VkStructureType sType
+ const void* pNext
+ VkImageAspectFlagBits planeAspect
+}
+
+class VkPhysicalDeviceSamplerYcbcrConversionFeatures {
+ VkStructureType sType
+ void* pNext
+ VkBool32 samplerYcbcrConversion
+}
+
+class VkSamplerYcbcrConversionImageFormatProperties {
+ VkStructureType sType
+ void* pNext
+ u32 combinedImageSamplerDescriptorCount
+}
+
+class VkDescriptorUpdateTemplateEntry {
+ u32 dstBinding
+ u32 dstArrayElement
+ u32 descriptorCount
+ VkDescriptorType descriptorType
+ platform.size_t offset
+ platform.size_t stride
+}
+
+class VkDescriptorUpdateTemplateCreateInfo {
+ VkStructureType sType
+ void* pNext
+ VkDescriptorUpdateTemplateCreateFlags flags
+ u32 descriptorUpdateEntryCount
+ const VkDescriptorUpdateTemplateEntry* pDescriptorUpdateEntries
+ VkDescriptorUpdateTemplateType templateType
+ VkDescriptorSetLayout descriptorSetLayout
+ VkPipelineBindPoint pipelineBindPoint
+ VkPipelineLayout pipelineLayout
+ u32 set
+}
+
+class VkExternalMemoryProperties {
+ VkExternalMemoryFeatureFlags externalMemoryFeatures
+ VkExternalMemoryHandleTypeFlags exportFromImportedHandleTypes
+ VkExternalMemoryHandleTypeFlags compatibleHandleTypes
+}
+
+class VkPhysicalDeviceExternalImageFormatInfo {
+ VkStructureType sType
+ const void* pNext
+ VkExternalMemoryHandleTypeFlagBits handleType
+}
+
+class VkExternalImageFormatProperties {
+ VkStructureType sType
+ void* pNext
+ VkExternalMemoryProperties externalMemoryProperties
+}
+
+class VkPhysicalDeviceExternalBufferInfo {
+ VkStructureType sType
+ const void* pNext
+ VkBufferCreateFlags flags
+ VkBufferUsageFlags usage
+ VkExternalMemoryHandleTypeFlagBits handleType
+}
+
+class VkExternalBufferProperties {
+ VkStructureType sType
+ void* pNext
+ VkExternalMemoryProperties externalMemoryProperties
+}
+
+class VkPhysicalDeviceIDProperties {
+ VkStructureType sType
+ void* pNext
+ u8[VK_UUID_SIZE] deviceUUID
+ u8[VK_UUID_SIZE] driverUUID
+ u8[VK_LUID_SIZE] deviceLUID
+ u32 deviceNodeMask
+ VkBool32 deviceLUIDValid
+}
+
+class VkExternalMemoryImageCreateInfo {
+ VkStructureType sType
+ const void* pNext
+ VkExternalMemoryHandleTypeFlags handleTypes
+}
+
+class VkExternalMemoryBufferCreateInfo {
+ VkStructureType sType
+ const void* pNext
+ VkExternalMemoryHandleTypeFlags handleTypes
+}
+
+class VkExportMemoryAllocateInfo {
+ VkStructureType sType
+ const void* pNext
+ VkExternalMemoryHandleTypeFlags handleTypes
+}
+
+class VkPhysicalDeviceExternalFenceInfo {
+ VkStructureType sType
+ const void* pNext
+ VkExternalFenceHandleTypeFlagBits handleType
+}
+
+class VkExternalFenceProperties {
+ VkStructureType sType
+ void* pNext
+ VkExternalFenceHandleTypeFlags exportFromImportedHandleTypes
+ VkExternalFenceHandleTypeFlags compatibleHandleTypes
+ VkExternalFenceFeatureFlags externalFenceFeatures
+}
+
+class VkExportFenceCreateInfo {
+ VkStructureType sType
+ const void* pNext
+ VkExternalFenceHandleTypeFlags handleTypes
+}
+
+class VkExportSemaphoreCreateInfo {
+ VkStructureType sType
+ const void* pNext
+ VkExternalSemaphoreHandleTypeFlags handleTypes
+}
+
+class VkPhysicalDeviceExternalSemaphoreInfo {
+ VkStructureType sType
+ const void* pNext
+ VkExternalSemaphoreHandleTypeFlagBits handleType
+}
+
+class VkExternalSemaphoreProperties {
+ VkStructureType sType
+ void* pNext
+ VkExternalSemaphoreHandleTypeFlags exportFromImportedHandleTypes
+ VkExternalSemaphoreHandleTypeFlags compatibleHandleTypes
+ VkExternalSemaphoreFeatureFlags externalSemaphoreFeatures
+}
+
+class VkPhysicalDeviceMaintenance3Properties {
+ VkStructureType sType
+ void* pNext
+ u32 maxPerSetDescriptors
+ VkDeviceSize maxMemoryAllocationSize
+}
+
+class VkDescriptorSetLayoutSupport {
+ VkStructureType sType
+ void* pNext
+ VkBool32 supported
+}
+
+class VkPhysicalDeviceShaderDrawParameterFeatures {
+ VkStructureType sType
+ void* pNext
+ VkBool32 shaderDrawParameters
+}
+
+
@extension("VK_KHR_surface") // 1
class VkSurfaceCapabilitiesKHR {
u32 minImageCount
@@ -3274,6 +4534,62 @@
VkResult* pResults
}
+@vulkan1_1
+@extension("VK_KHR_swapchain") // 2
+class VkImageSwapchainCreateInfoKHR {
+ VkStructureType sType
+ const void* pNext
+ VkSwapchainKHR swapchain
+}
+
+@vulkan1_1
+@extension("VK_KHR_swapchain") // 2
+class VkBindImageMemorySwapchainInfoKHR {
+ VkStructureType sType
+ const void* pNext
+ VkSwapchainKHR swapchain
+ u32 imageIndex
+}
+
+@vulkan1_1
+@extension("VK_KHR_swapchain") // 2
+class VkAcquireNextImageInfoKHR {
+ VkStructureType sType
+ const void* pNext
+ VkSwapchainKHR swapchain
+ u64 timeout
+ VkSemaphore semaphore
+ VkFence fence
+ u32 deviceMask
+}
+
+@vulkan1_1
+@extension("VK_KHR_swapchain") // 2
+class VkDeviceGroupPresentCapabilitiesKHR {
+ VkStructureType sType
+ const void* pNext
+ u32[VK_MAX_DEVICE_GROUP_SIZE] presentMask
+ VkDeviceGroupPresentModeFlagsKHR modes
+}
+
+@vulkan1_1
+@extension("VK_KHR_swapchain") // 2
+class VkDeviceGroupPresentInfoKHR {
+ VkStructureType sType
+ const void* pNext
+ u32 swapchainCount
+ const u32* pDeviceMasks
+ VkDeviceGroupPresentModeFlagBitsKHR mode
+}
+
+@vulkan1_1
+@extension("VK_KHR_swapchain") // 2
+class VkDeviceGroupSwapchainCreateInfoKHR {
+ VkStructureType sType
+ const void* pNext
+ VkDeviceGroupPresentModeFlagsKHR modes
+}
+
@extension("VK_KHR_display") // 3
class VkDisplayPropertiesKHR {
VkDisplayKHR display
@@ -3497,8 +4813,15 @@
VkBuffer buffer
}
-@extension("VK_KHX_multiview") // 54
-class VkRenderPassMultiviewCreateInfoKHX {
+@extension("VK_AMD_texture_gather_bias_lod") // 42
+class VkTextureLODGatherFormatPropertiesAMD {
+ VkStructureType sType
+ void* pNext
+ VkBool32 supportsTextureGatherLODBiasAMD
+}
+
+@extension("VK_KHR_multiview") // 54
+class VkRenderPassMultiviewCreateInfoKHR {
VkStructureType sType
const void* pNext
u32 subpassCount
@@ -3509,8 +4832,8 @@
const u32* pCorrelationMasks
}
-@extension("VK_KHX_multiview") // 54
-class VkPhysicalDeviceMultiviewFeaturesKHX {
+@extension("VK_KHR_multiview") // 54
+class VkPhysicalDeviceMultiviewFeaturesKHR {
VkStructureType sType
void* pNext
VkBool32 multiview
@@ -3518,8 +4841,8 @@
VkBool32 multiviewTessellationShader
}
-@extension("VK_KHX_multiview") // 54
-class VkPhysicalDeviceMultiviewPropertiesKHX {
+@extension("VK_KHR_multiview") // 54
+class VkPhysicalDeviceMultiviewPropertiesKHR {
VkStructureType sType
void* pNext
u32 maxMultiviewViewCount
@@ -3648,40 +4971,34 @@
VkImageTiling tiling
}
-@extension("VK_KHX_device_group") // 61
-class VkMemoryAllocateFlagsInfoKHX {
+@extension("VK_KHR_device_group") // 61
+class VkMemoryAllocateFlagsInfoKHR {
VkStructureType sType
const void* pNext
- VkMemoryAllocateFlagsKHX flags
+ VkMemoryAllocateFlagsKHR flags
u32 deviceMask
}
-@extension("VK_KHX_device_group") // 61
-class VkBindBufferMemoryInfoKHX {
+@extension("VK_KHR_device_group") // 61
+class VkBindBufferMemoryDeviceGroupInfoKHR {
VkStructureType sType
const void* pNext
- VkBuffer buffer
- VkDeviceMemory memory
- VkDeviceSize memoryOffset
u32 deviceIndexCount
const u32* pDeviceIndices
}
-@extension("VK_KHX_device_group") // 61
-class VkBindImageMemoryInfoKHX {
+@extension("VK_KHR_device_group") // 61
+class VkBindImageMemoryDeviceGroupInfoKHR {
VkStructureType sType
const void* pNext
- VkImage image
- VkDeviceMemory memory
- VkDeviceSize memoryOffset
u32 deviceIndexCount
const u32* pDeviceIndices
u32 SFRRectCount
const VkRect2D* pSFRRects
}
-@extension("VK_KHX_device_group") // 61
-class VkDeviceGroupRenderPassBeginInfoKHX {
+@extension("VK_KHR_device_group") // 61
+class VkDeviceGroupRenderPassBeginInfoKHR {
VkStructureType sType
const void* pNext
u32 deviceMask
@@ -3689,15 +5006,15 @@
const VkRect2D* pDeviceRenderAreas
}
-@extension("VK_KHX_device_group") // 61
-class VkDeviceGroupCommandBufferBeginInfoKHX {
+@extension("VK_KHR_device_group") // 61
+class VkDeviceGroupCommandBufferBeginInfoKHR {
VkStructureType sType
const void* pNext
u32 deviceMask
}
-@extension("VK_KHX_device_group") // 61
-class VkDeviceGroupSubmitInfoKHX {
+@extension("VK_KHR_device_group") // 61
+class VkDeviceGroupSubmitInfoKHR {
VkStructureType sType
const void* pNext
u32 waitSemaphoreCount
@@ -3708,64 +5025,14 @@
const u32* pSignalSemaphoreDeviceIndices
}
-@extension("VK_KHX_device_group") // 61
-class VkDeviceGroupBindSparseInfoKHX {
+@extension("VK_KHR_device_group") // 61
+class VkDeviceGroupBindSparseInfoKHR {
VkStructureType sType
const void* pNext
u32 resourceDeviceIndex
u32 memoryDeviceIndex
}
-@extension("VK_KHX_device_group") // 61
-class VkDeviceGroupPresentCapabilitiesKHX {
- VkStructureType sType
- const void* pNext
- u32[VK_MAX_DEVICE_GROUP_SIZE_KHX] presentMask
- VkDeviceGroupPresentModeFlagsKHX modes
-}
-
-@extension("VK_KHX_device_group") // 61
-class VkImageSwapchainCreateInfoKHX {
- VkStructureType sType
- const void* pNext
- VkSwapchainKHR swapchain
-}
-
-@extension("VK_KHX_device_group") // 61
-class VkBindImageMemorySwapchainInfoKHX {
- VkStructureType sType
- const void* pNext
- VkSwapchainKHR swapchain
- u32 imageIndex
-}
-
-@extension("VK_KHX_device_group") // 61
-class VkAcquireNextImageInfoKHX {
- VkStructureType sType
- const void* pNext
- VkSwapchainKHR swapchain
- u64 timeout
- VkSemaphore semaphore
- VkFence fence
- u32 deviceMask
-}
-
-@extension("VK_KHX_device_group") // 61
-class VkDeviceGroupPresentInfoKHX {
- VkStructureType sType
- const void* pNext
- u32 swapchainCount
- const u32* pDeviceMasks
- VkDeviceGroupPresentModeFlagBitsKHX mode
-}
-
-@extension("VK_KHX_device_group") // 61
-class VkDeviceGroupSwapchainCreateInfoKHX {
- VkStructureType sType
- const void* pNext
- VkDeviceGroupPresentModeFlagsKHX modes
-}
-
@extension("VK_EXT_validation_flags") // 62
class VkValidationFlagsEXT {
VkStructureType sType
@@ -3782,101 +5049,103 @@
void* window
}
-@extension("VK_KHX_device_group_creation") // 71
-class VkPhysicalDeviceGroupPropertiesKHX {
+@extension("VK_KHR_device_group_creation") // 71
+class VkPhysicalDeviceGroupPropertiesKHR {
VkStructureType sType
void* pNext
u32 physicalDeviceCount
- VkPhysicalDevice[VK_MAX_DEVICE_GROUP_SIZE_KHX] physicalDevices
+ VkPhysicalDevice[VK_MAX_DEVICE_GROUP_SIZE] physicalDevices
VkBool32 subsetAllocation
}
-@extension("VK_KHX_device_group_creation") // 71
-class VkDeviceGroupDeviceCreateInfoKHX {
+@extension("VK_KHR_device_group_creation") // 71
+class VkDeviceGroupDeviceCreateInfoKHR {
VkStructureType sType
const void* pNext
u32 physicalDeviceCount
const VkPhysicalDevice* pPhysicalDevices
}
-@extension("VK_KHX_external_memory_capabilities") // 72
-class VkExternalMemoryPropertiesKHX {
- VkExternalMemoryFeatureFlagsKHX externalMemoryFeatures
- VkExternalMemoryHandleTypeFlagsKHX exportFromImportedHandleTypes
- VkExternalMemoryHandleTypeFlagsKHX compatibleHandleTypes
+@extension("VK_KHR_external_memory_capabilities") // 72
+class VkExternalMemoryPropertiesKHR {
+ VkExternalMemoryFeatureFlagsKHR externalMemoryFeatures
+ VkExternalMemoryHandleTypeFlagsKHR exportFromImportedHandleTypes
+ VkExternalMemoryHandleTypeFlagsKHR compatibleHandleTypes
}
-@extension("VK_KHX_external_memory_capabilities") // 72
-class VkPhysicalDeviceExternalImageFormatInfoKHX {
+@extension("VK_KHR_external_memory_capabilities") // 72
+class VkPhysicalDeviceExternalImageFormatInfoKHR {
VkStructureType sType
const void* pNext
- VkExternalMemoryHandleTypeFlagBitsKHX handleType
+ VkExternalMemoryHandleTypeFlagBitsKHR handleType
}
-@extension("VK_KHX_external_memory_capabilities") // 72
-class VkExternalImageFormatPropertiesKHX {
+@extension("VK_KHR_external_memory_capabilities") // 72
+class VkExternalImageFormatPropertiesKHR {
VkStructureType sType
void* pNext
- VkExternalMemoryPropertiesKHX externalMemoryProperties
+ VkExternalMemoryPropertiesKHR externalMemoryProperties
}
-@extension("VK_KHX_external_memory_capabilities") // 72
-class VkPhysicalDeviceExternalBufferInfoKHX {
+@extension("VK_KHR_external_memory_capabilities") // 72
+class VkPhysicalDeviceExternalBufferInfoKHR {
VkStructureType sType
const void* pNext
VkBufferCreateFlags flags
VkBufferUsageFlags usage
- VkExternalMemoryHandleTypeFlagBitsKHX handleType
+ VkExternalMemoryHandleTypeFlagBitsKHR handleType
}
-@extension("VK_KHX_external_memory_capabilities") // 72
-class VkExternalBufferPropertiesKHX {
+@extension("VK_KHR_external_memory_capabilities") // 72
+class VkExternalBufferPropertiesKHR {
VkStructureType sType
void* pNext
- VkExternalMemoryPropertiesKHX externalMemoryProperties
+ VkExternalMemoryPropertiesKHR externalMemoryProperties
}
-@extension("VK_KHX_external_memory_capabilities") // 72
-class VkPhysicalDeviceIDPropertiesKHX {
+@extension("VK_KHR_external_memory_capabilities") // 72
+class VkPhysicalDeviceIDPropertiesKHR {
VkStructureType sType
void* pNext
u8[VK_UUID_SIZE] deviceUUID
u8[VK_UUID_SIZE] driverUUID
- u8[VK_LUID_SIZE_KHX] deviceLUID
+ u8[VK_LUID_SIZE] deviceLUID
+ u32 deviceNodeMask
VkBool32 deviceLUIDValid
}
-@extension("VK_KHX_external_memory") // 73
-class VkExternalMemoryImageCreateInfoKHX {
+@extension("VK_KHR_external_memory") // 73
+class VkExternalMemoryImageCreateInfoKHR {
VkStructureType sType
const void* pNext
- VkExternalMemoryHandleTypeFlagsKHX handleTypes
+ VkExternalMemoryHandleTypeFlagsKHR handleTypes
}
-@extension("VK_KHX_external_memory") // 73
-class VkExternalMemoryBufferCreateInfoKHX {
+@extension("VK_KHR_external_memory") // 73
+class VkExternalMemoryBufferCreateInfoKHR {
VkStructureType sType
const void* pNext
- VkExternalMemoryHandleTypeFlagsKHX handleTypes
+ VkExternalMemoryHandleTypeFlagsKHR handleTypes
}
-@extension("VK_KHX_external_memory") // 73
-class VkExportMemoryAllocateInfoKHX {
+@extension("VK_KHR_external_memory") // 73
+class VkExportMemoryAllocateInfoKHR {
VkStructureType sType
const void* pNext
- VkExternalMemoryHandleTypeFlagsKHX handleTypes
+ VkExternalMemoryHandleTypeFlagsKHR handleTypes
}
-@extension("VK_KHX_external_memory_win32") // 74
-class VkImportMemoryWin32HandleInfoKHX {
+@extension("VK_KHR_external_memory_win32") // 74
+class VkImportMemoryWin32HandleInfoKHR {
VkStructureType sType
const void* pNext
- VkExternalMemoryHandleTypeFlagBitsKHX handleType
+ VkExternalMemoryHandleTypeFlagBitsKHR handleType
platform.HANDLE handle
+ platform.LPCWSTR name
}
-@extension("VK_KHX_external_memory_win32") // 74
-class VkExportMemoryWin32HandleInfoKHX {
+@extension("VK_KHR_external_memory_win32") // 74
+class VkExportMemoryWin32HandleInfoKHR {
VkStructureType sType
const void* pNext
const platform.SECURITY_ATTRIBUTES* pAttributes
@@ -3884,30 +5153,46 @@
platform.LPCWSTR name
}
-@extension("VK_KHX_external_memory_win32") // 74
-class VkMemoryWin32HandlePropertiesKHX {
+@extension("VK_KHR_external_memory_win32") // 74
+class VkMemoryWin32HandlePropertiesKHR {
VkStructureType sType
void* pNext
u32 memoryTypeBits
}
-@extension("VK_KHX_external_memory_fd") // 75
-class VkImportMemoryFdInfoKHX {
+@extension("VK_KHR_external_memory_win32") // 74
+class VkMemoryGetWin32HandleInfoKHR {
+ VkStructureType sType
+ void* pNext
+ VkDeviceMemory memory
+ VkExternalMemoryHandleTypeFlagBitsKHR handleType
+}
+
+@extension("VK_KHR_external_memory_fd") // 75
+class VkImportMemoryFdInfoKHR {
VkStructureType sType
const void* pNext
- VkExternalMemoryHandleTypeFlagBitsKHX handleType
+ VkExternalMemoryHandleTypeFlagBitsKHR handleType
int fd
}
-@extension("VK_KHX_external_memory_fd") // 75
-class VkMemoryFdPropertiesKHX {
+@extension("VK_KHR_external_memory_fd") // 75
+class VkMemoryFdPropertiesKHR {
VkStructureType sType
void* pNext
u32 memoryTypeBits
}
-@extension("VK_KHX_win32_keyed_mutex") // 76
-class VkWin32KeyedMutexAcquireReleaseInfoKHX {
+@extension("VK_KHR_external_memory_fd") // 75
+class VkMemoryGetFdInfoKHR {
+ VkStructureType sType
+ void* pNext
+ VkDeviceMemory memory
+ VkExternalMemoryHandleTypeFlagBitsKHR handleType
+}
+
+@extension("VK_KHR_win32_keyed_mutex") // 76
+class VkWin32KeyedMutexAcquireReleaseInfoKHR {
VkStructureType sType
const void* pNext
u32 acquireCount
@@ -3919,40 +5204,42 @@
const u64* pReleaseKeys
}
-@extension("VK_KHX_external_semaphore_capabilities") // 77
-class VkPhysicalDeviceExternalSemaphoreInfoKHX {
+@extension("VK_KHR_external_semaphore_capabilities") // 77
+class VkPhysicalDeviceExternalSemaphoreInfoKHR {
VkStructureType sType
const void* pNext
- VkExternalSemaphoreHandleTypeFlagBitsKHX handleType
+ VkExternalSemaphoreHandleTypeFlagBitsKHR handleType
}
-@extension("VK_KHX_external_semaphore_capabilities") // 77
-class VkExternalSemaphorePropertiesKHX {
+@extension("VK_KHR_external_semaphore_capabilities") // 77
+class VkExternalSemaphorePropertiesKHR {
VkStructureType sType
void* pNext
- VkExternalSemaphoreHandleTypeFlagsKHX exportFromImportedHandleTypes
- VkExternalSemaphoreHandleTypeFlagsKHX compatibleHandleTypes
- VkExternalSemaphoreFeatureFlagsKHX externalSemaphoreFeatures
+ VkExternalSemaphoreHandleTypeFlagsKHR exportFromImportedHandleTypes
+ VkExternalSemaphoreHandleTypeFlagsKHR compatibleHandleTypes
+ VkExternalSemaphoreFeatureFlagsKHR externalSemaphoreFeatures
}
-@extension("VK_KHX_external_semaphore") // 78
-class VkExportSemaphoreCreateInfoKHX {
+@extension("VK_KHR_external_semaphore") // 78
+class VkExportSemaphoreCreateInfoKHR {
VkStructureType sType
const void* pNext
- VkExternalSemaphoreHandleTypeFlagsKHX handleTypes
+ VkExternalSemaphoreHandleTypeFlagsKHR handleTypes
}
-@extension("VK_KHX_external_semaphore_win32") // 79
-class VkImportSemaphoreWin32HandleInfoKHX {
+@extension("VK_KHR_external_semaphore_win32") // 79
+class VkImportSemaphoreWin32HandleInfoKHR {
VkStructureType sType
const void* pNext
VkSemaphore semaphore
- VkExternalSemaphoreHandleTypeFlagsKHX handleType
+ VkSemaphoreImportFlagsKHR flags
+ VkExternalSemaphoreHandleTypeFlagsKHR handleType
platform.HANDLE handle
+ platform.LPCWSTR name
}
-@extension("VK_KHX_external_semaphore_win32") // 79
-class VkExportSemaphoreWin32HandleInfoKHX {
+@extension("VK_KHR_external_semaphore_win32") // 79
+class VkExportSemaphoreWin32HandleInfoKHR {
VkStructureType sType
const void* pNext
const platform.SECURITY_ATTRIBUTES* pAttributes
@@ -3960,8 +5247,8 @@
platform.LPCWSTR name
}
-@extension("VK_KHX_external_semaphore_win32") // 79
-class VkD3D12FenceSubmitInfoKHX {
+@extension("VK_KHR_external_semaphore_win32") // 79
+class VkD3D12FenceSubmitInfoKHR {
VkStructureType sType
const void* pNext
u32 waitSemaphoreValuesCount
@@ -3970,15 +5257,32 @@
const u64* pSignalSemaphoreValues
}
-@extension("VK_KHX_external_semaphore_fd") // 80
-class VkImportSemaphoreFdInfoKHX {
+@extension("VK_KHR_external_semaphore_win32") // 79
+class VkSemaphoreGetWin32HandleInfoKHR {
VkStructureType sType
const void* pNext
VkSemaphore semaphore
- VkExternalSemaphoreHandleTypeFlagBitsKHX handleType
+ VkExternalSemaphoreHandleTypeFlagBitsKHR handleType
+}
+
+@extension("VK_KHR_external_semaphore_fd") // 80
+class VkImportSemaphoreFdInfoKHR {
+ VkStructureType sType
+ const void* pNext
+ VkSemaphore semaphore
+ VkSemaphoreImportFlagsKHR flags
+ VkExternalSemaphoreHandleTypeFlagBitsKHR handleType
s32 fd
}
+@extension("VK_KHR_external_semaphore_fd") // 80
+class VkSemaphoreGetFdInfoKHR {
+ VkStructureType sType
+ const void* pNext
+ VkSemaphore semaphore
+ VkExternalSemaphoreHandleTypeFlagBitsKHR handleType
+}
+
@extension("VK_KHR_push_descriptor") // 81
class VkPhysicalDevicePushDescriptorPropertiesKHR {
VkStructureType sType
@@ -3986,6 +5290,16 @@
u32 maxPushDescriptors
}
+@extension("VK_KHR_16bit_storage") // 84
+class VkPhysicalDevice16BitStorageFeaturesKHR {
+ VkStructureType sType
+ void* pNext
+ VkBool32 storageBuffer16BitAccess
+ VkBool32 uniformAndStorageBuffer16BitAccess
+ VkBool32 storagePushConstant16
+ VkBool32 storageInputOutput16
+}
+
@extension("VK_KHR_incremental_present") // 85
class VkRectLayerKHR {
VkOffset2D offset
@@ -4314,6 +5628,111 @@
VkImageUsageFlags sharedPresentSupportedUsageFlags
}
+@extension("VK_KHR_external_fence_capabilities") // 113
+class VkPhysicalDeviceExternalFenceInfoKHR {
+ VkStructureType sType
+ const void* pNext
+ VkExternalFenceHandleTypeFlagBitsKHR handleType
+}
+
+@extension("VK_KHR_external_fence_capabilities") // 113
+class VkExternalFencePropertiesKHR {
+ VkStructureType sType
+ void* pNext
+ VkExternalFenceHandleTypeFlagsKHR exportFromImportedHandleTypes
+ VkExternalFenceHandleTypeFlagsKHR compatibleHandleTypes
+ VkExternalFenceFeatureFlagsKHR externalFenceFeatures
+}
+
+@extension("VK_KHR_external_fence") // 114
+class VkExportFenceCreateInfoKHR {
+ VkStructureType sType
+ const void* pNext
+ VkExternalFenceHandleTypeFlagsKHR handleTypes
+}
+
+@extension("VK_KHR_external_fence_win32") // 115
+class VkImportFenceWin32HandleInfoKHR {
+ VkStructureType sType
+ const void* pNext
+ VkFence fence
+ VkFenceImportFlagsKHR flags
+ VkExternalFenceHandleTypeFlagBitsKHR handleType
+ platform.HANDLE handle
+ platform.LPCWSTR name
+}
+
+@extension("VK_KHR_external_fence_win32") // 115
+class VkExportFenceWin32HandleInfoKHR {
+ VkStructureType sType
+ const void* pNext
+ const platform.SECURITY_ATTRIBUTES* pAttributes
+ platform.DWORD dwAccess
+ platform.LPCWSTR name
+}
+
+@extension("VK_KHR_external_fence_win32") // 115
+class VkFenceGetWin32HandleInfoKHR {
+ VkStructureType sType
+ const void* pNext
+ VkFence fence
+ VkExternalFenceHandleTypeFlagBitsKHR handleType
+}
+
+@extension("VK_KHR_external_fence_fd") // 116
+class VkImportFenceFdInfoKHR {
+ VkStructureType sType
+ const void* pNext
+ VkFence fence
+ VkFenceImportFlagsKHR flags
+ VkExternalFenceHandleTypeFlagBitsKHR handleType
+ int fd
+}
+
+@extension("VK_KHR_external_fence_fd") // 116
+class VkFenceGetFdInfoKHR {
+ VkStructureType sType
+ const void* pNext
+ VkFence fence
+ VkExternalFenceHandleTypeFlagBitsKHR handleType
+}
+
+@extension("VK_KHR_maintenance2") // 118
+class VkPhysicalDevicePointClippingPropertiesKHR {
+ VkStructureType sType
+ void* pNext
+ VkPointClippingBehaviorKHR pointClippingBehavior
+}
+
+@extension("VK_KHR_maintenance2") // 118
+class VkInputAttachmentAspectReferenceKHR {
+ u32 subpass
+ u32 inputAttachmentIndex
+ VkImageAspectFlags aspectMask
+}
+
+@extension("VK_KHR_maintenance2") // 118
+class VkRenderPassInputAttachmentAspectCreateInfoKHR {
+ VkStructureType sType
+ const void* pNext
+ u32 aspectReferenceCount
+ const VkInputAttachmentAspectReferenceKHR* pAspectReferences
+}
+
+@extension("VK_KHR_maintenance2") // 118
+class VkImageViewUsageCreateInfoKHR {
+ VkStructureType sType
+ const void* pNext
+ VkImageUsageFlags usage
+}
+
+@extension("VK_KHR_maintenance2") // 118
+class VkPipelineTessellationDomainOriginStateCreateInfoKHR {
+ VkStructureType sType
+ const void* pNext
+ VkTessellationDomainOriginKHR domainOrigin
+}
+
@extension("VK_KHR_get_surface_capabilities2") // 120
class VkPhysicalDeviceSurfaceInfo2KHR {
VkStructureType sType
@@ -4335,6 +5754,14 @@
VkSurfaceFormatKHR surfaceFormat
}
+@extension("VK_KHR_variable_pointers") // 121
+class VkPhysicalDeviceVariablePointerFeaturesKHR {
+ VkStructureType sType
+ void* pNext
+ VkBool32 variablePointersStorageBuffer
+ VkBool32 variablePointers
+}
+
@extension("VK_MVK_ios_surface") // 123
class VkIOSSurfaceCreateInfoMVK {
VkStructureType sType
@@ -4351,6 +5778,291 @@
const void* pView
}
+@extension("VK_KHR_dedicated_allocation") // 128
+class VkMemoryDedicatedRequirementsKHR {
+ VkStructureType sType
+ void* pNext
+ VkBool32 prefersDedicatedAllocation
+ VkBool32 requiresDedicatedAllocation
+}
+
+@extension("VK_KHR_dedicated_allocation") // 128
+class VkMemoryDedicatedAllocateInfoKHR {
+ VkStructureType sType
+ const void* pNext
+ VkImage image
+ VkBuffer buffer
+}
+
+@extension("VK_EXT_sampler_filter_minmax") // 131
+class VkSamplerReductionModeCreateInfoEXT {
+ VkStructureType sType
+ const void* pNext
+ VkSamplerReductionModeEXT reductionMode
+}
+
+@extension("VK_EXT_sampler_filter_minmax") // 131
+class VkPhysicalDeviceSamplerFilterMinmaxPropertiesEXT {
+ VkStructureType sType
+ void* pNext
+ VkBool32 filterMinmaxSingleComponentFormats
+ VkBool32 filterMinmaxImageComponentMapping
+}
+
+@extension("VK_EXT_sample_locations") // 144
+class VkSampleLocationEXT {
+ f32 x
+ f32 y
+}
+
+@extension("VK_EXT_sample_locations") // 144
+class VkSampleLocationsInfoEXT {
+ VkStructureType sType
+ const void* pNext
+ VkSampleCountFlagBits sampleLocationsPerPixel
+ VkExtent2D sampleLocationGridSize
+ u32 sampleLocationsCount
+ const VkSampleLocationEXT* pSampleLocations
+}
+
+@extension("VK_EXT_sample_locations") // 144
+class VkAttachmentSampleLocationsEXT {
+ u32 attachmentIndex
+ VkSampleLocationsInfoEXT sampleLocationsInfo
+}
+
+@extension("VK_EXT_sample_locations") // 144
+class VkSubpassSampleLocationsEXT {
+ u32 subpassIndex
+ VkSampleLocationsInfoEXT sampleLocationsInfo
+}
+
+@extension("VK_EXT_sample_locations") // 144
+class VkRenderPassSampleLocationsBeginInfoEXT {
+ VkStructureType sType
+ const void* pNext
+ u32 attachmentInitialSampleLocationsCount
+ const VkAttachmentSampleLocationsEXT* pAttachmentInitialSampleLocations
+ u32 postSubpassSampleLocationsCount
+ const VkSubpassSampleLocationsEXT* pSubpassSampleLocations
+}
+
+@extension("VK_EXT_sample_locations") // 144
+class VkPipelineSampleLocationsStateCreateInfoEXT {
+ VkStructureType sType
+ const void* pNext
+ VkBool32 sampleLocationsEnable
+ VkSampleLocationsInfoEXT sampleLocationsInfo
+}
+
+@extension("VK_EXT_sample_locations") // 144
+class VkPhysicalDeviceSampleLocationsPropertiesEXT {
+ VkStructureType sType
+ void* pNext
+ VkSampleCountFlags sampleLocationSampleCounts
+ VkExtent2D maxSampleLocationGridSize
+ f32[2] sampleLocationCoordinateRange
+ u32 sampleLocationSubPixelBits
+ VkBool32 variableSampleLocations
+}
+
+@extension("VK_EXT_sample_locations") // 144
+class VkMultisamplePropertiesEXT {
+ VkStructureType sType
+ void* pNext
+ VkExtent2D maxSampleLocationGridSize
+}
+
+@extension("VK_KHR_get_memory_requirements2") // 147
+class VkBufferMemoryRequirementsInfo2KHR {
+ VkStructureType sType
+ const void* pNext
+ VkBuffer buffer
+}
+
+@extension("VK_KHR_get_memory_requirements2") // 147
+class VkImageMemoryRequirementsInfo2KHR {
+ VkStructureType sType
+ const void* pNext
+ VkImage image
+}
+
+@extension("VK_KHR_get_memory_requirements2") // 147
+class VkImageSparseMemoryRequirementsInfo2KHR {
+ VkStructureType sType
+ const void* pNext
+ VkImage image
+}
+
+@extension("VK_KHR_get_memory_requirements2") // 147
+class VkMemoryRequirements2KHR {
+ VkStructureType sType
+ void* pNext
+ VkMemoryRequirements memoryRequirements
+}
+
+@extension("VK_KHR_get_memory_requirements2") // 147
+class VkSparseImageMemoryRequirements2KHR {
+ VkStructureType sType
+ void* pNext
+ VkSparseImageMemoryRequirements memoryRequirements
+}
+
+@extension("VK_KHR_image_format_list") // 148
+class VkImageFormatListCreateInfoKHR {
+ VkStructureType sType
+ const void* pNext
+ u32 viewFormatCount
+ const VkFormat* pViewFormats
+}
+
+@extension("VK_EXT_blend_operation_advanced") // 149
+class VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT {
+ VkStructureType sType
+ void* pNext
+ VkBool32 advancedBlendCoherentOperations
+}
+
+@extension("VK_EXT_blend_operation_advanced") // 149
+class VkPhysicalDeviceBlendOperationAdvancedPropertiesEXT {
+ VkStructureType sType
+ void* pNext
+ u32 advancedBlendMaxColorAttachments
+ VkBool32 advancedBlendIndependentBlend
+ VkBool32 advancedBlendNonPremultipliedSrcColor
+ VkBool32 advancedBlendNonPremultipliedDstColor
+ VkBool32 advancedBlendCorrelatedOverlap
+ VkBool32 advancedBlendAllOperations
+}
+
+@extension("VK_EXT_blend_operation_advanced") // 149
+class VkPipelineColorBlendAdvancedStateCreateInfoEXT {
+ VkStructureType sType
+ const void* pNext
+ VkBool32 srcPremultiplied
+ VkBool32 dstPremultiplied
+ VkBlendOverlapEXT blendOverlap
+}
+
+@extension("VK_NV_fragment_coverage_to_color") // 150
+class VkPipelineCoverageToColorStateCreateInfoNV {
+ VkStructureType sType
+ const void* pNext
+ VkPipelineCoverageToColorStateCreateFlagsNV flags
+ VkBool32 coverageToColorEnable
+ u32 coverageToColorLocation
+}
+
+@extension("VK_NV_framebuffer_mixed_samples") // 153
+class VkPipelineCoverageModulationStateCreateInfoNV {
+ VkStructureType sType
+ const void* pNext
+ VkPipelineCoverageModulationStateCreateFlagsNV flags
+ VkCoverageModulationModeNV coverageModulationMode
+ VkBool32 coverageModulationTableEnable
+ u32 coverageModulationTableCount
+ const f32* pCoverageModulationTable
+}
+
+@extension("VK_KHR_sampler_ycbcr_conversion") // 157
+class VkSamplerYcbcrConversionCreateInfoKHR {
+ VkStructureType sType
+ const void* pNext
+ VkFormat format
+ VkSamplerYcbcrModelConversionKHR ycbcrModel
+ VkSamplerYcbcrRangeKHR ycbcrRange
+ VkComponentMapping components
+ VkChromaLocationKHR xChromaOffset
+ VkChromaLocationKHR yChromaOffset
+ VkFilter chromaFilter
+ VkBool32 forceExplicitReconstruction
+}
+
+@extension("VK_KHR_sampler_ycbcr_conversion") // 157
+class VkSamplerYcbcrConversionInfoKHR {
+ VkStructureType sType
+ const void* pNext
+ VkSamplerYcbcrConversionKHR conversion
+}
+
+@extension("VK_KHR_sampler_ycbcr_conversion") // 157
+class VkBindImagePlaneMemoryInfoKHR {
+ VkStructureType sType
+ const void* pNext
+ VkImageAspectFlagBits planeAspect
+}
+
+@extension("VK_KHR_sampler_ycbcr_conversion") // 157
+class VkImagePlaneMemoryRequirementsInfoKHR {
+ VkStructureType sType
+ const void* pNext
+ VkImageAspectFlagBits planeAspect
+}
+
+@extension("VK_KHR_sampler_ycbcr_conversion") // 157
+class VkPhysicalDeviceSamplerYcbcrConversionFeaturesKHR {
+ VkStructureType sType
+ void* pNext
+ VkBool32 samplerYcbcrConversion
+}
+
+@extension("VK_KHR_sampler_ycbcr_conversion") // 157
+class VkSamplerYcbcrConversionImageFormatPropertiesKHR {
+ VkStructureType sType
+ void* pNext
+ u32 combinedImageSamplerDescriptorCount
+}
+
+@extension("VK_KHR_bind_memory2") // 158
+class VkBindBufferMemoryInfoKHR {
+ VkStructureType sType
+ const void* pNext
+ VkBuffer buffer
+ VkDeviceMemory memory
+ VkDeviceSize memoryOffset
+}
+
+@extension("VK_KHR_bind_memory2") // 158
+class VkBindImageMemoryInfoKHR {
+ VkStructureType sType
+ const void* pNext
+ VkImage image
+ VkDeviceMemory memory
+ VkDeviceSize memoryOffset
+}
+
+@extension("VK_EXT_validation_cache") // 161
+class VkValidationCacheCreateInfoEXT {
+ VkStructureType sType
+ const void* pNext
+ VkValidationCacheCreateFlagsEXT flags
+ platform.size_t initialDataSize
+ const void* pInitialData
+}
+
+@extension("VK_EXT_validation_cache") // 161
+class VkShaderModuleValidationCacheCreateInfoEXT {
+ VkStructureType sType
+ const void* pNext
+ VkValidationCacheEXT validationCache
+}
+
+@extension("VK_KHR_maintenance3") // 169
+class VkPhysicalDeviceMaintenance3PropertiesKHR {
+ VkStructureType sType
+ void* pNext
+ u32 maxPerSetDescriptors
+ VkDeviceSize maxMemoryAllocationSize
+}
+
+@extension("VK_KHR_maintenance3") // 169
+class VkDescriptorSetLayoutSupportKHR {
+ VkStructureType sType
+ void* pNext
+ VkBool32 supported
+}
+
+
////////////////
// Commands //
////////////////
@@ -6546,6 +8258,241 @@
}
}
+//@vulkan1_1 functions
+
+@vulkan1_1
+cmd VkResult vkEnumerateInstanceVersion(
+ u32* pApiVersion) {
+ return ?
+}
+
+@vulkan1_1
+cmd VkResult vkBindBufferMemory2(
+ VkDevice device,
+ u32 bindInfoCount,
+ const VkBindBufferMemoryInfo* pBindInfos) {
+ return ?
+}
+
+@vulkan1_1
+cmd VkResult vkBindImageMemory2(
+ VkDevice device,
+ u32 bindInfoCount,
+ const VkBindImageMemoryInfo* pBindInfos) {
+ return ?
+}
+
+@vulkan1_1
+cmd void vkGetDeviceGroupPeerMemoryFeatures(
+ VkDevice device,
+ u32 heapIndex,
+ u32 localDeviceIndex,
+ u32 remoteDeviceIndex,
+ VkPeerMemoryFeatureFlags* pPeerMemoryFeatures) {
+}
+
+@vulkan1_1
+cmd void vkCmdSetDeviceMask(
+ VkCommandBuffer commandBuffer,
+ u32 deviceMask) {
+}
+
+@vulkan1_1
+cmd void vkCmdDispatchBase(
+ VkCommandBuffer commandBuffer,
+ u32 baseGroupX,
+ u32 baseGroupY,
+ u32 baseGroupZ,
+ u32 groupCountX,
+ u32 groupCountY,
+ u32 groupCountZ) {
+}
+
+@threadSafety("system")
+@vulkan1_1
+cmd VkResult vkEnumeratePhysicalDeviceGroups(
+ VkInstance instance,
+ u32* pPhysicalDeviceGroupCount,
+ VkPhysicalDeviceGroupProperties* pPhysicalDeviceGroupProperties) {
+ instanceObject := GetInstance(instance)
+
+ physicalDeviceGroupCount := as!u32(?)
+ pPhysicalDeviceGroupCount[0] = physicalDeviceGroupCount
+ physicalDevices := pPhysicalDeviceGroupProperties[0:physicalDeviceGroupCount]
+
+ for i in (0 .. physicalDeviceGroupCount) {
+ physicalDevice := ?
+ physicalDevices[i] = physicalDevice
+ if !(physicalDevice in State.PhysicalDevices) {
+ State.PhysicalDevices[physicalDevice] = new!PhysicalDeviceObject(instance: instance)
+ }
+ }
+
+ return ?
+}
+
+@vulkan1_1
+cmd void vkGetImageMemoryRequirements2(
+ VkDevice device,
+ const VkImageMemoryRequirementsInfo2* pInfo,
+ VkMemoryRequirements2* pMemoryRequirements) {
+}
+
+@vulkan1_1
+cmd void vkGetBufferMemoryRequirements2(
+ VkDevice device,
+ const VkBufferMemoryRequirementsInfo2* pInfo,
+ VkMemoryRequirements2* pMemoryRequirements) {
+}
+
+@vulkan1_1
+cmd void vkGetImageSparseMemoryRequirements2(
+ VkDevice device,
+ const VkImageSparseMemoryRequirementsInfo2* pInfo,
+ u32* pSparseMemoryRequirementCount,
+ VkSparseImageMemoryRequirements2* pSparseMemoryRequirements) {
+}
+
+@vulkan1_1
+cmd void vkGetPhysicalDeviceFeatures2(
+ VkPhysicalDevice physicalDevice,
+ VkPhysicalDeviceFeatures2* pFeatures) {
+}
+
+@vulkan1_1
+cmd void vkGetPhysicalDeviceProperties2(
+ VkPhysicalDevice physicalDevice,
+ VkPhysicalDeviceProperties2* pProperties) {
+}
+
+@vulkan1_1
+cmd void vkGetPhysicalDeviceFormatProperties2(
+ VkPhysicalDevice physicalDevice,
+ VkFormat format,
+ VkFormatProperties2* pFormatProperties) {
+}
+
+@vulkan1_1
+cmd VkResult vkGetPhysicalDeviceImageFormatProperties2(
+ VkPhysicalDevice physicalDevice,
+ const VkPhysicalDeviceImageFormatInfo2* pImageFormatInfo,
+ VkImageFormatProperties2* pImageFormatProperties) {
+ return ?
+}
+
+@vulkan1_1
+cmd void vkGetPhysicalDeviceQueueFamilyProperties2(
+ VkPhysicalDevice physicalDevice,
+ u32* pQueueFamilyPropertyCount,
+ VkQueueFamilyProperties2* pQueueFamilyProperties) {
+}
+
+@vulkan1_1
+cmd void vkGetPhysicalDeviceMemoryProperties2(
+ VkPhysicalDevice physicalDevice,
+ VkPhysicalDeviceMemoryProperties2* pMemoryProperties) {
+}
+
+@vulkan1_1
+cmd void vkGetPhysicalDeviceSparseImageFormatProperties2(
+ VkPhysicalDevice physicalDevice,
+ const VkPhysicalDeviceSparseImageFormatInfo2* pFormatInfo,
+ u32* pPropertyCount,
+ VkSparseImageFormatProperties2* pProperties) {
+}
+
+@vulkan1_1
+cmd void vkTrimCommandPool(
+ VkDevice device,
+ VkCommandPool commandPool,
+ VkCommandPoolTrimFlags flags) {
+}
+
+
+@vulkan1_1
+cmd void vkGetDeviceQueue2(
+ VkDevice device,
+ const VkDeviceQueueInfo2* pQueueInfo,
+ VkQueue* pQueue) {
+ deviceObject := GetDevice(device)
+
+ queue := ?
+ pQueue[0] = queue
+
+ if !(queue in State.Queues) {
+ State.Queues[queue] = new!QueueObject(device: device)
+ }
+}
+
+@vulkan1_1
+cmd VkResult vkCreateSamplerYcbcrConversion(
+ VkDevice device,
+ const VkSamplerYcbcrConversionCreateInfo* pCreateInfo,
+ const VkAllocationCallbacks* pAllocator,
+ VkSamplerYcbcrConversion* pYcbcrConversion) {
+ return ?
+}
+
+@vulkan1_1
+cmd void vkDestroySamplerYcbcrConversion(
+ VkDevice device,
+ VkSamplerYcbcrConversion ycbcrConversion,
+ const VkAllocationCallbacks* pAllocator) {
+}
+
+@vulkan1_1
+cmd VkResult vkCreateDescriptorUpdateTemplate(
+ VkDevice device,
+ const VkDescriptorUpdateTemplateCreateInfo* pCreateInfo,
+ const VkAllocationCallbacks* pAllocator,
+ VkDescriptorUpdateTemplate* pDescriptorUpdateTemplate) {
+ return ?
+}
+
+@vulkan1_1
+cmd void vkDestroyDescriptorUpdateTemplate(
+ VkDevice device,
+ VkDescriptorUpdateTemplate descriptorUpdateTemplate,
+ const VkAllocationCallbacks* pAllocator) {
+}
+
+@vulkan1_1
+cmd void vkUpdateDescriptorSetWithTemplate(
+ VkDevice device,
+ VkDescriptorSet descriptorSet,
+ VkDescriptorUpdateTemplate descriptorUpdateTemplate,
+ const void* pData) {
+}
+
+@vulkan1_1
+cmd void vkGetPhysicalDeviceExternalBufferProperties(
+ VkPhysicalDevice physicalDevice,
+ const VkPhysicalDeviceExternalBufferInfo* pExternalBufferInfo,
+ VkExternalBufferProperties* pExternalBufferProperties) {
+}
+
+@vulkan1_1
+cmd void vkGetPhysicalDeviceExternalFenceProperties(
+ VkPhysicalDevice physicalDevice,
+ const VkPhysicalDeviceExternalFenceInfo* pExternalFenceInfo,
+ VkExternalFenceProperties* pExternalFenceProperties) {
+}
+
+@vulkan1_1
+cmd void vkGetPhysicalDeviceExternalSemaphoreProperties(
+ VkPhysicalDevice physicalDevice,
+ const VkPhysicalDeviceExternalSemaphoreInfo* pExternalSemaphoreInfo,
+ VkExternalSemaphoreProperties* pExternalSemaphoreProperties) {
+}
+
+@vulkan1_1
+cmd void vkGetDescriptorSetLayoutSupport(
+ VkDevice device,
+ const VkDescriptorSetLayoutCreateInfo* pCreateInfo,
+ VkDescriptorSetLayoutSupport* pSupport) {
+}
+
+
@extension("VK_KHR_surface") // 1
cmd void vkDestroySurfaceKHR(
VkInstance instance,
@@ -6700,6 +8647,42 @@
return ?
}
+@vulkan1_1
+@extension("VK_KHR_swapchain") // 2
+cmd VkResult vkGetDeviceGroupPresentCapabilitiesKHR(
+ VkDevice device,
+ VkDeviceGroupPresentCapabilitiesKHR* pDeviceGroupPresentCapabilities) {
+ return ?
+}
+
+@vulkan1_1
+@extension("VK_KHR_swapchain") // 2
+cmd VkResult vkGetDeviceGroupSurfacePresentModesKHR(
+ VkDevice device,
+ VkSurfaceKHR surface,
+ VkDeviceGroupPresentModeFlagsKHR* pModes) {
+ return ?
+}
+
+@vulkan1_1
+@extension("VK_KHR_swapchain") // 2
+cmd VkResult vkGetPhysicalDevicePresentRectanglesKHR(
+ VkPhysicalDevice physicalDevice,
+ VkSurfaceKHR surface,
+ u32* pRectCount,
+ VkRect2D* pRects) {
+ return ?
+}
+
+@vulkan1_1
+@extension("VK_KHR_swapchain") // 2
+cmd VkResult vkAcquireNextImage2KHR(
+ VkDevice device,
+ const VkAcquireNextImageInfoKHR* pAcquireInfo,
+ u32* pImageIndex) {
+ return ?
+}
+
@extension("VK_KHR_display") // 3
cmd VkResult vkGetPhysicalDeviceDisplayPropertiesKHR(
VkPhysicalDevice physicalDevice,
@@ -6972,21 +8955,21 @@
@extension("VK_EXT_debug_marker") // 23
cmd VkResult vkDebugMarkerSetObjectTagEXT(
VkDevice device,
- VkDebugMarkerObjectTagInfoEXT* pTagInfo) {
+ const VkDebugMarkerObjectTagInfoEXT* pTagInfo) {
return ?
}
@extension("VK_EXT_debug_marker") // 23
cmd VkResult vkDebugMarkerSetObjectNameEXT(
VkDevice device,
- VkDebugMarkerObjectNameInfoEXT* pNameInfo) {
+ const VkDebugMarkerObjectNameInfoEXT* pNameInfo) {
return ?
}
@extension("VK_EXT_debug_marker") // 23
cmd void vkCmdDebugMarkerBeginEXT(
VkCommandBuffer commandBuffer,
- VkDebugMarkerMarkerInfoEXT* pMarkerInfo) {
+ const VkDebugMarkerMarkerInfoEXT* pMarkerInfo) {
}
@extension("VK_EXT_debug_marker") // 23
@@ -6997,7 +8980,7 @@
@extension("VK_EXT_debug_marker") // 23
cmd void vkCmdDebugMarkerInsertEXT(
VkCommandBuffer commandBuffer,
- VkDebugMarkerMarkerInfoEXT* pMarkerInfo) {
+ const VkDebugMarkerMarkerInfoEXT* pMarkerInfo) {
}
@extension("VK_AMD_draw_indirect_count") // 34
@@ -7092,62 +9075,24 @@
VkSparseImageFormatProperties2KHR* pProperties) {
}
-@extension("VK_KHX_device_group") // 61
-cmd void vkGetDeviceGroupPeerMemoryFeaturesKHX(
+@extension("VK_KHR_device_group") // 61
+cmd void vkGetDeviceGroupPeerMemoryFeaturesKHR(
VkDevice device,
u32 heapIndex,
u32 localDeviceIndex,
u32 remoteDeviceIndex,
- VkPeerMemoryFeatureFlagsKHX* pPeerMemoryFeatures) {
+ VkPeerMemoryFeatureFlagsKHR* pPeerMemoryFeatures) {
}
-@extension("VK_KHX_device_group") // 61
-cmd VkResult vkBindBufferMemory2KHX(
- VkDevice device,
- u32 bindInfoCount,
- const VkBindBufferMemoryInfoKHX* pBindInfos) {
- return ?
-}
-
-@extension("VK_KHX_device_group") // 61
-cmd VkResult vkBindImageMemory2KHX(
- VkDevice device,
- u32 bindInfoCount,
- const VkBindImageMemoryInfoKHX* pBindInfos) {
- return ?
-}
-
-@extension("VK_KHX_device_group") // 61
-cmd void vkCmdSetDeviceMaskKHX(
+@extension("VK_KHR_device_group") // 61
+cmd void vkCmdSetDeviceMaskKHR(
VkCommandBuffer commandBuffer,
u32 deviceMask) {
}
-@extension("VK_KHX_device_group") // 61
-cmd VkResult vkGetDeviceGroupPresentCapabilitiesKHX(
- VkDevice device,
- VkDeviceGroupPresentCapabilitiesKHX* pDeviceGroupPresentCapabilities) {
- return ?
-}
-@extension("VK_KHX_device_group") // 61
-cmd VkResult vkGetDeviceGroupSurfacePresentModesKHX(
- VkDevice device,
- VkSurfaceKHR surface,
- VkDeviceGroupPresentModeFlagsKHX* pModes) {
- return ?
-}
-
-@extension("VK_KHX_device_group") // 61
-cmd VkResult vkAcquireNextImage2KHX(
- VkDevice device,
- const VkAcquireNextImageInfoKHX* pAcquireInfo,
- u32* pImageIndex) {
- return ?
-}
-
-@extension("VK_KHX_device_group") // 61
-cmd void vkCmdDispatchBaseKHX(
+@extension("VK_KHR_device_group") // 61
+cmd void vkCmdDispatchBaseKHR(
VkCommandBuffer commandBuffer,
u32 baseGroupX,
u32 baseGroupY,
@@ -7157,15 +9102,6 @@
u32 groupCountZ) {
}
-@extension("VK_KHX_device_group") // 61
-cmd VkResult vkGetPhysicalDevicePresentRectanglesKHX(
- VkPhysicalDevice physicalDevice,
- VkSurfaceKHR surface,
- u32* pRectCount,
- VkRect2D* pRects) {
- return ?
-}
-
@extension("VK_NN_vi_surface") // 63
cmd VkResult vkCreateViSurfaceNN(
VkInstance instance,
@@ -7182,92 +9118,103 @@
VkCommandPoolTrimFlagsKHR flags) {
}
-@extension("VK_KHX_device_group_creation") // 71
-cmd VkResult vkEnumeratePhysicalDeviceGroupsKHX(
+@extension("VK_KHR_device_group_creation") // 71
+@threadSafety("system")
+cmd VkResult vkEnumeratePhysicalDeviceGroupsKHR(
VkInstance instance,
u32* pPhysicalDeviceGroupCount,
- VkPhysicalDeviceGroupPropertiesKHX* pPhysicalDeviceGroupProperties) {
+ VkPhysicalDeviceGroupPropertiesKHR* pPhysicalDeviceGroupProperties) {
+ instanceObject := GetInstance(instance)
+
+ physicalDeviceGroupCount := as!u32(?)
+ pPhysicalDeviceGroupCount[0] = physicalDeviceGroupCount
+ physicalDevices := pPhysicalDeviceGroupProperties[0:physicalDeviceGroupCount]
+
+ for i in (0 .. physicalDeviceGroupCount) {
+ physicalDevice := ?
+ physicalDevices[i] = physicalDevice
+ if !(physicalDevice in State.PhysicalDevices) {
+ State.PhysicalDevices[physicalDevice] = new!PhysicalDeviceObject(instance: instance)
+ }
+ }
+
return ?
}
-@extension("VK_KHX_external_memory_capabilities") // 72
-cmd void vkGetPhysicalDeviceExternalBufferPropertiesKHX(
+@extension("VK_KHR_external_memory_capabilities") // 72
+cmd void vkGetPhysicalDeviceExternalBufferPropertiesKHR(
VkPhysicalDevice physicalDevice,
- const VkPhysicalDeviceExternalBufferInfoKHX* pExternalBufferInfo,
- VkExternalBufferPropertiesKHX* pExternalBufferProperties) {
+ const VkPhysicalDeviceExternalBufferInfoKHR* pExternalBufferInfo,
+ VkExternalBufferPropertiesKHR* pExternalBufferProperties) {
}
-@extension("VK_KHX_external_memory_win32") // 74
-cmd VkResult vkGetMemoryWin32HandleKHX(
+@extension("VK_KHR_external_memory_win32") // 74
+cmd VkResult vkGetMemoryWin32HandleKHR(
VkDevice device,
- VkDeviceMemory memory,
- VkExternalMemoryHandleTypeFlagBitsKHX handleType,
+ const VkMemoryGetWin32HandleInfoKHR* pGetWin32HandleInfo,
platform.HANDLE* pHandle) {
return ?
}
-@extension("VK_KHX_external_memory_win32") // 74
-cmd VkResult vkGetMemoryWin32HandlePropertiesKHX(
+@extension("VK_KHR_external_memory_win32") // 74
+cmd VkResult vkGetMemoryWin32HandlePropertiesKHR(
VkDevice device,
- VkExternalMemoryHandleTypeFlagBitsKHX handleType,
+ VkExternalMemoryHandleTypeFlagBitsKHR handleType,
platform.HANDLE handle,
- VkMemoryWin32HandlePropertiesKHX* pMemoryWin32HandleProperties) {
+ VkMemoryWin32HandlePropertiesKHR* pMemoryWin32HandleProperties) {
return ?
}
-@extension("VK_KHX_external_memory_fd") // 75
-cmd VkResult vkGetMemoryFdKHX(
+@extension("VK_KHR_external_memory_fd") // 75
+cmd VkResult vkGetMemoryFdKHR(
VkDevice device,
- VkDeviceMemory memory,
- VkExternalMemoryHandleTypeFlagBitsKHX handleType,
+ const VkMemoryGetFdInfoKHR* pGetFdInfo,
s32* pFd) {
return ?
}
-@extension("VK_KHX_external_memory_fd") // 75
-cmd VkResult vkGetMemoryFdPropertiesKHX(
+@extension("VK_KHR_external_memory_fd") // 75
+cmd VkResult vkGetMemoryFdPropertiesKHR(
VkDevice device,
- VkExternalMemoryHandleTypeFlagBitsKHX handleType,
+ VkExternalMemoryHandleTypeFlagBitsKHR handleType,
s32 fd,
- VkMemoryFdPropertiesKHX* pMemoryFdProperties) {
+ VkMemoryFdPropertiesKHR* pMemoryFdProperties) {
return ?
}
-@extension("VK_KHX_external_semaphore_capabilities") // 77
-cmd void vkGetPhysicalDeviceExternalSemaphorePropertiesKHX(
+@extension("VK_KHR_external_semaphore_capabilities") // 77
+cmd void vkGetPhysicalDeviceExternalSemaphorePropertiesKHR(
VkPhysicalDevice physicalDevice,
- const VkPhysicalDeviceExternalSemaphoreInfoKHX* pExternalSemaphoreInfo,
- VkExternalSemaphorePropertiesKHX* pExternalSemaphoreProperties) {
+ const VkPhysicalDeviceExternalSemaphoreInfoKHR* pExternalSemaphoreInfo,
+ VkExternalSemaphorePropertiesKHR* pExternalSemaphoreProperties) {
}
-@extension("VK_KHX_external_semaphore_win32") // 79
-cmd VkResult vkImportSemaphoreWin32HandleKHX(
+@extension("VK_KHR_external_semaphore_win32") // 79
+cmd VkResult vkImportSemaphoreWin32HandleKHR(
VkDevice device,
- const VkImportSemaphoreWin32HandleInfoKHX* pImportSemaphoreWin32HandleInfo) {
+ const VkImportSemaphoreWin32HandleInfoKHR* pImportSemaphoreWin32HandleInfo) {
return ?
}
-@extension("VK_KHX_external_semaphore_win32") // 79
-cmd VkResult vkGetSemaphoreWin32HandleKHX(
+@extension("VK_KHR_external_semaphore_win32") // 79
+cmd VkResult vkGetSemaphoreWin32HandleKHR(
VkDevice device,
- VkSemaphore semaphore,
- VkExternalSemaphoreHandleTypeFlagBitsKHX handleType,
+ const VkSemaphoreGetWin32HandleInfoKHR* pGetWin32HandleInfo,
platform.HANDLE* pHandle) {
return ?
}
-@extension("VK_KHX_external_semaphore_fd") // 80
-cmd VkResult vkImportSemaphoreFdKHX(
+@extension("VK_KHR_external_semaphore_fd") // 80
+cmd VkResult vkImportSemaphoreFdKHR(
VkDevice device,
- const VkImportSemaphoreFdInfoKHX* pImportSemaphoreFdInfo) {
+ const VkImportSemaphoreFdInfoKHR* pImportSemaphoreFdInfo) {
return ?
}
-@extension("VK_KHX_external_semaphore_fd") // 80
-cmd VkResult vkGetSemaphoreFdKHX(
+@extension("VK_KHR_external_semaphore_fd") // 80
+cmd VkResult vkGetSemaphoreFdKHR(
VkDevice device,
- VkSemaphore semaphore,
- VkExternalSemaphoreHandleTypeFlagBitsKHX handleType,
+ const VkSemaphoreGetFdInfoKHR* pGetFdInfo,
s32* pFd) {
return ?
}
@@ -7508,6 +9455,43 @@
return ?
}
+@extension("VK_KHR_external_fence_capabilities") // 113
+cmd void vkGetPhysicalDeviceExternalFencePropertiesKHR(
+ VkPhysicalDevice physicalDevice,
+ const VkPhysicalDeviceExternalFenceInfoKHR* pExternalFenceInfo,
+ VkExternalFencePropertiesKHR* pExternalFenceProperties) {
+}
+
+@extension("VK_KHR_external_fence_win32") // 115
+cmd VkResult vkImportFenceWin32HandleKHR(
+ VkDevice device,
+ const VkImportFenceWin32HandleInfoKHR* pImportFenceWin32HandleInfo) {
+ return ?
+}
+
+@extension("VK_KHR_external_fence_win32") // 115
+cmd VkResult vkGetFenceWin32HandleKHR(
+ VkDevice device,
+ const VkFenceGetWin32HandleInfoKHR* pGetWin32HandleInfo,
+ platform.HANDLE* pHandle) {
+ return ?
+}
+
+@extension("VK_KHR_external_fence_fd") // 116
+cmd VkResult vkImportFenceFdKHR(
+ VkDevice device,
+ const VkImportFenceFdInfoKHR* pImportFenceFdInfo) {
+ return ?
+}
+
+@extension("VK_KHR_external_fence_fd") // 116
+cmd VkResult vkGetFenceFdKHR(
+ VkDevice device,
+ const VkFenceGetFdInfoKHR* pGetFdInfo,
+ int* pFd) {
+ return ?
+}
+
@extension("VK_KHR_get_surface_capabilities2") // 120
cmd VkResult vkGetPhysicalDeviceSurfaceCapabilities2KHR(
VkPhysicalDevice physicalDevice,
@@ -7543,6 +9527,114 @@
return ?
}
+@extension("VK_EXT_sample_locations") // 144
+cmd void vkCmdSetSampleLocationsEXT(
+ VkCommandBuffer commandBuffer,
+ const VkSampleLocationsInfoEXT* pSampleLocationsInfo) {
+}
+
+@extension("VK_EXT_sample_locations") // 144
+cmd void vkGetPhysicalDeviceMultisamplePropertiesEXT(
+ VkPhysicalDevice physicalDevice,
+ VkSampleCountFlagBits samples,
+ VkMultisamplePropertiesEXT* pMultisampleProperties) {
+}
+
+@extension("VK_KHR_get_memory_requirements2") // 147
+cmd void vkGetImageMemoryRequirements2KHR(
+ VkDevice device,
+ const VkImageMemoryRequirementsInfo2KHR* pInfo,
+ VkMemoryRequirements2KHR* pMemoryRequirements) {
+}
+
+@extension("VK_KHR_get_memory_requirements2") // 147
+cmd void vkGetBufferMemoryRequirements2KHR(
+ VkDevice device,
+ const VkBufferMemoryRequirementsInfo2KHR* pInfo,
+ VkMemoryRequirements2KHR* pMemoryRequirements) {
+}
+
+@extension("VK_KHR_get_memory_requirements2") // 147
+cmd void vkGetImageSparseMemoryRequirements2KHR(
+ VkDevice device,
+ const VkImageSparseMemoryRequirementsInfo2KHR* pInfo,
+ u32* pSparseMemoryRequirementCount,
+ VkSparseImageMemoryRequirements2KHR* pSparseMemoryRequirements) {
+}
+
+@extension("VK_KHR_sampler_ycbcr_conversion") // 157
+cmd VkResult vkCreateSamplerYcbcrConversionKHR(
+ VkDevice device,
+ const VkSamplerYcbcrConversionCreateInfoKHR* pCreateInfo,
+ const VkAllocationCallbacks* pAllocator,
+ VkSamplerYcbcrConversionKHR* pYcbcrConversion) {
+ return ?
+}
+
+@extension("VK_KHR_sampler_ycbcr_conversion") // 157
+cmd void vkDestroySamplerYcbcrConversionKHR(
+ VkDevice device,
+ VkSamplerYcbcrConversionKHR ycbcrConversion,
+ const VkAllocationCallbacks* pAllocator) {
+}
+
+@extension("VK_KHR_bind_memory2") // 158
+cmd VkResult vkBindBufferMemory2KHR(
+ VkDevice device,
+ u32 bindInfoCount,
+ const VkBindBufferMemoryInfoKHR* pBindInfos) {
+ return ?
+}
+
+@extension("VK_KHR_bind_memory2") // 158
+cmd VkResult vkBindImageMemory2KHR(
+ VkDevice device,
+ u32 bindInfoCount,
+ const VkBindImageMemoryInfoKHR* pBindInfos) {
+ return ?
+}
+
+@extension("VK_EXT_validation_cache") // 161
+cmd VkResult vkCreateValidationCacheEXT(
+ VkDevice device,
+ const VkValidationCacheCreateInfoEXT* pCreateInfo,
+ const VkAllocationCallbacks* pAllocator,
+ VkValidationCacheEXT* pValidationCache) {
+ return ?
+}
+
+@extension("VK_EXT_validation_cache") // 161
+cmd void vkDestroyValidationCacheEXT(
+ VkDevice device,
+ VkValidationCacheEXT validationCache,
+ const VkAllocationCallbacks* pAllocator) {
+}
+
+@extension("VK_EXT_validation_cache") // 161
+cmd VkResult vkMergeValidationCachesEXT(
+ VkDevice device,
+ VkValidationCacheEXT dstCache,
+ u32 srcCacheCount,
+ const VkValidationCacheEXT* pSrcCaches) {
+ return ?
+}
+
+@extension("VK_EXT_validation_cache") // 161
+cmd VkResult vkGetValidationCacheDataEXT(
+ VkDevice device,
+ VkValidationCacheEXT validationCache,
+ platform.size_t* pDataSize,
+ void* pData) {
+ return ?
+}
+
+@extension("VK_KHR_maintenance3") // 169
+cmd void vkGetDescriptorSetLayoutSupportKHR(
+ VkDevice device,
+ const VkDescriptorSetLayoutCreateInfo* pCreateInfo,
+ VkDescriptorSetLayoutSupportKHR* pSupport) {
+}
+
////////////////
// Validation //
////////////////
diff --git a/vulkan/include/vulkan/vulkan.h b/vulkan/include/vulkan/vulkan.h
index ee30913..f96a9fa 100644
--- a/vulkan/include/vulkan/vulkan.h
+++ b/vulkan/include/vulkan/vulkan.h
@@ -34,16 +34,16 @@
(((major) << 22) | ((minor) << 12) | (patch))
// DEPRECATED: This define has been removed. Specific version defines (e.g. VK_API_VERSION_1_0), or the VK_MAKE_VERSION macro, should be used instead.
-//#define VK_API_VERSION VK_MAKE_VERSION(1, 0, 0)
+//#define VK_API_VERSION VK_MAKE_VERSION(1, 0, 0) // Patch version should always be set to 0
// Vulkan 1.0 version number
-#define VK_API_VERSION_1_0 VK_MAKE_VERSION(1, 0, 0)
+#define VK_API_VERSION_1_0 VK_MAKE_VERSION(1, 0, 0)// Patch version should always be set to 0
#define VK_VERSION_MAJOR(version) ((uint32_t)(version) >> 22)
#define VK_VERSION_MINOR(version) (((uint32_t)(version) >> 12) & 0x3ff)
#define VK_VERSION_PATCH(version) ((uint32_t)(version) & 0xfff)
// Version of this file
-#define VK_HEADER_VERSION 49
+#define VK_HEADER_VERSION 61
#define VK_NULL_HANDLE 0
@@ -138,6 +138,8 @@
VK_ERROR_TOO_MANY_OBJECTS = -10,
VK_ERROR_FORMAT_NOT_SUPPORTED = -11,
VK_ERROR_FRAGMENTED_POOL = -12,
+ VK_ERROR_OUT_OF_POOL_MEMORY = -1000069000,
+ VK_ERROR_INVALID_EXTERNAL_HANDLE = -1000072003,
VK_ERROR_SURFACE_LOST_KHR = -1000000000,
VK_ERROR_NATIVE_WINDOW_IN_USE_KHR = -1000000001,
VK_SUBOPTIMAL_KHR = 1000001003,
@@ -145,8 +147,6 @@
VK_ERROR_INCOMPATIBLE_DISPLAY_KHR = -1000003001,
VK_ERROR_VALIDATION_FAILED_EXT = -1000011001,
VK_ERROR_INVALID_SHADER_NV = -1000012000,
- VK_ERROR_OUT_OF_POOL_MEMORY_KHR = -1000069000,
- VK_ERROR_INVALID_EXTERNAL_HANDLE_KHX = -1000072003,
VK_RESULT_BEGIN_RANGE = VK_ERROR_FRAGMENTED_POOL,
VK_RESULT_END_RANGE = VK_INCOMPLETE,
VK_RESULT_RANGE_SIZE = (VK_INCOMPLETE - VK_ERROR_FRAGMENTED_POOL + 1),
@@ -203,8 +203,79 @@
VK_STRUCTURE_TYPE_MEMORY_BARRIER = 46,
VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO = 47,
VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO = 48,
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES = 1000094000,
+ VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_INFO = 1000157000,
+ VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO = 1000157001,
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES = 1000083000,
+ VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS = 1000127000,
+ VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO = 1000127001,
+ VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO = 1000060000,
+ VK_STRUCTURE_TYPE_DEVICE_GROUP_RENDER_PASS_BEGIN_INFO = 1000060003,
+ VK_STRUCTURE_TYPE_DEVICE_GROUP_COMMAND_BUFFER_BEGIN_INFO = 1000060004,
+ VK_STRUCTURE_TYPE_DEVICE_GROUP_SUBMIT_INFO = 1000060005,
+ VK_STRUCTURE_TYPE_DEVICE_GROUP_BIND_SPARSE_INFO = 1000060006,
+ VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_DEVICE_GROUP_INFO = 1000060013,
+ VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_DEVICE_GROUP_INFO = 1000060014,
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES = 1000070000,
+ VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO = 1000070001,
+ VK_STRUCTURE_TYPE_BUFFER_MEMORY_REQUIREMENTS_INFO_2 = 1000146000,
+ VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2 = 1000146001,
+ VK_STRUCTURE_TYPE_IMAGE_SPARSE_MEMORY_REQUIREMENTS_INFO_2 = 1000146002,
+ VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2 = 1000146003,
+ VK_STRUCTURE_TYPE_SPARSE_IMAGE_MEMORY_REQUIREMENTS_2 = 1000146004,
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2 = 1000059000,
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2 = 1000059001,
+ VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2 = 1000059002,
+ VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2 = 1000059003,
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2 = 1000059004,
+ VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2 = 1000059005,
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2 = 1000059006,
+ VK_STRUCTURE_TYPE_SPARSE_IMAGE_FORMAT_PROPERTIES_2 = 1000059007,
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SPARSE_IMAGE_FORMAT_INFO_2 = 1000059008,
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_POINT_CLIPPING_PROPERTIES = 1000117000,
+ VK_STRUCTURE_TYPE_RENDER_PASS_INPUT_ATTACHMENT_ASPECT_CREATE_INFO = 1000117001,
+ VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO = 1000117002,
+ VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_DOMAIN_ORIGIN_STATE_CREATE_INFO = 1000117003,
+ VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO = 1000053000,
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES = 1000053001,
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES = 1000053002,
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTER_FEATURES = 1000120000,
+ VK_STRUCTURE_TYPE_PROTECTED_SUBMIT_INFO = 1000145000,
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_FEATURES = 1000145001,
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_PROPERTIES = 1000145002,
+ VK_STRUCTURE_TYPE_DEVICE_QUEUE_INFO_2 = 1000145003,
+ VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO = 1000156000,
+ VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO = 1000156001,
+ VK_STRUCTURE_TYPE_BIND_IMAGE_PLANE_MEMORY_INFO = 1000156002,
+ VK_STRUCTURE_TYPE_IMAGE_PLANE_MEMORY_REQUIREMENTS_INFO = 1000156003,
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES = 1000156004,
+ VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_IMAGE_FORMAT_PROPERTIES = 1000156005,
+ VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO = 1000085000,
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO = 1000071000,
+ VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES = 1000071001,
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_BUFFER_INFO = 1000071002,
+ VK_STRUCTURE_TYPE_EXTERNAL_BUFFER_PROPERTIES = 1000071003,
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES = 1000071004,
+ VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO = 1000072000,
+ VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO = 1000072001,
+ VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO = 1000072002,
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_FENCE_INFO = 1000112000,
+ VK_STRUCTURE_TYPE_EXTERNAL_FENCE_PROPERTIES = 1000112001,
+ VK_STRUCTURE_TYPE_EXPORT_FENCE_CREATE_INFO = 1000113000,
+ VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO = 1000077000,
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO = 1000076000,
+ VK_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_PROPERTIES = 1000076001,
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES = 1000168000,
+ VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_SUPPORT = 1000168001,
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETER_FEATURES = 1000063000,
+ VK_STRUCTURE_TYPE_DEVICE_GROUP_PRESENT_CAPABILITIES_KHR = 1000060007,
VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR = 1000001000,
VK_STRUCTURE_TYPE_PRESENT_INFO_KHR = 1000001001,
+ VK_STRUCTURE_TYPE_IMAGE_SWAPCHAIN_CREATE_INFO_KHR = 1000060008,
+ VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_SWAPCHAIN_INFO_KHR = 1000060009,
+ VK_STRUCTURE_TYPE_ACQUIRE_NEXT_IMAGE_INFO_KHR = 1000060010,
+ VK_STRUCTURE_TYPE_DEVICE_GROUP_PRESENT_INFO_KHR = 1000060011,
+ VK_STRUCTURE_TYPE_DEVICE_GROUP_SWAPCHAIN_CREATE_INFO_KHR = 1000060012,
VK_STRUCTURE_TYPE_DISPLAY_MODE_CREATE_INFO_KHR = 1000002000,
VK_STRUCTURE_TYPE_DISPLAY_SURFACE_CREATE_INFO_KHR = 1000002001,
VK_STRUCTURE_TYPE_DISPLAY_PRESENT_INFO_KHR = 1000003000,
@@ -222,64 +293,30 @@
VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_IMAGE_CREATE_INFO_NV = 1000026000,
VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_BUFFER_CREATE_INFO_NV = 1000026001,
VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_MEMORY_ALLOCATE_INFO_NV = 1000026002,
- VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO_KHX = 1000053000,
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES_KHX = 1000053001,
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES_KHX = 1000053002,
+ VK_STRUCTURE_TYPE_TEXTURE_LOD_GATHER_FORMAT_PROPERTIES_AMD = 1000041000,
VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO_NV = 1000056000,
VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_NV = 1000056001,
VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_NV = 1000057000,
VK_STRUCTURE_TYPE_EXPORT_MEMORY_WIN32_HANDLE_INFO_NV = 1000057001,
VK_STRUCTURE_TYPE_WIN32_KEYED_MUTEX_ACQUIRE_RELEASE_INFO_NV = 1000058000,
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR = 1000059000,
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR = 1000059001,
- VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2_KHR = 1000059002,
- VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2_KHR = 1000059003,
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2_KHR = 1000059004,
- VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2_KHR = 1000059005,
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2_KHR = 1000059006,
- VK_STRUCTURE_TYPE_SPARSE_IMAGE_FORMAT_PROPERTIES_2_KHR = 1000059007,
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SPARSE_IMAGE_FORMAT_INFO_2_KHR = 1000059008,
- VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO_KHX = 1000060000,
- VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_INFO_KHX = 1000060001,
- VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO_KHX = 1000060002,
- VK_STRUCTURE_TYPE_DEVICE_GROUP_RENDER_PASS_BEGIN_INFO_KHX = 1000060003,
- VK_STRUCTURE_TYPE_DEVICE_GROUP_COMMAND_BUFFER_BEGIN_INFO_KHX = 1000060004,
- VK_STRUCTURE_TYPE_DEVICE_GROUP_SUBMIT_INFO_KHX = 1000060005,
- VK_STRUCTURE_TYPE_DEVICE_GROUP_BIND_SPARSE_INFO_KHX = 1000060006,
- VK_STRUCTURE_TYPE_DEVICE_GROUP_PRESENT_CAPABILITIES_KHX = 1000060007,
- VK_STRUCTURE_TYPE_IMAGE_SWAPCHAIN_CREATE_INFO_KHX = 1000060008,
- VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_SWAPCHAIN_INFO_KHX = 1000060009,
- VK_STRUCTURE_TYPE_ACQUIRE_NEXT_IMAGE_INFO_KHX = 1000060010,
- VK_STRUCTURE_TYPE_DEVICE_GROUP_PRESENT_INFO_KHX = 1000060011,
- VK_STRUCTURE_TYPE_DEVICE_GROUP_SWAPCHAIN_CREATE_INFO_KHX = 1000060012,
VK_STRUCTURE_TYPE_VALIDATION_FLAGS_EXT = 1000061000,
VK_STRUCTURE_TYPE_VI_SURFACE_CREATE_INFO_NN = 1000062000,
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES_KHX = 1000070000,
- VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO_KHX = 1000070001,
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO_KHX = 1000071000,
- VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES_KHX = 1000071001,
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_BUFFER_INFO_KHX = 1000071002,
- VK_STRUCTURE_TYPE_EXTERNAL_BUFFER_PROPERTIES_KHX = 1000071003,
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES_KHX = 1000071004,
- VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO_KHX = 1000072000,
- VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO_KHX = 1000072001,
- VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_KHX = 1000072002,
- VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_KHX = 1000073000,
- VK_STRUCTURE_TYPE_EXPORT_MEMORY_WIN32_HANDLE_INFO_KHX = 1000073001,
- VK_STRUCTURE_TYPE_MEMORY_WIN32_HANDLE_PROPERTIES_KHX = 1000073002,
- VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHX = 1000074000,
- VK_STRUCTURE_TYPE_MEMORY_FD_PROPERTIES_KHX = 1000074001,
- VK_STRUCTURE_TYPE_WIN32_KEYED_MUTEX_ACQUIRE_RELEASE_INFO_KHX = 1000075000,
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO_KHX = 1000076000,
- VK_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_PROPERTIES_KHX = 1000076001,
- VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO_KHX = 1000077000,
- VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_WIN32_HANDLE_INFO_KHX = 1000078000,
- VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_WIN32_HANDLE_INFO_KHX = 1000078001,
- VK_STRUCTURE_TYPE_D3D12_FENCE_SUBMIT_INFO_KHX = 1000078002,
- VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_FD_INFO_KHX = 1000079000,
+ VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_KHR = 1000073000,
+ VK_STRUCTURE_TYPE_EXPORT_MEMORY_WIN32_HANDLE_INFO_KHR = 1000073001,
+ VK_STRUCTURE_TYPE_MEMORY_WIN32_HANDLE_PROPERTIES_KHR = 1000073002,
+ VK_STRUCTURE_TYPE_MEMORY_GET_WIN32_HANDLE_INFO_KHR = 1000073003,
+ VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR = 1000074000,
+ VK_STRUCTURE_TYPE_MEMORY_FD_PROPERTIES_KHR = 1000074001,
+ VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR = 1000074002,
+ VK_STRUCTURE_TYPE_WIN32_KEYED_MUTEX_ACQUIRE_RELEASE_INFO_KHR = 1000075000,
+ VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_WIN32_HANDLE_INFO_KHR = 1000078000,
+ VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_WIN32_HANDLE_INFO_KHR = 1000078001,
+ VK_STRUCTURE_TYPE_D3D12_FENCE_SUBMIT_INFO_KHR = 1000078002,
+ VK_STRUCTURE_TYPE_SEMAPHORE_GET_WIN32_HANDLE_INFO_KHR = 1000078003,
+ VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_FD_INFO_KHR = 1000079000,
+ VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR = 1000079001,
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PUSH_DESCRIPTOR_PROPERTIES_KHR = 1000080000,
VK_STRUCTURE_TYPE_PRESENT_REGIONS_KHR = 1000084000,
- VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO_KHR = 1000085000,
VK_STRUCTURE_TYPE_OBJECT_TABLE_CREATE_INFO_NVX = 1000086000,
VK_STRUCTURE_TYPE_INDIRECT_COMMANDS_LAYOUT_CREATE_INFO_NVX = 1000086001,
VK_STRUCTURE_TYPE_CMD_PROCESS_COMMANDS_INFO_NVX = 1000086002,
@@ -287,7 +324,7 @@
VK_STRUCTURE_TYPE_DEVICE_GENERATED_COMMANDS_LIMITS_NVX = 1000086004,
VK_STRUCTURE_TYPE_DEVICE_GENERATED_COMMANDS_FEATURES_NVX = 1000086005,
VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_W_SCALING_STATE_CREATE_INFO_NV = 1000087000,
- VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES2_EXT = 1000090000,
+ VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_EXT = 1000090000,
VK_STRUCTURE_TYPE_DISPLAY_POWER_INFO_EXT = 1000091000,
VK_STRUCTURE_TYPE_DEVICE_EVENT_INFO_EXT = 1000091001,
VK_STRUCTURE_TYPE_DISPLAY_EVENT_INFO_EXT = 1000091002,
@@ -299,11 +336,31 @@
VK_STRUCTURE_TYPE_PIPELINE_DISCARD_RECTANGLE_STATE_CREATE_INFO_EXT = 1000099001,
VK_STRUCTURE_TYPE_HDR_METADATA_EXT = 1000105000,
VK_STRUCTURE_TYPE_SHARED_PRESENT_SURFACE_CAPABILITIES_KHR = 1000111000,
+ VK_STRUCTURE_TYPE_IMPORT_FENCE_WIN32_HANDLE_INFO_KHR = 1000114000,
+ VK_STRUCTURE_TYPE_EXPORT_FENCE_WIN32_HANDLE_INFO_KHR = 1000114001,
+ VK_STRUCTURE_TYPE_FENCE_GET_WIN32_HANDLE_INFO_KHR = 1000114002,
+ VK_STRUCTURE_TYPE_IMPORT_FENCE_FD_INFO_KHR = 1000115000,
+ VK_STRUCTURE_TYPE_FENCE_GET_FD_INFO_KHR = 1000115001,
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR = 1000119000,
VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR = 1000119001,
VK_STRUCTURE_TYPE_SURFACE_FORMAT_2_KHR = 1000119002,
VK_STRUCTURE_TYPE_IOS_SURFACE_CREATE_INFO_MVK = 1000122000,
VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK = 1000123000,
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_FILTER_MINMAX_PROPERTIES_EXT = 1000130000,
+ VK_STRUCTURE_TYPE_SAMPLER_REDUCTION_MODE_CREATE_INFO_EXT = 1000130001,
+ VK_STRUCTURE_TYPE_SAMPLE_LOCATIONS_INFO_EXT = 1000143000,
+ VK_STRUCTURE_TYPE_RENDER_PASS_SAMPLE_LOCATIONS_BEGIN_INFO_EXT = 1000143001,
+ VK_STRUCTURE_TYPE_PIPELINE_SAMPLE_LOCATIONS_STATE_CREATE_INFO_EXT = 1000143002,
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLE_LOCATIONS_PROPERTIES_EXT = 1000143003,
+ VK_STRUCTURE_TYPE_MULTISAMPLE_PROPERTIES_EXT = 1000143004,
+ VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO_KHR = 1000147000,
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_FEATURES_EXT = 1000148000,
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_PROPERTIES_EXT = 1000148001,
+ VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_ADVANCED_STATE_CREATE_INFO_EXT = 1000148002,
+ VK_STRUCTURE_TYPE_PIPELINE_COVERAGE_TO_COLOR_STATE_CREATE_INFO_NV = 1000149000,
+ VK_STRUCTURE_TYPE_PIPELINE_COVERAGE_MODULATION_STATE_CREATE_INFO_NV = 1000152000,
+ VK_STRUCTURE_TYPE_VALIDATION_CACHE_CREATE_INFO_EXT = 1000160000,
+ VK_STRUCTURE_TYPE_SHADER_MODULE_VALIDATION_CACHE_CREATE_INFO_EXT = 1000160001,
VK_STRUCTURE_TYPE_BEGIN_RANGE = VK_STRUCTURE_TYPE_APPLICATION_INFO,
VK_STRUCTURE_TYPE_END_RANGE = VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO,
VK_STRUCTURE_TYPE_RANGE_SIZE = (VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO - VK_STRUCTURE_TYPE_APPLICATION_INFO + 1),
@@ -516,6 +573,40 @@
VK_FORMAT_ASTC_12x10_SRGB_BLOCK = 182,
VK_FORMAT_ASTC_12x12_UNORM_BLOCK = 183,
VK_FORMAT_ASTC_12x12_SRGB_BLOCK = 184,
+ VK_FORMAT_G8B8G8R8_422_UNORM = 1000156000,
+ VK_FORMAT_B8G8R8G8_422_UNORM = 1000156001,
+ VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM = 1000156002,
+ VK_FORMAT_G8_B8R8_2PLANE_420_UNORM = 1000156003,
+ VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM = 1000156004,
+ VK_FORMAT_G8_B8R8_2PLANE_422_UNORM = 1000156005,
+ VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM = 1000156006,
+ VK_FORMAT_R10X6_UNORM_PACK16 = 1000156007,
+ VK_FORMAT_R10X6G10X6_UNORM_2PACK16 = 1000156008,
+ VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16 = 1000156009,
+ VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16 = 1000156010,
+ VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16 = 1000156011,
+ VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16 = 1000156012,
+ VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16 = 1000156013,
+ VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16 = 1000156014,
+ VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16 = 1000156015,
+ VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16 = 1000156016,
+ VK_FORMAT_R12X4_UNORM_PACK16 = 1000156017,
+ VK_FORMAT_R12X4G12X4_UNORM_2PACK16 = 1000156018,
+ VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16 = 1000156019,
+ VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16 = 1000156020,
+ VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16 = 1000156021,
+ VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16 = 1000156022,
+ VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16 = 1000156023,
+ VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16 = 1000156024,
+ VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16 = 1000156025,
+ VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16 = 1000156026,
+ VK_FORMAT_G16B16G16R16_422_UNORM = 1000156027,
+ VK_FORMAT_B16G16R16G16_422_UNORM = 1000156028,
+ VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM = 1000156029,
+ VK_FORMAT_G16_B16R16_2PLANE_420_UNORM = 1000156030,
+ VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM = 1000156031,
+ VK_FORMAT_G16_B16R16_2PLANE_422_UNORM = 1000156032,
+ VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM = 1000156033,
VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG = 1000054000,
VK_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG = 1000054001,
VK_FORMAT_PVRTC2_2BPP_UNORM_BLOCK_IMG = 1000054002,
@@ -590,6 +681,8 @@
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL = 6,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL = 7,
VK_IMAGE_LAYOUT_PREINITIALIZED = 8,
+ VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL = 1000117000,
+ VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL = 1000117001,
VK_IMAGE_LAYOUT_PRESENT_SRC_KHR = 1000001002,
VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR = 1000111000,
VK_IMAGE_LAYOUT_BEGIN_RANGE = VK_IMAGE_LAYOUT_UNDEFINED,
@@ -657,6 +750,7 @@
VK_POLYGON_MODE_FILL = 0,
VK_POLYGON_MODE_LINE = 1,
VK_POLYGON_MODE_POINT = 2,
+ VK_POLYGON_MODE_FILL_RECTANGLE_NV = 1000153000,
VK_POLYGON_MODE_BEGIN_RANGE = VK_POLYGON_MODE_FILL,
VK_POLYGON_MODE_END_RANGE = VK_POLYGON_MODE_POINT,
VK_POLYGON_MODE_RANGE_SIZE = (VK_POLYGON_MODE_POINT - VK_POLYGON_MODE_FILL + 1),
@@ -757,6 +851,52 @@
VK_BLEND_OP_REVERSE_SUBTRACT = 2,
VK_BLEND_OP_MIN = 3,
VK_BLEND_OP_MAX = 4,
+ VK_BLEND_OP_ZERO_EXT = 1000148000,
+ VK_BLEND_OP_SRC_EXT = 1000148001,
+ VK_BLEND_OP_DST_EXT = 1000148002,
+ VK_BLEND_OP_SRC_OVER_EXT = 1000148003,
+ VK_BLEND_OP_DST_OVER_EXT = 1000148004,
+ VK_BLEND_OP_SRC_IN_EXT = 1000148005,
+ VK_BLEND_OP_DST_IN_EXT = 1000148006,
+ VK_BLEND_OP_SRC_OUT_EXT = 1000148007,
+ VK_BLEND_OP_DST_OUT_EXT = 1000148008,
+ VK_BLEND_OP_SRC_ATOP_EXT = 1000148009,
+ VK_BLEND_OP_DST_ATOP_EXT = 1000148010,
+ VK_BLEND_OP_XOR_EXT = 1000148011,
+ VK_BLEND_OP_MULTIPLY_EXT = 1000148012,
+ VK_BLEND_OP_SCREEN_EXT = 1000148013,
+ VK_BLEND_OP_OVERLAY_EXT = 1000148014,
+ VK_BLEND_OP_DARKEN_EXT = 1000148015,
+ VK_BLEND_OP_LIGHTEN_EXT = 1000148016,
+ VK_BLEND_OP_COLORDODGE_EXT = 1000148017,
+ VK_BLEND_OP_COLORBURN_EXT = 1000148018,
+ VK_BLEND_OP_HARDLIGHT_EXT = 1000148019,
+ VK_BLEND_OP_SOFTLIGHT_EXT = 1000148020,
+ VK_BLEND_OP_DIFFERENCE_EXT = 1000148021,
+ VK_BLEND_OP_EXCLUSION_EXT = 1000148022,
+ VK_BLEND_OP_INVERT_EXT = 1000148023,
+ VK_BLEND_OP_INVERT_RGB_EXT = 1000148024,
+ VK_BLEND_OP_LINEARDODGE_EXT = 1000148025,
+ VK_BLEND_OP_LINEARBURN_EXT = 1000148026,
+ VK_BLEND_OP_VIVIDLIGHT_EXT = 1000148027,
+ VK_BLEND_OP_LINEARLIGHT_EXT = 1000148028,
+ VK_BLEND_OP_PINLIGHT_EXT = 1000148029,
+ VK_BLEND_OP_HARDMIX_EXT = 1000148030,
+ VK_BLEND_OP_HSL_HUE_EXT = 1000148031,
+ VK_BLEND_OP_HSL_SATURATION_EXT = 1000148032,
+ VK_BLEND_OP_HSL_COLOR_EXT = 1000148033,
+ VK_BLEND_OP_HSL_LUMINOSITY_EXT = 1000148034,
+ VK_BLEND_OP_PLUS_EXT = 1000148035,
+ VK_BLEND_OP_PLUS_CLAMPED_EXT = 1000148036,
+ VK_BLEND_OP_PLUS_CLAMPED_ALPHA_EXT = 1000148037,
+ VK_BLEND_OP_PLUS_DARKER_EXT = 1000148038,
+ VK_BLEND_OP_MINUS_EXT = 1000148039,
+ VK_BLEND_OP_MINUS_CLAMPED_EXT = 1000148040,
+ VK_BLEND_OP_CONTRAST_EXT = 1000148041,
+ VK_BLEND_OP_INVERT_OVG_EXT = 1000148042,
+ VK_BLEND_OP_RED_EXT = 1000148043,
+ VK_BLEND_OP_GREEN_EXT = 1000148044,
+ VK_BLEND_OP_BLUE_EXT = 1000148045,
VK_BLEND_OP_BEGIN_RANGE = VK_BLEND_OP_ADD,
VK_BLEND_OP_END_RANGE = VK_BLEND_OP_MAX,
VK_BLEND_OP_RANGE_SIZE = (VK_BLEND_OP_MAX - VK_BLEND_OP_ADD + 1),
@@ -775,6 +915,7 @@
VK_DYNAMIC_STATE_STENCIL_REFERENCE = 8,
VK_DYNAMIC_STATE_VIEWPORT_W_SCALING_NV = 1000087000,
VK_DYNAMIC_STATE_DISCARD_RECTANGLE_EXT = 1000099000,
+ VK_DYNAMIC_STATE_SAMPLE_LOCATIONS_EXT = 1000143000,
VK_DYNAMIC_STATE_BEGIN_RANGE = VK_DYNAMIC_STATE_VIEWPORT,
VK_DYNAMIC_STATE_END_RANGE = VK_DYNAMIC_STATE_STENCIL_REFERENCE,
VK_DYNAMIC_STATE_RANGE_SIZE = (VK_DYNAMIC_STATE_STENCIL_REFERENCE - VK_DYNAMIC_STATE_VIEWPORT + 1),
@@ -925,14 +1066,16 @@
VK_OBJECT_TYPE_DESCRIPTOR_SET = 23,
VK_OBJECT_TYPE_FRAMEBUFFER = 24,
VK_OBJECT_TYPE_COMMAND_POOL = 25,
+ VK_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION = 1000156000,
+ VK_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE = 1000085000,
VK_OBJECT_TYPE_SURFACE_KHR = 1000000000,
VK_OBJECT_TYPE_SWAPCHAIN_KHR = 1000001000,
VK_OBJECT_TYPE_DISPLAY_KHR = 1000002000,
VK_OBJECT_TYPE_DISPLAY_MODE_KHR = 1000002001,
VK_OBJECT_TYPE_DEBUG_REPORT_CALLBACK_EXT = 1000011000,
- VK_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_KHR = 1000085000,
VK_OBJECT_TYPE_OBJECT_TABLE_NVX = 1000086000,
VK_OBJECT_TYPE_INDIRECT_COMMANDS_LAYOUT_NVX = 1000086001,
+ VK_OBJECT_TYPE_VALIDATION_CACHE_EXT = 1000160000,
VK_OBJECT_TYPE_BEGIN_RANGE = VK_OBJECT_TYPE_UNKNOWN,
VK_OBJECT_TYPE_END_RANGE = VK_OBJECT_TYPE_COMMAND_POOL,
VK_OBJECT_TYPE_RANGE_SIZE = (VK_OBJECT_TYPE_COMMAND_POOL - VK_OBJECT_TYPE_UNKNOWN + 1),
@@ -955,9 +1098,17 @@
VK_FORMAT_FEATURE_BLIT_SRC_BIT = 0x00000400,
VK_FORMAT_FEATURE_BLIT_DST_BIT = 0x00000800,
VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT = 0x00001000,
+ VK_FORMAT_FEATURE_TRANSFER_SRC_BIT = 0x00004000,
+ VK_FORMAT_FEATURE_TRANSFER_DST_BIT = 0x00008000,
+ VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT = 0x00020000,
+ VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT = 0x00040000,
+ VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER_BIT = 0x00080000,
+ VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_BIT = 0x00100000,
+ VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE_BIT = 0x00200000,
+ VK_FORMAT_FEATURE_DISJOINT_BIT = 0x00400000,
+ VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT = 0x00800000,
VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_IMG = 0x00002000,
- VK_FORMAT_FEATURE_TRANSFER_SRC_BIT_KHR = 0x00004000,
- VK_FORMAT_FEATURE_TRANSFER_DST_BIT_KHR = 0x00008000,
+ VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_MINMAX_BIT_EXT = 0x00010000,
VK_FORMAT_FEATURE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
} VkFormatFeatureFlagBits;
typedef VkFlags VkFormatFeatureFlags;
@@ -981,8 +1132,14 @@
VK_IMAGE_CREATE_SPARSE_ALIASED_BIT = 0x00000004,
VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT = 0x00000008,
VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT = 0x00000010,
- VK_IMAGE_CREATE_BIND_SFR_BIT_KHX = 0x00000040,
- VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT_KHR = 0x00000020,
+ VK_IMAGE_CREATE_ALIAS_BIT = 0x00000400,
+ VK_IMAGE_CREATE_BIND_SFR_BIT = 0x00000040,
+ VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT = 0x00000020,
+ VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT = 0x00000080,
+ VK_IMAGE_CREATE_EXTENDED_USAGE_BIT = 0x00000100,
+ VK_IMAGE_CREATE_PROTECTED_BIT = 0x00000800,
+ VK_IMAGE_CREATE_DISJOINT_BIT = 0x00000200,
+ VK_IMAGE_CREATE_SAMPLE_LOCATIONS_COMPATIBLE_DEPTH_BIT_EXT = 0x00001000,
VK_IMAGE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
} VkImageCreateFlagBits;
typedef VkFlags VkImageCreateFlags;
@@ -1004,6 +1161,7 @@
VK_QUEUE_COMPUTE_BIT = 0x00000002,
VK_QUEUE_TRANSFER_BIT = 0x00000004,
VK_QUEUE_SPARSE_BINDING_BIT = 0x00000008,
+ VK_QUEUE_PROTECTED_BIT = 0x00000010,
VK_QUEUE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
} VkQueueFlagBits;
typedef VkFlags VkQueueFlags;
@@ -1014,17 +1172,23 @@
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT = 0x00000004,
VK_MEMORY_PROPERTY_HOST_CACHED_BIT = 0x00000008,
VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT = 0x00000010,
+ VK_MEMORY_PROPERTY_PROTECTED_BIT = 0x00000020,
VK_MEMORY_PROPERTY_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
} VkMemoryPropertyFlagBits;
typedef VkFlags VkMemoryPropertyFlags;
typedef enum VkMemoryHeapFlagBits {
VK_MEMORY_HEAP_DEVICE_LOCAL_BIT = 0x00000001,
- VK_MEMORY_HEAP_MULTI_INSTANCE_BIT_KHX = 0x00000002,
+ VK_MEMORY_HEAP_MULTI_INSTANCE_BIT = 0x00000002,
VK_MEMORY_HEAP_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
} VkMemoryHeapFlagBits;
typedef VkFlags VkMemoryHeapFlags;
typedef VkFlags VkDeviceCreateFlags;
+
+typedef enum VkDeviceQueueCreateFlagBits {
+ VK_DEVICE_QUEUE_CREATE_PROTECTED_BIT = 0x00000001,
+ VK_DEVICE_QUEUE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
+} VkDeviceQueueCreateFlagBits;
typedef VkFlags VkDeviceQueueCreateFlags;
typedef enum VkPipelineStageFlagBits {
@@ -1056,6 +1220,9 @@
VK_IMAGE_ASPECT_DEPTH_BIT = 0x00000002,
VK_IMAGE_ASPECT_STENCIL_BIT = 0x00000004,
VK_IMAGE_ASPECT_METADATA_BIT = 0x00000008,
+ VK_IMAGE_ASPECT_PLANE_0_BIT = 0x00000010,
+ VK_IMAGE_ASPECT_PLANE_1_BIT = 0x00000020,
+ VK_IMAGE_ASPECT_PLANE_2_BIT = 0x00000040,
VK_IMAGE_ASPECT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
} VkImageAspectFlagBits;
typedef VkFlags VkImageAspectFlags;
@@ -1112,6 +1279,7 @@
VK_BUFFER_CREATE_SPARSE_BINDING_BIT = 0x00000001,
VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT = 0x00000002,
VK_BUFFER_CREATE_SPARSE_ALIASED_BIT = 0x00000004,
+ VK_BUFFER_CREATE_PROTECTED_BIT = 0x00000008,
VK_BUFFER_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
} VkBufferCreateFlagBits;
typedef VkFlags VkBufferCreateFlags;
@@ -1138,8 +1306,8 @@
VK_PIPELINE_CREATE_DISABLE_OPTIMIZATION_BIT = 0x00000001,
VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT = 0x00000002,
VK_PIPELINE_CREATE_DERIVATIVE_BIT = 0x00000004,
- VK_PIPELINE_CREATE_VIEW_INDEX_FROM_DEVICE_INDEX_BIT_KHX = 0x00000008,
- VK_PIPELINE_CREATE_DISPATCH_BASE_KHX = 0x00000010,
+ VK_PIPELINE_CREATE_VIEW_INDEX_FROM_DEVICE_INDEX_BIT = 0x00000008,
+ VK_PIPELINE_CREATE_DISPATCH_BASE = 0x00000010,
VK_PIPELINE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
} VkPipelineCreateFlagBits;
typedef VkFlags VkPipelineCreateFlags;
@@ -1235,14 +1403,15 @@
VK_ACCESS_MEMORY_WRITE_BIT = 0x00010000,
VK_ACCESS_COMMAND_PROCESS_READ_BIT_NVX = 0x00020000,
VK_ACCESS_COMMAND_PROCESS_WRITE_BIT_NVX = 0x00040000,
+ VK_ACCESS_COLOR_ATTACHMENT_READ_NONCOHERENT_BIT_EXT = 0x00080000,
VK_ACCESS_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
} VkAccessFlagBits;
typedef VkFlags VkAccessFlags;
typedef enum VkDependencyFlagBits {
VK_DEPENDENCY_BY_REGION_BIT = 0x00000001,
- VK_DEPENDENCY_VIEW_LOCAL_BIT_KHX = 0x00000002,
- VK_DEPENDENCY_DEVICE_GROUP_BIT_KHX = 0x00000004,
+ VK_DEPENDENCY_DEVICE_GROUP_BIT = 0x00000004,
+ VK_DEPENDENCY_VIEW_LOCAL_BIT = 0x00000002,
VK_DEPENDENCY_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
} VkDependencyFlagBits;
typedef VkFlags VkDependencyFlags;
@@ -1250,6 +1419,7 @@
typedef enum VkCommandPoolCreateFlagBits {
VK_COMMAND_POOL_CREATE_TRANSIENT_BIT = 0x00000001,
VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT = 0x00000002,
+ VK_COMMAND_POOL_CREATE_PROTECTED_BIT = 0x00000004,
VK_COMMAND_POOL_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
} VkCommandPoolCreateFlagBits;
typedef VkFlags VkCommandPoolCreateFlags;
@@ -1288,6 +1458,27 @@
} VkStencilFaceFlagBits;
typedef VkFlags VkStencilFaceFlags;
+typedef struct VkApplicationInfo {
+ VkStructureType sType;
+ const void* pNext;
+ const char* pApplicationName;
+ uint32_t applicationVersion;
+ const char* pEngineName;
+ uint32_t engineVersion;
+ uint32_t apiVersion;
+} VkApplicationInfo;
+
+typedef struct VkInstanceCreateInfo {
+ VkStructureType sType;
+ const void* pNext;
+ VkInstanceCreateFlags flags;
+ const VkApplicationInfo* pApplicationInfo;
+ uint32_t enabledLayerCount;
+ const char* const* ppEnabledLayerNames;
+ uint32_t enabledExtensionCount;
+ const char* const* ppEnabledExtensionNames;
+} VkInstanceCreateInfo;
+
typedef void* (VKAPI_PTR *PFN_vkAllocationFunction)(
void* pUserData,
size_t size,
@@ -1317,29 +1508,6 @@
VkInternalAllocationType allocationType,
VkSystemAllocationScope allocationScope);
-typedef void (VKAPI_PTR *PFN_vkVoidFunction)(void);
-
-typedef struct VkApplicationInfo {
- VkStructureType sType;
- const void* pNext;
- const char* pApplicationName;
- uint32_t applicationVersion;
- const char* pEngineName;
- uint32_t engineVersion;
- uint32_t apiVersion;
-} VkApplicationInfo;
-
-typedef struct VkInstanceCreateInfo {
- VkStructureType sType;
- const void* pNext;
- VkInstanceCreateFlags flags;
- const VkApplicationInfo* pApplicationInfo;
- uint32_t enabledLayerCount;
- const char* const* ppEnabledLayerNames;
- uint32_t enabledExtensionCount;
- const char* const* ppEnabledExtensionNames;
-} VkInstanceCreateInfo;
-
typedef struct VkAllocationCallbacks {
void* pUserData;
PFN_vkAllocationFunction pfnAllocation;
@@ -1580,6 +1748,7 @@
VkMemoryHeap memoryHeaps[VK_MAX_MEMORY_HEAPS];
} VkPhysicalDeviceMemoryProperties;
+typedef void (VKAPI_PTR *PFN_vkVoidFunction)(void);
typedef struct VkDeviceQueueCreateInfo {
VkStructureType sType;
const void* pNext;
@@ -3332,10 +3501,837 @@
const VkCommandBuffer* pCommandBuffers);
#endif
+#define VK_VERSION_1_1 1
+// Vulkan 1.1 version number
+#define VK_API_VERSION_1_1 VK_MAKE_VERSION(1, 1, 0)// Patch version should always be set to 0
+
+
+VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSamplerYcbcrConversion)
+VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDescriptorUpdateTemplate)
+
+#define VK_MAX_DEVICE_GROUP_SIZE 32
+#define VK_LUID_SIZE 8
+#define VK_QUEUE_FAMILY_EXTERNAL (~0U-1)
+
+
+typedef enum VkPointClippingBehavior {
+ VK_POINT_CLIPPING_BEHAVIOR_ALL_CLIP_PLANES = 0,
+ VK_POINT_CLIPPING_BEHAVIOR_USER_CLIP_PLANES_ONLY = 1,
+ VK_POINT_CLIPPING_BEHAVIOR_BEGIN_RANGE = VK_POINT_CLIPPING_BEHAVIOR_ALL_CLIP_PLANES,
+ VK_POINT_CLIPPING_BEHAVIOR_END_RANGE = VK_POINT_CLIPPING_BEHAVIOR_USER_CLIP_PLANES_ONLY,
+ VK_POINT_CLIPPING_BEHAVIOR_RANGE_SIZE = (VK_POINT_CLIPPING_BEHAVIOR_USER_CLIP_PLANES_ONLY - VK_POINT_CLIPPING_BEHAVIOR_ALL_CLIP_PLANES + 1),
+ VK_POINT_CLIPPING_BEHAVIOR_MAX_ENUM = 0x7FFFFFFF
+} VkPointClippingBehavior;
+
+typedef enum VkTessellationDomainOrigin {
+ VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT = 0,
+ VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT = 1,
+ VK_TESSELLATION_DOMAIN_ORIGIN_BEGIN_RANGE = VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT,
+ VK_TESSELLATION_DOMAIN_ORIGIN_END_RANGE = VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT,
+ VK_TESSELLATION_DOMAIN_ORIGIN_RANGE_SIZE = (VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT - VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT + 1),
+ VK_TESSELLATION_DOMAIN_ORIGIN_MAX_ENUM = 0x7FFFFFFF
+} VkTessellationDomainOrigin;
+
+typedef enum VkSamplerYcbcrModelConversion {
+ VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY = 0,
+ VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_IDENTITY = 1,
+ VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_709 = 2,
+ VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601 = 3,
+ VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020 = 4,
+ VK_SAMPLER_YCBCR_MODEL_CONVERSION_BEGIN_RANGE = VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY,
+ VK_SAMPLER_YCBCR_MODEL_CONVERSION_END_RANGE = VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020,
+ VK_SAMPLER_YCBCR_MODEL_CONVERSION_RANGE_SIZE = (VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020 - VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY + 1),
+ VK_SAMPLER_YCBCR_MODEL_CONVERSION_MAX_ENUM = 0x7FFFFFFF
+} VkSamplerYcbcrModelConversion;
+
+typedef enum VkSamplerYcbcrRange {
+ VK_SAMPLER_YCBCR_RANGE_ITU_FULL = 0,
+ VK_SAMPLER_YCBCR_RANGE_ITU_NARROW = 1,
+ VK_SAMPLER_YCBCR_RANGE_BEGIN_RANGE = VK_SAMPLER_YCBCR_RANGE_ITU_FULL,
+ VK_SAMPLER_YCBCR_RANGE_END_RANGE = VK_SAMPLER_YCBCR_RANGE_ITU_NARROW,
+ VK_SAMPLER_YCBCR_RANGE_RANGE_SIZE = (VK_SAMPLER_YCBCR_RANGE_ITU_NARROW - VK_SAMPLER_YCBCR_RANGE_ITU_FULL + 1),
+ VK_SAMPLER_YCBCR_RANGE_MAX_ENUM = 0x7FFFFFFF
+} VkSamplerYcbcrRange;
+
+typedef enum VkChromaLocation {
+ VK_CHROMA_LOCATION_COSITED_EVEN = 0,
+ VK_CHROMA_LOCATION_MIDPOINT = 1,
+ VK_CHROMA_LOCATION_BEGIN_RANGE = VK_CHROMA_LOCATION_COSITED_EVEN,
+ VK_CHROMA_LOCATION_END_RANGE = VK_CHROMA_LOCATION_MIDPOINT,
+ VK_CHROMA_LOCATION_RANGE_SIZE = (VK_CHROMA_LOCATION_MIDPOINT - VK_CHROMA_LOCATION_COSITED_EVEN + 1),
+ VK_CHROMA_LOCATION_MAX_ENUM = 0x7FFFFFFF
+} VkChromaLocation;
+
+typedef enum VkDescriptorUpdateTemplateType {
+ VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET = 0,
+ VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_PUSH_DESCRIPTORS_KHR = 1,
+ VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_BEGIN_RANGE = VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET,
+ VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_END_RANGE = VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET,
+ VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_RANGE_SIZE = (VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET - VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET + 1),
+ VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_MAX_ENUM = 0x7FFFFFFF
+} VkDescriptorUpdateTemplateType;
+
+
+typedef enum VkSubgroupFeatureFlagBits {
+ VK_SUBGROUP_FEATURE_BASIC_BIT = 0x00000001,
+ VK_SUBGROUP_FEATURE_VOTE_BIT = 0x00000002,
+ VK_SUBGROUP_FEATURE_ARITHMETIC_BIT = 0x00000004,
+ VK_SUBGROUP_FEATURE_BALLOT_BIT = 0x00000008,
+ VK_SUBGROUP_FEATURE_SHUFFLE_BIT = 0x00000010,
+ VK_SUBGROUP_FEATURE_SHUFFLE_RELATIVE_BIT = 0x00000020,
+ VK_SUBGROUP_FEATURE_CLUSTERED_BIT = 0x00000040,
+ VK_SUBGROUP_FEATURE_QUAD_BIT = 0x00000080,
+ VK_SUBGROUP_FEATURE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
+} VkSubgroupFeatureFlagBits;
+typedef VkFlags VkSubgroupFeatureFlags;
+
+typedef enum VkPeerMemoryFeatureFlagBits {
+ VK_PEER_MEMORY_FEATURE_COPY_SRC_BIT = 0x00000001,
+ VK_PEER_MEMORY_FEATURE_COPY_DST_BIT = 0x00000002,
+ VK_PEER_MEMORY_FEATURE_GENERIC_SRC_BIT = 0x00000004,
+ VK_PEER_MEMORY_FEATURE_GENERIC_DST_BIT = 0x00000008,
+ VK_PEER_MEMORY_FEATURE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
+} VkPeerMemoryFeatureFlagBits;
+typedef VkFlags VkPeerMemoryFeatureFlags;
+
+typedef enum VkMemoryAllocateFlagBits {
+ VK_MEMORY_ALLOCATE_DEVICE_MASK_BIT = 0x00000001,
+ VK_MEMORY_ALLOCATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
+} VkMemoryAllocateFlagBits;
+typedef VkFlags VkMemoryAllocateFlags;
+typedef VkFlags VkCommandPoolTrimFlags;
+typedef VkFlags VkDescriptorUpdateTemplateCreateFlags;
+
+typedef enum VkExternalMemoryHandleTypeFlagBits {
+ VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT = 0x00000001,
+ VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT = 0x00000002,
+ VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT = 0x00000004,
+ VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT = 0x00000008,
+ VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_KMT_BIT = 0x00000010,
+ VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_HEAP_BIT = 0x00000020,
+ VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_RESOURCE_BIT = 0x00000040,
+ VK_EXTERNAL_MEMORY_HANDLE_TYPE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
+} VkExternalMemoryHandleTypeFlagBits;
+typedef VkFlags VkExternalMemoryHandleTypeFlags;
+
+typedef enum VkExternalMemoryFeatureFlagBits {
+ VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT = 0x00000001,
+ VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT = 0x00000002,
+ VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT = 0x00000004,
+ VK_EXTERNAL_MEMORY_FEATURE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
+} VkExternalMemoryFeatureFlagBits;
+typedef VkFlags VkExternalMemoryFeatureFlags;
+
+typedef enum VkExternalFenceHandleTypeFlagBits {
+ VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT = 0x00000001,
+ VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_BIT = 0x00000002,
+ VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT = 0x00000004,
+ VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT = 0x00000008,
+ VK_EXTERNAL_FENCE_HANDLE_TYPE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
+} VkExternalFenceHandleTypeFlagBits;
+typedef VkFlags VkExternalFenceHandleTypeFlags;
+
+typedef enum VkExternalFenceFeatureFlagBits {
+ VK_EXTERNAL_FENCE_FEATURE_EXPORTABLE_BIT = 0x00000001,
+ VK_EXTERNAL_FENCE_FEATURE_IMPORTABLE_BIT = 0x00000002,
+ VK_EXTERNAL_FENCE_FEATURE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
+} VkExternalFenceFeatureFlagBits;
+typedef VkFlags VkExternalFenceFeatureFlags;
+
+typedef enum VkFenceImportFlagBits {
+ VK_FENCE_IMPORT_TEMPORARY_BIT = 0x00000001,
+ VK_FENCE_IMPORT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
+} VkFenceImportFlagBits;
+typedef VkFlags VkFenceImportFlags;
+
+typedef enum VkSemaphoreImportFlagBits {
+ VK_SEMAPHORE_IMPORT_TEMPORARY_BIT = 0x00000001,
+ VK_SEMAPHORE_IMPORT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
+} VkSemaphoreImportFlagBits;
+typedef VkFlags VkSemaphoreImportFlags;
+
+typedef enum VkExternalSemaphoreHandleTypeFlagBits {
+ VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT = 0x00000001,
+ VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT = 0x00000002,
+ VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT = 0x00000004,
+ VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT = 0x00000008,
+ VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT = 0x00000010,
+ VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
+} VkExternalSemaphoreHandleTypeFlagBits;
+typedef VkFlags VkExternalSemaphoreHandleTypeFlags;
+
+typedef enum VkExternalSemaphoreFeatureFlagBits {
+ VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT = 0x00000001,
+ VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT = 0x00000002,
+ VK_EXTERNAL_SEMAPHORE_FEATURE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
+} VkExternalSemaphoreFeatureFlagBits;
+typedef VkFlags VkExternalSemaphoreFeatureFlags;
+
+typedef struct VkPhysicalDeviceSubgroupProperties {
+ VkStructureType sType;
+ void* pNext;
+ uint32_t subgroupSize;
+ VkShaderStageFlags supportedStages;
+ VkSubgroupFeatureFlags supportedOperations;
+ VkBool32 quadOperationsInAllStages;
+} VkPhysicalDeviceSubgroupProperties;
+
+typedef struct VkBindBufferMemoryInfo {
+ VkStructureType sType;
+ const void* pNext;
+ VkBuffer buffer;
+ VkDeviceMemory memory;
+ VkDeviceSize memoryOffset;
+} VkBindBufferMemoryInfo;
+
+typedef struct VkBindImageMemoryInfo {
+ VkStructureType sType;
+ const void* pNext;
+ VkImage image;
+ VkDeviceMemory memory;
+ VkDeviceSize memoryOffset;
+} VkBindImageMemoryInfo;
+
+typedef struct VkPhysicalDevice16BitStorageFeatures {
+ VkStructureType sType;
+ void* pNext;
+ VkBool32 storageBuffer16BitAccess;
+ VkBool32 uniformAndStorageBuffer16BitAccess;
+ VkBool32 storagePushConstant16;
+ VkBool32 storageInputOutput16;
+} VkPhysicalDevice16BitStorageFeatures;
+
+typedef struct VkMemoryDedicatedRequirements {
+ VkStructureType sType;
+ void* pNext;
+ VkBool32 prefersDedicatedAllocation;
+ VkBool32 requiresDedicatedAllocation;
+} VkMemoryDedicatedRequirements;
+
+typedef struct VkMemoryDedicatedAllocateInfo {
+ VkStructureType sType;
+ const void* pNext;
+ VkImage image;
+ VkBuffer buffer;
+} VkMemoryDedicatedAllocateInfo;
+
+typedef struct VkMemoryAllocateFlagsInfo {
+ VkStructureType sType;
+ const void* pNext;
+ VkMemoryAllocateFlags flags;
+ uint32_t deviceMask;
+} VkMemoryAllocateFlagsInfo;
+
+typedef struct VkDeviceGroupRenderPassBeginInfo {
+ VkStructureType sType;
+ const void* pNext;
+ uint32_t deviceMask;
+ uint32_t deviceRenderAreaCount;
+ const VkRect2D* pDeviceRenderAreas;
+} VkDeviceGroupRenderPassBeginInfo;
+
+typedef struct VkDeviceGroupCommandBufferBeginInfo {
+ VkStructureType sType;
+ const void* pNext;
+ uint32_t deviceMask;
+} VkDeviceGroupCommandBufferBeginInfo;
+
+typedef struct VkDeviceGroupSubmitInfo {
+ VkStructureType sType;
+ const void* pNext;
+ uint32_t waitSemaphoreCount;
+ const uint32_t* pWaitSemaphoreDeviceIndices;
+ uint32_t commandBufferCount;
+ const uint32_t* pCommandBufferDeviceMasks;
+ uint32_t signalSemaphoreCount;
+ const uint32_t* pSignalSemaphoreDeviceIndices;
+} VkDeviceGroupSubmitInfo;
+
+typedef struct VkDeviceGroupBindSparseInfo {
+ VkStructureType sType;
+ const void* pNext;
+ uint32_t resourceDeviceIndex;
+ uint32_t memoryDeviceIndex;
+} VkDeviceGroupBindSparseInfo;
+
+typedef struct VkBindBufferMemoryDeviceGroupInfo {
+ VkStructureType sType;
+ const void* pNext;
+ uint32_t deviceIndexCount;
+ const uint32_t* pDeviceIndices;
+} VkBindBufferMemoryDeviceGroupInfo;
+
+typedef struct VkBindImageMemoryDeviceGroupInfo {
+ VkStructureType sType;
+ const void* pNext;
+ uint32_t deviceIndexCount;
+ const uint32_t* pDeviceIndices;
+ uint32_t SFRRectCount;
+ const VkRect2D* pSFRRects;
+} VkBindImageMemoryDeviceGroupInfo;
+
+typedef struct VkPhysicalDeviceGroupProperties {
+ VkStructureType sType;
+ void* pNext;
+ uint32_t physicalDeviceCount;
+ VkPhysicalDevice physicalDevices[VK_MAX_DEVICE_GROUP_SIZE];
+ VkBool32 subsetAllocation;
+} VkPhysicalDeviceGroupProperties;
+
+typedef struct VkDeviceGroupDeviceCreateInfo {
+ VkStructureType sType;
+ const void* pNext;
+ uint32_t physicalDeviceCount;
+ const VkPhysicalDevice* pPhysicalDevices;
+} VkDeviceGroupDeviceCreateInfo;
+
+typedef struct VkBufferMemoryRequirementsInfo2 {
+ VkStructureType sType;
+ const void* pNext;
+ VkBuffer buffer;
+} VkBufferMemoryRequirementsInfo2;
+
+typedef struct VkImageMemoryRequirementsInfo2 {
+ VkStructureType sType;
+ const void* pNext;
+ VkImage image;
+} VkImageMemoryRequirementsInfo2;
+
+typedef struct VkImageSparseMemoryRequirementsInfo2 {
+ VkStructureType sType;
+ const void* pNext;
+ VkImage image;
+} VkImageSparseMemoryRequirementsInfo2;
+
+typedef struct VkMemoryRequirements2 {
+ VkStructureType sType;
+ void* pNext;
+ VkMemoryRequirements memoryRequirements;
+} VkMemoryRequirements2;
+
+typedef struct VkSparseImageMemoryRequirements2 {
+ VkStructureType sType;
+ void* pNext;
+ VkSparseImageMemoryRequirements memoryRequirements;
+} VkSparseImageMemoryRequirements2;
+
+typedef struct VkPhysicalDeviceFeatures2 {
+ VkStructureType sType;
+ void* pNext;
+ VkPhysicalDeviceFeatures features;
+} VkPhysicalDeviceFeatures2;
+
+typedef struct VkPhysicalDeviceProperties2 {
+ VkStructureType sType;
+ void* pNext;
+ VkPhysicalDeviceProperties properties;
+} VkPhysicalDeviceProperties2;
+
+typedef struct VkFormatProperties2 {
+ VkStructureType sType;
+ void* pNext;
+ VkFormatProperties formatProperties;
+} VkFormatProperties2;
+
+typedef struct VkImageFormatProperties2 {
+ VkStructureType sType;
+ void* pNext;
+ VkImageFormatProperties imageFormatProperties;
+} VkImageFormatProperties2;
+
+typedef struct VkPhysicalDeviceImageFormatInfo2 {
+ VkStructureType sType;
+ const void* pNext;
+ VkFormat format;
+ VkImageType type;
+ VkImageTiling tiling;
+ VkImageUsageFlags usage;
+ VkImageCreateFlags flags;
+} VkPhysicalDeviceImageFormatInfo2;
+
+typedef struct VkQueueFamilyProperties2 {
+ VkStructureType sType;
+ void* pNext;
+ VkQueueFamilyProperties queueFamilyProperties;
+} VkQueueFamilyProperties2;
+
+typedef struct VkPhysicalDeviceMemoryProperties2 {
+ VkStructureType sType;
+ void* pNext;
+ VkPhysicalDeviceMemoryProperties memoryProperties;
+} VkPhysicalDeviceMemoryProperties2;
+
+typedef struct VkSparseImageFormatProperties2 {
+ VkStructureType sType;
+ void* pNext;
+ VkSparseImageFormatProperties properties;
+} VkSparseImageFormatProperties2;
+
+typedef struct VkPhysicalDeviceSparseImageFormatInfo2 {
+ VkStructureType sType;
+ const void* pNext;
+ VkFormat format;
+ VkImageType type;
+ VkSampleCountFlagBits samples;
+ VkImageUsageFlags usage;
+ VkImageTiling tiling;
+} VkPhysicalDeviceSparseImageFormatInfo2;
+
+typedef struct VkPhysicalDevicePointClippingProperties {
+ VkStructureType sType;
+ void* pNext;
+ VkPointClippingBehavior pointClippingBehavior;
+} VkPhysicalDevicePointClippingProperties;
+
+typedef struct VkInputAttachmentAspectReference {
+ uint32_t subpass;
+ uint32_t inputAttachmentIndex;
+ VkImageAspectFlags aspectMask;
+} VkInputAttachmentAspectReference;
+
+typedef struct VkRenderPassInputAttachmentAspectCreateInfo {
+ VkStructureType sType;
+ const void* pNext;
+ uint32_t aspectReferenceCount;
+ const VkInputAttachmentAspectReference* pAspectReferences;
+} VkRenderPassInputAttachmentAspectCreateInfo;
+
+typedef struct VkImageViewUsageCreateInfo {
+ VkStructureType sType;
+ const void* pNext;
+ VkImageUsageFlags usage;
+} VkImageViewUsageCreateInfo;
+
+typedef struct VkPipelineTessellationDomainOriginStateCreateInfo {
+ VkStructureType sType;
+ const void* pNext;
+ VkTessellationDomainOrigin domainOrigin;
+} VkPipelineTessellationDomainOriginStateCreateInfo;
+
+typedef struct VkRenderPassMultiviewCreateInfo {
+ VkStructureType sType;
+ const void* pNext;
+ uint32_t subpassCount;
+ const uint32_t* pViewMasks;
+ uint32_t dependencyCount;
+ const int32_t* pViewOffsets;
+ uint32_t correlationMaskCount;
+ const uint32_t* pCorrelationMasks;
+} VkRenderPassMultiviewCreateInfo;
+
+typedef struct VkPhysicalDeviceMultiviewFeatures {
+ VkStructureType sType;
+ void* pNext;
+ VkBool32 multiview;
+ VkBool32 multiviewGeometryShader;
+ VkBool32 multiviewTessellationShader;
+} VkPhysicalDeviceMultiviewFeatures;
+
+typedef struct VkPhysicalDeviceMultiviewProperties {
+ VkStructureType sType;
+ void* pNext;
+ uint32_t maxMultiviewViewCount;
+ uint32_t maxMultiviewInstanceIndex;
+} VkPhysicalDeviceMultiviewProperties;
+
+typedef struct VkPhysicalDeviceVariablePointerFeatures {
+ VkStructureType sType;
+ void* pNext;
+ VkBool32 variablePointersStorageBuffer;
+ VkBool32 variablePointers;
+} VkPhysicalDeviceVariablePointerFeatures;
+
+typedef struct VkPhysicalDeviceProtectedMemoryFeatures {
+ VkStructureType sType;
+ void* pNext;
+ VkBool32 protectedMemory;
+} VkPhysicalDeviceProtectedMemoryFeatures;
+
+typedef struct VkPhysicalDeviceProtectedMemoryProperties {
+ VkStructureType sType;
+ void* pNext;
+ VkBool32 protectedNoFault;
+} VkPhysicalDeviceProtectedMemoryProperties;
+
+typedef struct VkDeviceQueueInfo2 {
+ VkStructureType sType;
+ const void* pNext;
+ VkDeviceQueueCreateFlags flags;
+ uint32_t queueFamilyIndex;
+ uint32_t queueIndex;
+} VkDeviceQueueInfo2;
+
+typedef struct VkProtectedSubmitInfo {
+ VkStructureType sType;
+ const void* pNext;
+ VkBool32 protectedSubmit;
+} VkProtectedSubmitInfo;
+
+typedef struct VkSamplerYcbcrConversionCreateInfo {
+ VkStructureType sType;
+ const void* pNext;
+ VkFormat format;
+ VkSamplerYcbcrModelConversion ycbcrModel;
+ VkSamplerYcbcrRange ycbcrRange;
+ VkComponentMapping components;
+ VkChromaLocation xChromaOffset;
+ VkChromaLocation yChromaOffset;
+ VkFilter chromaFilter;
+ VkBool32 forceExplicitReconstruction;
+} VkSamplerYcbcrConversionCreateInfo;
+
+typedef struct VkSamplerYcbcrConversionInfo {
+ VkStructureType sType;
+ const void* pNext;
+ VkSamplerYcbcrConversion conversion;
+} VkSamplerYcbcrConversionInfo;
+
+typedef struct VkBindImagePlaneMemoryInfo {
+ VkStructureType sType;
+ const void* pNext;
+ VkImageAspectFlagBits planeAspect;
+} VkBindImagePlaneMemoryInfo;
+
+typedef struct VkImagePlaneMemoryRequirementsInfo {
+ VkStructureType sType;
+ const void* pNext;
+ VkImageAspectFlagBits planeAspect;
+} VkImagePlaneMemoryRequirementsInfo;
+
+typedef struct VkPhysicalDeviceSamplerYcbcrConversionFeatures {
+ VkStructureType sType;
+ void* pNext;
+ VkBool32 samplerYcbcrConversion;
+} VkPhysicalDeviceSamplerYcbcrConversionFeatures;
+
+typedef struct VkSamplerYcbcrConversionImageFormatProperties {
+ VkStructureType sType;
+ void* pNext;
+ uint32_t combinedImageSamplerDescriptorCount;
+} VkSamplerYcbcrConversionImageFormatProperties;
+
+typedef struct VkDescriptorUpdateTemplateEntry {
+ uint32_t dstBinding;
+ uint32_t dstArrayElement;
+ uint32_t descriptorCount;
+ VkDescriptorType descriptorType;
+ size_t offset;
+ size_t stride;
+} VkDescriptorUpdateTemplateEntry;
+
+typedef struct VkDescriptorUpdateTemplateCreateInfo {
+ VkStructureType sType;
+ void* pNext;
+ VkDescriptorUpdateTemplateCreateFlags flags;
+ uint32_t descriptorUpdateEntryCount;
+ const VkDescriptorUpdateTemplateEntry* pDescriptorUpdateEntries;
+ VkDescriptorUpdateTemplateType templateType;
+ VkDescriptorSetLayout descriptorSetLayout;
+ VkPipelineBindPoint pipelineBindPoint;
+ VkPipelineLayout pipelineLayout;
+ uint32_t set;
+} VkDescriptorUpdateTemplateCreateInfo;
+
+typedef struct VkExternalMemoryProperties {
+ VkExternalMemoryFeatureFlags externalMemoryFeatures;
+ VkExternalMemoryHandleTypeFlags exportFromImportedHandleTypes;
+ VkExternalMemoryHandleTypeFlags compatibleHandleTypes;
+} VkExternalMemoryProperties;
+
+typedef struct VkPhysicalDeviceExternalImageFormatInfo {
+ VkStructureType sType;
+ const void* pNext;
+ VkExternalMemoryHandleTypeFlagBits handleType;
+} VkPhysicalDeviceExternalImageFormatInfo;
+
+typedef struct VkExternalImageFormatProperties {
+ VkStructureType sType;
+ void* pNext;
+ VkExternalMemoryProperties externalMemoryProperties;
+} VkExternalImageFormatProperties;
+
+typedef struct VkPhysicalDeviceExternalBufferInfo {
+ VkStructureType sType;
+ const void* pNext;
+ VkBufferCreateFlags flags;
+ VkBufferUsageFlags usage;
+ VkExternalMemoryHandleTypeFlagBits handleType;
+} VkPhysicalDeviceExternalBufferInfo;
+
+typedef struct VkExternalBufferProperties {
+ VkStructureType sType;
+ void* pNext;
+ VkExternalMemoryProperties externalMemoryProperties;
+} VkExternalBufferProperties;
+
+typedef struct VkPhysicalDeviceIDProperties {
+ VkStructureType sType;
+ void* pNext;
+ uint8_t deviceUUID[VK_UUID_SIZE];
+ uint8_t driverUUID[VK_UUID_SIZE];
+ uint8_t deviceLUID[VK_LUID_SIZE];
+ uint32_t deviceNodeMask;
+ VkBool32 deviceLUIDValid;
+} VkPhysicalDeviceIDProperties;
+
+typedef struct VkExternalMemoryImageCreateInfo {
+ VkStructureType sType;
+ const void* pNext;
+ VkExternalMemoryHandleTypeFlags handleTypes;
+} VkExternalMemoryImageCreateInfo;
+
+typedef struct VkExternalMemoryBufferCreateInfo {
+ VkStructureType sType;
+ const void* pNext;
+ VkExternalMemoryHandleTypeFlags handleTypes;
+} VkExternalMemoryBufferCreateInfo;
+
+typedef struct VkExportMemoryAllocateInfo {
+ VkStructureType sType;
+ const void* pNext;
+ VkExternalMemoryHandleTypeFlags handleTypes;
+} VkExportMemoryAllocateInfo;
+
+typedef struct VkPhysicalDeviceExternalFenceInfo {
+ VkStructureType sType;
+ const void* pNext;
+ VkExternalFenceHandleTypeFlagBits handleType;
+} VkPhysicalDeviceExternalFenceInfo;
+
+typedef struct VkExternalFenceProperties {
+ VkStructureType sType;
+ void* pNext;
+ VkExternalFenceHandleTypeFlags exportFromImportedHandleTypes;
+ VkExternalFenceHandleTypeFlags compatibleHandleTypes;
+ VkExternalFenceFeatureFlags externalFenceFeatures;
+} VkExternalFenceProperties;
+
+typedef struct VkExportFenceCreateInfo {
+ VkStructureType sType;
+ const void* pNext;
+ VkExternalFenceHandleTypeFlags handleTypes;
+} VkExportFenceCreateInfo;
+
+typedef struct VkExportSemaphoreCreateInfo {
+ VkStructureType sType;
+ const void* pNext;
+ VkExternalSemaphoreHandleTypeFlags handleTypes;
+} VkExportSemaphoreCreateInfo;
+
+typedef struct VkPhysicalDeviceExternalSemaphoreInfo {
+ VkStructureType sType;
+ const void* pNext;
+ VkExternalSemaphoreHandleTypeFlagBits handleType;
+} VkPhysicalDeviceExternalSemaphoreInfo;
+
+typedef struct VkExternalSemaphoreProperties {
+ VkStructureType sType;
+ void* pNext;
+ VkExternalSemaphoreHandleTypeFlags exportFromImportedHandleTypes;
+ VkExternalSemaphoreHandleTypeFlags compatibleHandleTypes;
+ VkExternalSemaphoreFeatureFlags externalSemaphoreFeatures;
+} VkExternalSemaphoreProperties;
+
+typedef struct VkPhysicalDeviceMaintenance3Properties {
+ VkStructureType sType;
+ void* pNext;
+ uint32_t maxPerSetDescriptors;
+ VkDeviceSize maxMemoryAllocationSize;
+} VkPhysicalDeviceMaintenance3Properties;
+
+typedef struct VkDescriptorSetLayoutSupport {
+ VkStructureType sType;
+ void* pNext;
+ VkBool32 supported;
+} VkDescriptorSetLayoutSupport;
+
+typedef struct VkPhysicalDeviceShaderDrawParameterFeatures {
+ VkStructureType sType;
+ void* pNext;
+ VkBool32 shaderDrawParameters;
+} VkPhysicalDeviceShaderDrawParameterFeatures;
+
+
+typedef VkResult (VKAPI_PTR *PFN_vkEnumerateInstanceVersion)(uint32_t* pApiVersion);
+typedef VkResult (VKAPI_PTR *PFN_vkBindBufferMemory2)(VkDevice device, uint32_t bindInfoCount, const VkBindBufferMemoryInfo* pBindInfos);
+typedef VkResult (VKAPI_PTR *PFN_vkBindImageMemory2)(VkDevice device, uint32_t bindInfoCount, const VkBindImageMemoryInfo* pBindInfos);
+typedef void (VKAPI_PTR *PFN_vkGetDeviceGroupPeerMemoryFeatures)(VkDevice device, uint32_t heapIndex, uint32_t localDeviceIndex, uint32_t remoteDeviceIndex, VkPeerMemoryFeatureFlags* pPeerMemoryFeatures);
+typedef void (VKAPI_PTR *PFN_vkCmdSetDeviceMask)(VkCommandBuffer commandBuffer, uint32_t deviceMask);
+typedef void (VKAPI_PTR *PFN_vkCmdDispatchBase)(VkCommandBuffer commandBuffer, uint32_t baseGroupX, uint32_t baseGroupY, uint32_t baseGroupZ, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ);
+typedef VkResult (VKAPI_PTR *PFN_vkEnumeratePhysicalDeviceGroups)(VkInstance instance, uint32_t* pPhysicalDeviceGroupCount, VkPhysicalDeviceGroupProperties* pPhysicalDeviceGroupProperties);
+typedef void (VKAPI_PTR *PFN_vkGetImageMemoryRequirements2)(VkDevice device, const VkImageMemoryRequirementsInfo2* pInfo, VkMemoryRequirements2* pMemoryRequirements);
+typedef void (VKAPI_PTR *PFN_vkGetBufferMemoryRequirements2)(VkDevice device, const VkBufferMemoryRequirementsInfo2* pInfo, VkMemoryRequirements2* pMemoryRequirements);
+typedef void (VKAPI_PTR *PFN_vkGetImageSparseMemoryRequirements2)(VkDevice device, const VkImageSparseMemoryRequirementsInfo2* pInfo, uint32_t* pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements2* pSparseMemoryRequirements);
+typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceFeatures2)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures2* pFeatures);
+typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceProperties2)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties2* pProperties);
+typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceFormatProperties2)(VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties2* pFormatProperties);
+typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceImageFormatProperties2)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceImageFormatInfo2* pImageFormatInfo, VkImageFormatProperties2* pImageFormatProperties);
+typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceQueueFamilyProperties2)(VkPhysicalDevice physicalDevice, uint32_t* pQueueFamilyPropertyCount, VkQueueFamilyProperties2* pQueueFamilyProperties);
+typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceMemoryProperties2)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties2* pMemoryProperties);
+typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceSparseImageFormatProperties2)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSparseImageFormatInfo2* pFormatInfo, uint32_t* pPropertyCount, VkSparseImageFormatProperties2* pProperties);
+typedef void (VKAPI_PTR *PFN_vkTrimCommandPool)(VkDevice device, VkCommandPool commandPool, VkCommandPoolTrimFlags flags);
+typedef void (VKAPI_PTR *PFN_vkGetDeviceQueue2)(VkDevice device, const VkDeviceQueueInfo2* pQueueInfo, VkQueue* pQueue);
+typedef VkResult (VKAPI_PTR *PFN_vkCreateSamplerYcbcrConversion)(VkDevice device, const VkSamplerYcbcrConversionCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSamplerYcbcrConversion* pYcbcrConversion);
+typedef void (VKAPI_PTR *PFN_vkDestroySamplerYcbcrConversion)(VkDevice device, VkSamplerYcbcrConversion ycbcrConversion, const VkAllocationCallbacks* pAllocator);
+typedef VkResult (VKAPI_PTR *PFN_vkCreateDescriptorUpdateTemplate)(VkDevice device, const VkDescriptorUpdateTemplateCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDescriptorUpdateTemplate* pDescriptorUpdateTemplate);
+typedef void (VKAPI_PTR *PFN_vkDestroyDescriptorUpdateTemplate)(VkDevice device, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const VkAllocationCallbacks* pAllocator);
+typedef void (VKAPI_PTR *PFN_vkUpdateDescriptorSetWithTemplate)(VkDevice device, VkDescriptorSet descriptorSet, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const void* pData);
+typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceExternalBufferProperties)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalBufferInfo* pExternalBufferInfo, VkExternalBufferProperties* pExternalBufferProperties);
+typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceExternalFenceProperties)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalFenceInfo* pExternalFenceInfo, VkExternalFenceProperties* pExternalFenceProperties);
+typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceExternalSemaphoreProperties)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalSemaphoreInfo* pExternalSemaphoreInfo, VkExternalSemaphoreProperties* pExternalSemaphoreProperties);
+typedef void (VKAPI_PTR *PFN_vkGetDescriptorSetLayoutSupport)(VkDevice device, const VkDescriptorSetLayoutCreateInfo* pCreateInfo, VkDescriptorSetLayoutSupport* pSupport);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceVersion(
+ uint32_t* pApiVersion);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkBindBufferMemory2(
+ VkDevice device,
+ uint32_t bindInfoCount,
+ const VkBindBufferMemoryInfo* pBindInfos);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkBindImageMemory2(
+ VkDevice device,
+ uint32_t bindInfoCount,
+ const VkBindImageMemoryInfo* pBindInfos);
+
+VKAPI_ATTR void VKAPI_CALL vkGetDeviceGroupPeerMemoryFeatures(
+ VkDevice device,
+ uint32_t heapIndex,
+ uint32_t localDeviceIndex,
+ uint32_t remoteDeviceIndex,
+ VkPeerMemoryFeatureFlags* pPeerMemoryFeatures);
+
+VKAPI_ATTR void VKAPI_CALL vkCmdSetDeviceMask(
+ VkCommandBuffer commandBuffer,
+ uint32_t deviceMask);
+
+VKAPI_ATTR void VKAPI_CALL vkCmdDispatchBase(
+ VkCommandBuffer commandBuffer,
+ uint32_t baseGroupX,
+ uint32_t baseGroupY,
+ uint32_t baseGroupZ,
+ uint32_t groupCountX,
+ uint32_t groupCountY,
+ uint32_t groupCountZ);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkEnumeratePhysicalDeviceGroups(
+ VkInstance instance,
+ uint32_t* pPhysicalDeviceGroupCount,
+ VkPhysicalDeviceGroupProperties* pPhysicalDeviceGroupProperties);
+
+VKAPI_ATTR void VKAPI_CALL vkGetImageMemoryRequirements2(
+ VkDevice device,
+ const VkImageMemoryRequirementsInfo2* pInfo,
+ VkMemoryRequirements2* pMemoryRequirements);
+
+VKAPI_ATTR void VKAPI_CALL vkGetBufferMemoryRequirements2(
+ VkDevice device,
+ const VkBufferMemoryRequirementsInfo2* pInfo,
+ VkMemoryRequirements2* pMemoryRequirements);
+
+VKAPI_ATTR void VKAPI_CALL vkGetImageSparseMemoryRequirements2(
+ VkDevice device,
+ const VkImageSparseMemoryRequirementsInfo2* pInfo,
+ uint32_t* pSparseMemoryRequirementCount,
+ VkSparseImageMemoryRequirements2* pSparseMemoryRequirements);
+
+VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceFeatures2(
+ VkPhysicalDevice physicalDevice,
+ VkPhysicalDeviceFeatures2* pFeatures);
+
+VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceProperties2(
+ VkPhysicalDevice physicalDevice,
+ VkPhysicalDeviceProperties2* pProperties);
+
+VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceFormatProperties2(
+ VkPhysicalDevice physicalDevice,
+ VkFormat format,
+ VkFormatProperties2* pFormatProperties);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceImageFormatProperties2(
+ VkPhysicalDevice physicalDevice,
+ const VkPhysicalDeviceImageFormatInfo2* pImageFormatInfo,
+ VkImageFormatProperties2* pImageFormatProperties);
+
+VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceQueueFamilyProperties2(
+ VkPhysicalDevice physicalDevice,
+ uint32_t* pQueueFamilyPropertyCount,
+ VkQueueFamilyProperties2* pQueueFamilyProperties);
+
+VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceMemoryProperties2(
+ VkPhysicalDevice physicalDevice,
+ VkPhysicalDeviceMemoryProperties2* pMemoryProperties);
+
+VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceSparseImageFormatProperties2(
+ VkPhysicalDevice physicalDevice,
+ const VkPhysicalDeviceSparseImageFormatInfo2* pFormatInfo,
+ uint32_t* pPropertyCount,
+ VkSparseImageFormatProperties2* pProperties);
+
+VKAPI_ATTR void VKAPI_CALL vkTrimCommandPool(
+ VkDevice device,
+ VkCommandPool commandPool,
+ VkCommandPoolTrimFlags flags);
+
+VKAPI_ATTR void VKAPI_CALL vkGetDeviceQueue2(
+ VkDevice device,
+ const VkDeviceQueueInfo2* pQueueInfo,
+ VkQueue* pQueue);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkCreateSamplerYcbcrConversion(
+ VkDevice device,
+ const VkSamplerYcbcrConversionCreateInfo* pCreateInfo,
+ const VkAllocationCallbacks* pAllocator,
+ VkSamplerYcbcrConversion* pYcbcrConversion);
+
+VKAPI_ATTR void VKAPI_CALL vkDestroySamplerYcbcrConversion(
+ VkDevice device,
+ VkSamplerYcbcrConversion ycbcrConversion,
+ const VkAllocationCallbacks* pAllocator);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkCreateDescriptorUpdateTemplate(
+ VkDevice device,
+ const VkDescriptorUpdateTemplateCreateInfo* pCreateInfo,
+ const VkAllocationCallbacks* pAllocator,
+ VkDescriptorUpdateTemplate* pDescriptorUpdateTemplate);
+
+VKAPI_ATTR void VKAPI_CALL vkDestroyDescriptorUpdateTemplate(
+ VkDevice device,
+ VkDescriptorUpdateTemplate descriptorUpdateTemplate,
+ const VkAllocationCallbacks* pAllocator);
+
+VKAPI_ATTR void VKAPI_CALL vkUpdateDescriptorSetWithTemplate(
+ VkDevice device,
+ VkDescriptorSet descriptorSet,
+ VkDescriptorUpdateTemplate descriptorUpdateTemplate,
+ const void* pData);
+
+VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceExternalBufferProperties(
+ VkPhysicalDevice physicalDevice,
+ const VkPhysicalDeviceExternalBufferInfo* pExternalBufferInfo,
+ VkExternalBufferProperties* pExternalBufferProperties);
+
+VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceExternalFenceProperties(
+ VkPhysicalDevice physicalDevice,
+ const VkPhysicalDeviceExternalFenceInfo* pExternalFenceInfo,
+ VkExternalFenceProperties* pExternalFenceProperties);
+
+VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceExternalSemaphoreProperties(
+ VkPhysicalDevice physicalDevice,
+ const VkPhysicalDeviceExternalSemaphoreInfo* pExternalSemaphoreInfo,
+ VkExternalSemaphoreProperties* pExternalSemaphoreProperties);
+
+VKAPI_ATTR void VKAPI_CALL vkGetDescriptorSetLayoutSupport(
+ VkDevice device,
+ const VkDescriptorSetLayoutCreateInfo* pCreateInfo,
+ VkDescriptorSetLayoutSupport* pSupport);
+#endif
+
#define VK_KHR_surface 1
VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSurfaceKHR)
-#define VK_KHR_SURFACE_SPEC_VERSION 25
+#define VK_KHR_SURFACE_SPEC_VERSION 26
#define VK_KHR_SURFACE_EXTENSION_NAME "VK_KHR_surface"
#define VK_COLORSPACE_SRGB_NONLINEAR_KHR VK_COLOR_SPACE_SRGB_NONLINEAR_KHR
@@ -3355,6 +4351,7 @@
VK_COLOR_SPACE_ADOBERGB_LINEAR_EXT = 1000104011,
VK_COLOR_SPACE_ADOBERGB_NONLINEAR_EXT = 1000104012,
VK_COLOR_SPACE_PASS_THROUGH_EXT = 1000104013,
+ VK_COLOR_SPACE_EXTENDED_SRGB_NONLINEAR_EXT = 1000104014,
VK_COLOR_SPACE_BEGIN_RANGE_KHR = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR,
VK_COLOR_SPACE_END_RANGE_KHR = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR,
VK_COLOR_SPACE_RANGE_SIZE_KHR = (VK_COLOR_SPACE_SRGB_NONLINEAR_KHR - VK_COLOR_SPACE_SRGB_NONLINEAR_KHR + 1),
@@ -3398,6 +4395,15 @@
} VkCompositeAlphaFlagBitsKHR;
typedef VkFlags VkCompositeAlphaFlagsKHR;
+typedef enum VkDeviceGroupPresentModeFlagBitsKHR {
+ VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_BIT_KHR = 0x00000001,
+ VK_DEVICE_GROUP_PRESENT_MODE_REMOTE_BIT_KHR = 0x00000002,
+ VK_DEVICE_GROUP_PRESENT_MODE_SUM_BIT_KHR = 0x00000004,
+ VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_MULTI_DEVICE_BIT_KHR = 0x00000008,
+ VK_DEVICE_GROUP_PRESENT_MODE_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF
+} VkDeviceGroupPresentModeFlagBitsKHR;
+typedef VkFlags VkDeviceGroupPresentModeFlagsKHR;
+
typedef struct VkSurfaceCapabilitiesKHR {
uint32_t minImageCount;
uint32_t maxImageCount;
@@ -3456,12 +4462,13 @@
#define VK_KHR_swapchain 1
VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSwapchainKHR)
-#define VK_KHR_SWAPCHAIN_SPEC_VERSION 68
+#define VK_KHR_SWAPCHAIN_SPEC_VERSION 69
#define VK_KHR_SWAPCHAIN_EXTENSION_NAME "VK_KHR_swapchain"
typedef enum VkSwapchainCreateFlagBitsKHR {
- VK_SWAPCHAIN_CREATE_BIND_SFR_BIT_KHX = 0x00000001,
+ VK_SWAPCHAIN_CREATE_BIND_SFR_BIT_KHR = 0x00000001,
+ VK_SWAPCHAIN_CREATE_PROTECTED_BIT_KHR = 0x00000002,
VK_SWAPCHAIN_CREATE_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF
} VkSwapchainCreateFlagBitsKHR;
typedef VkFlags VkSwapchainCreateFlagsKHR;
@@ -3498,12 +4505,60 @@
VkResult* pResults;
} VkPresentInfoKHR;
+typedef struct VkImageSwapchainCreateInfoKHR {
+ VkStructureType sType;
+ const void* pNext;
+ VkSwapchainKHR swapchain;
+} VkImageSwapchainCreateInfoKHR;
+
+typedef struct VkBindImageMemorySwapchainInfoKHR {
+ VkStructureType sType;
+ const void* pNext;
+ VkSwapchainKHR swapchain;
+ uint32_t imageIndex;
+} VkBindImageMemorySwapchainInfoKHR;
+
+typedef struct VkAcquireNextImageInfoKHR {
+ VkStructureType sType;
+ const void* pNext;
+ VkSwapchainKHR swapchain;
+ uint64_t timeout;
+ VkSemaphore semaphore;
+ VkFence fence;
+ uint32_t deviceMask;
+} VkAcquireNextImageInfoKHR;
+
+typedef struct VkDeviceGroupPresentCapabilitiesKHR {
+ VkStructureType sType;
+ const void* pNext;
+ uint32_t presentMask[VK_MAX_DEVICE_GROUP_SIZE];
+ VkDeviceGroupPresentModeFlagsKHR modes;
+} VkDeviceGroupPresentCapabilitiesKHR;
+
+typedef struct VkDeviceGroupPresentInfoKHR {
+ VkStructureType sType;
+ const void* pNext;
+ uint32_t swapchainCount;
+ const uint32_t* pDeviceMasks;
+ VkDeviceGroupPresentModeFlagBitsKHR mode;
+} VkDeviceGroupPresentInfoKHR;
+
+typedef struct VkDeviceGroupSwapchainCreateInfoKHR {
+ VkStructureType sType;
+ const void* pNext;
+ VkDeviceGroupPresentModeFlagsKHR modes;
+} VkDeviceGroupSwapchainCreateInfoKHR;
+
typedef VkResult (VKAPI_PTR *PFN_vkCreateSwapchainKHR)(VkDevice device, const VkSwapchainCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSwapchainKHR* pSwapchain);
typedef void (VKAPI_PTR *PFN_vkDestroySwapchainKHR)(VkDevice device, VkSwapchainKHR swapchain, const VkAllocationCallbacks* pAllocator);
typedef VkResult (VKAPI_PTR *PFN_vkGetSwapchainImagesKHR)(VkDevice device, VkSwapchainKHR swapchain, uint32_t* pSwapchainImageCount, VkImage* pSwapchainImages);
typedef VkResult (VKAPI_PTR *PFN_vkAcquireNextImageKHR)(VkDevice device, VkSwapchainKHR swapchain, uint64_t timeout, VkSemaphore semaphore, VkFence fence, uint32_t* pImageIndex);
typedef VkResult (VKAPI_PTR *PFN_vkQueuePresentKHR)(VkQueue queue, const VkPresentInfoKHR* pPresentInfo);
+typedef VkResult (VKAPI_PTR *PFN_vkGetDeviceGroupPresentCapabilitiesKHR)(VkDevice device, VkDeviceGroupPresentCapabilitiesKHR* pDeviceGroupPresentCapabilities);
+typedef VkResult (VKAPI_PTR *PFN_vkGetDeviceGroupSurfacePresentModesKHR)(VkDevice device, VkSurfaceKHR surface, VkDeviceGroupPresentModeFlagsKHR* pModes);
+typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDevicePresentRectanglesKHR)(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t* pRectCount, VkRect2D* pRects);
+typedef VkResult (VKAPI_PTR *PFN_vkAcquireNextImage2KHR)(VkDevice device, const VkAcquireNextImageInfoKHR* pAcquireInfo, uint32_t* pImageIndex);
#ifndef VK_NO_PROTOTYPES
VKAPI_ATTR VkResult VKAPI_CALL vkCreateSwapchainKHR(
@@ -3534,6 +4589,26 @@
VKAPI_ATTR VkResult VKAPI_CALL vkQueuePresentKHR(
VkQueue queue,
const VkPresentInfoKHR* pPresentInfo);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkGetDeviceGroupPresentCapabilitiesKHR(
+ VkDevice device,
+ VkDeviceGroupPresentCapabilitiesKHR* pDeviceGroupPresentCapabilities);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkGetDeviceGroupSurfacePresentModesKHR(
+ VkDevice device,
+ VkSurfaceKHR surface,
+ VkDeviceGroupPresentModeFlagsKHR* pModes);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDevicePresentRectanglesKHR(
+ VkPhysicalDevice physicalDevice,
+ VkSurfaceKHR surface,
+ uint32_t* pRectCount,
+ VkRect2D* pRects);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkAcquireNextImage2KHR(
+ VkDevice device,
+ const VkAcquireNextImageInfoKHR* pAcquireInfo,
+ uint32_t* pImageIndex);
#endif
#define VK_KHR_display 1
@@ -3861,7 +4936,7 @@
#define VK_KHR_win32_surface 1
#include <windows.h>
-#define VK_KHR_WIN32_SURFACE_SPEC_VERSION 5
+#define VK_KHR_WIN32_SURFACE_SPEC_VERSION 6
#define VK_KHR_WIN32_SURFACE_EXTENSION_NAME "VK_KHR_win32_surface"
typedef VkFlags VkWin32SurfaceCreateFlagsKHR;
@@ -3896,114 +4971,141 @@
#define VK_KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE_EXTENSION_NAME "VK_KHR_sampler_mirror_clamp_to_edge"
+#define VK_KHR_multiview 1
+typedef VkPhysicalDeviceMultiviewFeatures VkPhysicalDeviceMultiviewFeaturesKHR;
+typedef VkPhysicalDeviceMultiviewProperties VkPhysicalDeviceMultiviewPropertiesKHR;
+typedef VkRenderPassMultiviewCreateInfo VkRenderPassMultiviewCreateInfoKHR;
+
+#define VK_KHR_MULTIVIEW_SPEC_VERSION 1
+#define VK_KHR_MULTIVIEW_EXTENSION_NAME "VK_KHR_multiview"
+#define VK_DEPENDENCY_VIEW_LOCAL_BIT_KHR VK_DEPENDENCY_VIEW_LOCAL_BIT
+#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES_KHR VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES
+#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES_KHR VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES
+#define VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO_KHR VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO
+
+
#define VK_KHR_get_physical_device_properties2 1
+typedef VkFormatProperties2 VkFormatProperties2KHR;
+typedef VkImageFormatProperties2 VkImageFormatProperties2KHR;
+typedef VkPhysicalDeviceFeatures2 VkPhysicalDeviceFeatures2KHR;
+typedef VkPhysicalDeviceImageFormatInfo2 VkPhysicalDeviceImageFormatInfo2KHR;
+typedef VkPhysicalDeviceMemoryProperties2 VkPhysicalDeviceMemoryProperties2KHR;
+typedef VkPhysicalDeviceProperties2 VkPhysicalDeviceProperties2KHR;
+typedef VkPhysicalDeviceSparseImageFormatInfo2 VkPhysicalDeviceSparseImageFormatInfo2KHR;
+typedef VkQueueFamilyProperties2 VkQueueFamilyProperties2KHR;
+typedef VkSparseImageFormatProperties2 VkSparseImageFormatProperties2KHR;
+
#define VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_SPEC_VERSION 1
#define VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME "VK_KHR_get_physical_device_properties2"
+#define VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2_KHR VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2
+#define VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2_KHR VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2
+#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2
+#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2_KHR VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2
+#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2_KHR VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2
+#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2
+#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SPARSE_IMAGE_FORMAT_INFO_2_KHR VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SPARSE_IMAGE_FORMAT_INFO_2
+#define VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2_KHR VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2
+#define VK_STRUCTURE_TYPE_SPARSE_IMAGE_FORMAT_PROPERTIES_2_KHR VK_STRUCTURE_TYPE_SPARSE_IMAGE_FORMAT_PROPERTIES_2
-typedef struct VkPhysicalDeviceFeatures2KHR {
- VkStructureType sType;
- void* pNext;
- VkPhysicalDeviceFeatures features;
-} VkPhysicalDeviceFeatures2KHR;
-
-typedef struct VkPhysicalDeviceProperties2KHR {
- VkStructureType sType;
- void* pNext;
- VkPhysicalDeviceProperties properties;
-} VkPhysicalDeviceProperties2KHR;
-
-typedef struct VkFormatProperties2KHR {
- VkStructureType sType;
- void* pNext;
- VkFormatProperties formatProperties;
-} VkFormatProperties2KHR;
-
-typedef struct VkImageFormatProperties2KHR {
- VkStructureType sType;
- void* pNext;
- VkImageFormatProperties imageFormatProperties;
-} VkImageFormatProperties2KHR;
-
-typedef struct VkPhysicalDeviceImageFormatInfo2KHR {
- VkStructureType sType;
- const void* pNext;
- VkFormat format;
- VkImageType type;
- VkImageTiling tiling;
- VkImageUsageFlags usage;
- VkImageCreateFlags flags;
-} VkPhysicalDeviceImageFormatInfo2KHR;
-
-typedef struct VkQueueFamilyProperties2KHR {
- VkStructureType sType;
- void* pNext;
- VkQueueFamilyProperties queueFamilyProperties;
-} VkQueueFamilyProperties2KHR;
-
-typedef struct VkPhysicalDeviceMemoryProperties2KHR {
- VkStructureType sType;
- void* pNext;
- VkPhysicalDeviceMemoryProperties memoryProperties;
-} VkPhysicalDeviceMemoryProperties2KHR;
-
-typedef struct VkSparseImageFormatProperties2KHR {
- VkStructureType sType;
- void* pNext;
- VkSparseImageFormatProperties properties;
-} VkSparseImageFormatProperties2KHR;
-
-typedef struct VkPhysicalDeviceSparseImageFormatInfo2KHR {
- VkStructureType sType;
- const void* pNext;
- VkFormat format;
- VkImageType type;
- VkSampleCountFlagBits samples;
- VkImageUsageFlags usage;
- VkImageTiling tiling;
-} VkPhysicalDeviceSparseImageFormatInfo2KHR;
-
-
-typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceFeatures2KHR)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures2KHR* pFeatures);
-typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceProperties2KHR)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties2KHR* pProperties);
-typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceFormatProperties2KHR)(VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties2KHR* pFormatProperties);
-typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceImageFormatProperties2KHR)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceImageFormatInfo2KHR* pImageFormatInfo, VkImageFormatProperties2KHR* pImageFormatProperties);
-typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceQueueFamilyProperties2KHR)(VkPhysicalDevice physicalDevice, uint32_t* pQueueFamilyPropertyCount, VkQueueFamilyProperties2KHR* pQueueFamilyProperties);
-typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceMemoryProperties2KHR)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties2KHR* pMemoryProperties);
-typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceSparseImageFormatProperties2KHR)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSparseImageFormatInfo2KHR* pFormatInfo, uint32_t* pPropertyCount, VkSparseImageFormatProperties2KHR* pProperties);
+typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceFeatures2KHR)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures2* pFeatures);
+typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceFormatProperties2KHR)(VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties2* pFormatProperties);
+typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceImageFormatProperties2KHR)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceImageFormatInfo2* pImageFormatInfo, VkImageFormatProperties2* pImageFormatProperties);
+typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceMemoryProperties2KHR)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties2* pMemoryProperties);
+typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceProperties2KHR)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties2* pProperties);
+typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceQueueFamilyProperties2KHR)(VkPhysicalDevice physicalDevice, uint32_t* pQueueFamilyPropertyCount, VkQueueFamilyProperties2* pQueueFamilyProperties);
+typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceSparseImageFormatProperties2KHR)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSparseImageFormatInfo2* pFormatInfo, uint32_t* pPropertyCount, VkSparseImageFormatProperties2* pProperties);
#ifndef VK_NO_PROTOTYPES
VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceFeatures2KHR(
VkPhysicalDevice physicalDevice,
- VkPhysicalDeviceFeatures2KHR* pFeatures);
-
-VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceProperties2KHR(
- VkPhysicalDevice physicalDevice,
- VkPhysicalDeviceProperties2KHR* pProperties);
+ VkPhysicalDeviceFeatures2* pFeatures);
VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceFormatProperties2KHR(
VkPhysicalDevice physicalDevice,
VkFormat format,
- VkFormatProperties2KHR* pFormatProperties);
+ VkFormatProperties2* pFormatProperties);
VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceImageFormatProperties2KHR(
VkPhysicalDevice physicalDevice,
- const VkPhysicalDeviceImageFormatInfo2KHR* pImageFormatInfo,
- VkImageFormatProperties2KHR* pImageFormatProperties);
+ const VkPhysicalDeviceImageFormatInfo2* pImageFormatInfo,
+ VkImageFormatProperties2* pImageFormatProperties);
+
+VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceMemoryProperties2KHR(
+ VkPhysicalDevice physicalDevice,
+ VkPhysicalDeviceMemoryProperties2* pMemoryProperties);
+
+VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceProperties2KHR(
+ VkPhysicalDevice physicalDevice,
+ VkPhysicalDeviceProperties2* pProperties);
VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceQueueFamilyProperties2KHR(
VkPhysicalDevice physicalDevice,
uint32_t* pQueueFamilyPropertyCount,
- VkQueueFamilyProperties2KHR* pQueueFamilyProperties);
-
-VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceMemoryProperties2KHR(
- VkPhysicalDevice physicalDevice,
- VkPhysicalDeviceMemoryProperties2KHR* pMemoryProperties);
+ VkQueueFamilyProperties2* pQueueFamilyProperties);
VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceSparseImageFormatProperties2KHR(
VkPhysicalDevice physicalDevice,
- const VkPhysicalDeviceSparseImageFormatInfo2KHR* pFormatInfo,
+ const VkPhysicalDeviceSparseImageFormatInfo2* pFormatInfo,
uint32_t* pPropertyCount,
- VkSparseImageFormatProperties2KHR* pProperties);
+ VkSparseImageFormatProperties2* pProperties);
+#endif
+
+#define VK_KHR_device_group 1
+typedef VkDeviceGroupBindSparseInfo VkDeviceGroupBindSparseInfoKHR;
+typedef VkDeviceGroupCommandBufferBeginInfo VkDeviceGroupCommandBufferBeginInfoKHR;
+typedef VkDeviceGroupRenderPassBeginInfo VkDeviceGroupRenderPassBeginInfoKHR;
+typedef VkDeviceGroupSubmitInfo VkDeviceGroupSubmitInfoKHR;
+typedef VkMemoryAllocateFlagBits VkMemoryAllocateFlagBitsKHR;
+typedef VkMemoryAllocateFlagsInfo VkMemoryAllocateFlagsInfoKHR;
+typedef VkMemoryAllocateFlags VkMemoryAllocateFlagsKHR;
+typedef VkPeerMemoryFeatureFlagBits VkPeerMemoryFeatureFlagBitsKHR;
+typedef VkPeerMemoryFeatureFlags VkPeerMemoryFeatureFlagsKHR;
+typedef VkBindBufferMemoryDeviceGroupInfo VkBindBufferMemoryDeviceGroupInfoKHR;
+typedef VkBindImageMemoryDeviceGroupInfo VkBindImageMemoryDeviceGroupInfoKHR;
+
+#define VK_KHR_DEVICE_GROUP_SPEC_VERSION 2
+#define VK_KHR_DEVICE_GROUP_EXTENSION_NAME "VK_KHR_device_group"
+#define VK_DEPENDENCY_DEVICE_GROUP_BIT_KHR VK_DEPENDENCY_DEVICE_GROUP_BIT
+#define VK_MEMORY_ALLOCATE_DEVICE_MASK_BIT_KHR VK_MEMORY_ALLOCATE_DEVICE_MASK_BIT
+#define VK_PEER_MEMORY_FEATURE_COPY_DST_BIT_KHR VK_PEER_MEMORY_FEATURE_COPY_DST_BIT
+#define VK_PEER_MEMORY_FEATURE_COPY_SRC_BIT_KHR VK_PEER_MEMORY_FEATURE_COPY_SRC_BIT
+#define VK_PEER_MEMORY_FEATURE_GENERIC_DST_BIT_KHR VK_PEER_MEMORY_FEATURE_GENERIC_DST_BIT
+#define VK_PEER_MEMORY_FEATURE_GENERIC_SRC_BIT_KHR VK_PEER_MEMORY_FEATURE_GENERIC_SRC_BIT
+#define VK_PIPELINE_CREATE_DISPATCH_BASE_KHR VK_PIPELINE_CREATE_DISPATCH_BASE
+#define VK_PIPELINE_CREATE_VIEW_INDEX_FROM_DEVICE_INDEX_BIT_KHR VK_PIPELINE_CREATE_VIEW_INDEX_FROM_DEVICE_INDEX_BIT
+#define VK_STRUCTURE_TYPE_DEVICE_GROUP_BIND_SPARSE_INFO_KHR VK_STRUCTURE_TYPE_DEVICE_GROUP_BIND_SPARSE_INFO
+#define VK_STRUCTURE_TYPE_DEVICE_GROUP_COMMAND_BUFFER_BEGIN_INFO_KHR VK_STRUCTURE_TYPE_DEVICE_GROUP_COMMAND_BUFFER_BEGIN_INFO
+#define VK_STRUCTURE_TYPE_DEVICE_GROUP_RENDER_PASS_BEGIN_INFO_KHR VK_STRUCTURE_TYPE_DEVICE_GROUP_RENDER_PASS_BEGIN_INFO
+#define VK_STRUCTURE_TYPE_DEVICE_GROUP_SUBMIT_INFO_KHR VK_STRUCTURE_TYPE_DEVICE_GROUP_SUBMIT_INFO
+#define VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO_KHR VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO
+#define VK_IMAGE_CREATE_BIND_SFR_BIT_KHR VK_IMAGE_CREATE_BIND_SFR_BIT
+#define VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_DEVICE_GROUP_INFO_KHR VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_DEVICE_GROUP_INFO
+#define VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_DEVICE_GROUP_INFO_KHR VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_DEVICE_GROUP_INFO
+
+typedef void (VKAPI_PTR *PFN_vkCmdDispatchBaseKHR)(VkCommandBuffer commandBuffer, uint32_t baseGroupX, uint32_t baseGroupY, uint32_t baseGroupZ, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ);
+typedef void (VKAPI_PTR *PFN_vkCmdSetDeviceMaskKHR)(VkCommandBuffer commandBuffer, uint32_t deviceMask);
+typedef void (VKAPI_PTR *PFN_vkGetDeviceGroupPeerMemoryFeaturesKHR)(VkDevice device, uint32_t heapIndex, uint32_t localDeviceIndex, uint32_t remoteDeviceIndex, VkPeerMemoryFeatureFlags* pPeerMemoryFeatures);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR void VKAPI_CALL vkCmdDispatchBaseKHR(
+ VkCommandBuffer commandBuffer,
+ uint32_t baseGroupX,
+ uint32_t baseGroupY,
+ uint32_t baseGroupZ,
+ uint32_t groupCountX,
+ uint32_t groupCountY,
+ uint32_t groupCountZ);
+
+VKAPI_ATTR void VKAPI_CALL vkCmdSetDeviceMaskKHR(
+ VkCommandBuffer commandBuffer,
+ uint32_t deviceMask);
+
+VKAPI_ATTR void VKAPI_CALL vkGetDeviceGroupPeerMemoryFeaturesKHR(
+ VkDevice device,
+ uint32_t heapIndex,
+ uint32_t localDeviceIndex,
+ uint32_t remoteDeviceIndex,
+ VkPeerMemoryFeatureFlags* pPeerMemoryFeatures);
#endif
#define VK_KHR_shader_draw_parameters 1
@@ -4012,22 +5114,343 @@
#define VK_KHR_maintenance1 1
+typedef VkCommandPoolTrimFlags VkCommandPoolTrimFlagsKHR;
+
#define VK_KHR_MAINTENANCE1_SPEC_VERSION 1
#define VK_KHR_MAINTENANCE1_EXTENSION_NAME "VK_KHR_maintenance1"
+#define VK_ERROR_OUT_OF_POOL_MEMORY_KHR VK_ERROR_OUT_OF_POOL_MEMORY
+#define VK_FORMAT_FEATURE_TRANSFER_DST_BIT_KHR VK_FORMAT_FEATURE_TRANSFER_DST_BIT
+#define VK_FORMAT_FEATURE_TRANSFER_SRC_BIT_KHR VK_FORMAT_FEATURE_TRANSFER_SRC_BIT
+#define VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT_KHR VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT
-typedef VkFlags VkCommandPoolTrimFlagsKHR;
-
-typedef void (VKAPI_PTR *PFN_vkTrimCommandPoolKHR)(VkDevice device, VkCommandPool commandPool, VkCommandPoolTrimFlagsKHR flags);
+typedef void (VKAPI_PTR *PFN_vkTrimCommandPoolKHR)(VkDevice device, VkCommandPool commandPool, VkCommandPoolTrimFlags flags);
#ifndef VK_NO_PROTOTYPES
VKAPI_ATTR void VKAPI_CALL vkTrimCommandPoolKHR(
VkDevice device,
VkCommandPool commandPool,
- VkCommandPoolTrimFlagsKHR flags);
+ VkCommandPoolTrimFlags flags);
+#endif
+
+#define VK_KHR_device_group_creation 1
+typedef VkDeviceGroupDeviceCreateInfo VkDeviceGroupDeviceCreateInfoKHR;
+typedef VkPhysicalDeviceGroupProperties VkPhysicalDeviceGroupPropertiesKHR;
+
+#define VK_KHR_DEVICE_GROUP_CREATION_SPEC_VERSION 1
+#define VK_KHR_DEVICE_GROUP_CREATION_EXTENSION_NAME "VK_KHR_device_group_creation"
+#define VK_MAX_DEVICE_GROUP_SIZE_KHR VK_MAX_DEVICE_GROUP_SIZE
+#define VK_MEMORY_HEAP_MULTI_INSTANCE_BIT_KHR VK_MEMORY_HEAP_MULTI_INSTANCE_BIT
+#define VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO_KHR VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO
+#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES_KHR VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES
+
+typedef VkResult (VKAPI_PTR *PFN_vkEnumeratePhysicalDeviceGroupsKHR)(VkInstance instance, uint32_t* pPhysicalDeviceGroupCount, VkPhysicalDeviceGroupProperties* pPhysicalDeviceGroupProperties);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR VkResult VKAPI_CALL vkEnumeratePhysicalDeviceGroupsKHR(
+ VkInstance instance,
+ uint32_t* pPhysicalDeviceGroupCount,
+ VkPhysicalDeviceGroupProperties* pPhysicalDeviceGroupProperties);
+#endif
+
+#define VK_KHR_external_memory_capabilities 1
+typedef VkExternalBufferProperties VkExternalBufferPropertiesKHR;
+typedef VkExternalImageFormatProperties VkExternalImageFormatPropertiesKHR;
+typedef VkExternalMemoryFeatureFlagBits VkExternalMemoryFeatureFlagBitsKHR;
+typedef VkExternalMemoryFeatureFlags VkExternalMemoryFeatureFlagsKHR;
+typedef VkExternalMemoryHandleTypeFlagBits VkExternalMemoryHandleTypeFlagBitsKHR;
+typedef VkExternalMemoryHandleTypeFlags VkExternalMemoryHandleTypeFlagsKHR;
+typedef VkExternalMemoryProperties VkExternalMemoryPropertiesKHR;
+typedef VkPhysicalDeviceExternalBufferInfo VkPhysicalDeviceExternalBufferInfoKHR;
+typedef VkPhysicalDeviceExternalImageFormatInfo VkPhysicalDeviceExternalImageFormatInfoKHR;
+typedef VkPhysicalDeviceIDProperties VkPhysicalDeviceIDPropertiesKHR;
+
+#define VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_SPEC_VERSION 1
+#define VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME "VK_KHR_external_memory_capabilities"
+#define VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT_KHR VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT
+#define VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT_KHR VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT
+#define VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT_KHR VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT
+#define VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT_KHR VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT
+#define VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_KMT_BIT_KHR VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_KMT_BIT
+#define VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_HEAP_BIT_KHR VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_HEAP_BIT
+#define VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_RESOURCE_BIT_KHR VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_RESOURCE_BIT
+#define VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT
+#define VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT
+#define VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHR VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT
+#define VK_LUID_SIZE_KHR VK_LUID_SIZE
+#define VK_STRUCTURE_TYPE_EXTERNAL_BUFFER_PROPERTIES_KHR VK_STRUCTURE_TYPE_EXTERNAL_BUFFER_PROPERTIES
+#define VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES_KHR VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES
+#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_BUFFER_INFO_KHR VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_BUFFER_INFO
+#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO_KHR VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO
+#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES_KHR VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES
+
+typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceExternalBufferPropertiesKHR)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalBufferInfo* pExternalBufferInfo, VkExternalBufferProperties* pExternalBufferProperties);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceExternalBufferPropertiesKHR(
+ VkPhysicalDevice physicalDevice,
+ const VkPhysicalDeviceExternalBufferInfo* pExternalBufferInfo,
+ VkExternalBufferProperties* pExternalBufferProperties);
+#endif
+
+#define VK_KHR_external_memory 1
+typedef VkExportMemoryAllocateInfo VkExportMemoryAllocateInfoKHR;
+typedef VkExternalMemoryBufferCreateInfo VkExternalMemoryBufferCreateInfoKHR;
+typedef VkExternalMemoryImageCreateInfo VkExternalMemoryImageCreateInfoKHR;
+
+#define VK_KHR_EXTERNAL_MEMORY_SPEC_VERSION 1
+#define VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME "VK_KHR_external_memory"
+#define VK_ERROR_INVALID_EXTERNAL_HANDLE_KHR VK_ERROR_INVALID_EXTERNAL_HANDLE
+#define VK_QUEUE_FAMILY_EXTERNAL_KHR VK_QUEUE_FAMILY_EXTERNAL
+#define VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_KHR VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO
+#define VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO_KHR VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO
+#define VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO_KHR VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO
+
+
+#ifdef VK_USE_PLATFORM_WIN32_KHR
+#define VK_KHR_external_memory_win32 1
+#define VK_KHR_EXTERNAL_MEMORY_WIN32_SPEC_VERSION 1
+#define VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME "VK_KHR_external_memory_win32"
+
+typedef struct VkImportMemoryWin32HandleInfoKHR {
+ VkStructureType sType;
+ const void* pNext;
+ VkExternalMemoryHandleTypeFlagBits handleType;
+ HANDLE handle;
+ LPCWSTR name;
+} VkImportMemoryWin32HandleInfoKHR;
+
+typedef struct VkExportMemoryWin32HandleInfoKHR {
+ VkStructureType sType;
+ const void* pNext;
+ const SECURITY_ATTRIBUTES* pAttributes;
+ DWORD dwAccess;
+ LPCWSTR name;
+} VkExportMemoryWin32HandleInfoKHR;
+
+typedef struct VkMemoryWin32HandlePropertiesKHR {
+ VkStructureType sType;
+ void* pNext;
+ uint32_t memoryTypeBits;
+} VkMemoryWin32HandlePropertiesKHR;
+
+typedef struct VkMemoryGetWin32HandleInfoKHR {
+ VkStructureType sType;
+ const void* pNext;
+ VkDeviceMemory memory;
+ VkExternalMemoryHandleTypeFlagBits handleType;
+} VkMemoryGetWin32HandleInfoKHR;
+
+
+typedef VkResult (VKAPI_PTR *PFN_vkGetMemoryWin32HandleKHR)(VkDevice device, const VkMemoryGetWin32HandleInfoKHR* pGetWin32HandleInfo, HANDLE* pHandle);
+typedef VkResult (VKAPI_PTR *PFN_vkGetMemoryWin32HandlePropertiesKHR)(VkDevice device, VkExternalMemoryHandleTypeFlagBits handleType, HANDLE handle, VkMemoryWin32HandlePropertiesKHR* pMemoryWin32HandleProperties);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR VkResult VKAPI_CALL vkGetMemoryWin32HandleKHR(
+ VkDevice device,
+ const VkMemoryGetWin32HandleInfoKHR* pGetWin32HandleInfo,
+ HANDLE* pHandle);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkGetMemoryWin32HandlePropertiesKHR(
+ VkDevice device,
+ VkExternalMemoryHandleTypeFlagBits handleType,
+ HANDLE handle,
+ VkMemoryWin32HandlePropertiesKHR* pMemoryWin32HandleProperties);
+#endif
+#endif /* VK_USE_PLATFORM_WIN32_KHR */
+
+#define VK_KHR_external_memory_fd 1
+#define VK_KHR_EXTERNAL_MEMORY_FD_SPEC_VERSION 1
+#define VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME "VK_KHR_external_memory_fd"
+
+typedef struct VkImportMemoryFdInfoKHR {
+ VkStructureType sType;
+ const void* pNext;
+ VkExternalMemoryHandleTypeFlagBits handleType;
+ int fd;
+} VkImportMemoryFdInfoKHR;
+
+typedef struct VkMemoryFdPropertiesKHR {
+ VkStructureType sType;
+ void* pNext;
+ uint32_t memoryTypeBits;
+} VkMemoryFdPropertiesKHR;
+
+typedef struct VkMemoryGetFdInfoKHR {
+ VkStructureType sType;
+ const void* pNext;
+ VkDeviceMemory memory;
+ VkExternalMemoryHandleTypeFlagBits handleType;
+} VkMemoryGetFdInfoKHR;
+
+
+typedef VkResult (VKAPI_PTR *PFN_vkGetMemoryFdKHR)(VkDevice device, const VkMemoryGetFdInfoKHR* pGetFdInfo, int* pFd);
+typedef VkResult (VKAPI_PTR *PFN_vkGetMemoryFdPropertiesKHR)(VkDevice device, VkExternalMemoryHandleTypeFlagBits handleType, int fd, VkMemoryFdPropertiesKHR* pMemoryFdProperties);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR VkResult VKAPI_CALL vkGetMemoryFdKHR(
+ VkDevice device,
+ const VkMemoryGetFdInfoKHR* pGetFdInfo,
+ int* pFd);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkGetMemoryFdPropertiesKHR(
+ VkDevice device,
+ VkExternalMemoryHandleTypeFlagBits handleType,
+ int fd,
+ VkMemoryFdPropertiesKHR* pMemoryFdProperties);
+#endif
+
+#ifdef VK_USE_PLATFORM_WIN32_KHR
+#define VK_KHR_win32_keyed_mutex 1
+#define VK_KHR_WIN32_KEYED_MUTEX_SPEC_VERSION 1
+#define VK_KHR_WIN32_KEYED_MUTEX_EXTENSION_NAME "VK_KHR_win32_keyed_mutex"
+
+typedef struct VkWin32KeyedMutexAcquireReleaseInfoKHR {
+ VkStructureType sType;
+ const void* pNext;
+ uint32_t acquireCount;
+ const VkDeviceMemory* pAcquireSyncs;
+ const uint64_t* pAcquireKeys;
+ const uint32_t* pAcquireTimeouts;
+ uint32_t releaseCount;
+ const VkDeviceMemory* pReleaseSyncs;
+ const uint64_t* pReleaseKeys;
+} VkWin32KeyedMutexAcquireReleaseInfoKHR;
+
+
+#endif /* VK_USE_PLATFORM_WIN32_KHR */
+
+#define VK_KHR_external_semaphore_capabilities 1
+typedef VkExternalSemaphoreFeatureFlagBits VkExternalSemaphoreFeatureFlagBitsKHR;
+typedef VkExternalSemaphoreFeatureFlags VkExternalSemaphoreFeatureFlagsKHR;
+typedef VkExternalSemaphoreHandleTypeFlagBits VkExternalSemaphoreHandleTypeFlagBitsKHR;
+typedef VkExternalSemaphoreHandleTypeFlags VkExternalSemaphoreHandleTypeFlagsKHR;
+typedef VkExternalSemaphoreProperties VkExternalSemaphorePropertiesKHR;
+typedef VkPhysicalDeviceExternalSemaphoreInfo VkPhysicalDeviceExternalSemaphoreInfoKHR;
+
+#define VK_KHR_EXTERNAL_SEMAPHORE_CAPABILITIES_SPEC_VERSION 1
+#define VK_KHR_EXTERNAL_SEMAPHORE_CAPABILITIES_EXTENSION_NAME "VK_KHR_external_semaphore_capabilities"
+#define VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT_KHR VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT
+#define VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT_KHR VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT
+#define VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT_KHR VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT
+#define VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT_KHR VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT
+#define VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT
+#define VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHR VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT
+#define VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT_KHR VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT
+#define VK_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_PROPERTIES_KHR VK_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_PROPERTIES
+#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO_KHR VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO
+
+typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceExternalSemaphorePropertiesKHR)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalSemaphoreInfo* pExternalSemaphoreInfo, VkExternalSemaphoreProperties* pExternalSemaphoreProperties);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceExternalSemaphorePropertiesKHR(
+ VkPhysicalDevice physicalDevice,
+ const VkPhysicalDeviceExternalSemaphoreInfo* pExternalSemaphoreInfo,
+ VkExternalSemaphoreProperties* pExternalSemaphoreProperties);
+#endif
+
+#define VK_KHR_external_semaphore 1
+typedef VkExportSemaphoreCreateInfo VkExportSemaphoreCreateInfoKHR;
+typedef VkSemaphoreImportFlagBits VkSemaphoreImportFlagBitsKHR;
+typedef VkSemaphoreImportFlags VkSemaphoreImportFlagsKHR;
+
+#define VK_KHR_EXTERNAL_SEMAPHORE_SPEC_VERSION 1
+#define VK_KHR_EXTERNAL_SEMAPHORE_EXTENSION_NAME "VK_KHR_external_semaphore"
+#define VK_SEMAPHORE_IMPORT_TEMPORARY_BIT_KHR VK_SEMAPHORE_IMPORT_TEMPORARY_BIT
+#define VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO_KHR VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO
+
+
+#ifdef VK_USE_PLATFORM_WIN32_KHR
+#define VK_KHR_external_semaphore_win32 1
+#define VK_KHR_EXTERNAL_SEMAPHORE_WIN32_SPEC_VERSION 1
+#define VK_KHR_EXTERNAL_SEMAPHORE_WIN32_EXTENSION_NAME "VK_KHR_external_semaphore_win32"
+
+typedef struct VkImportSemaphoreWin32HandleInfoKHR {
+ VkStructureType sType;
+ const void* pNext;
+ VkSemaphore semaphore;
+ VkSemaphoreImportFlags flags;
+ VkExternalSemaphoreHandleTypeFlagBits handleType;
+ HANDLE handle;
+ LPCWSTR name;
+} VkImportSemaphoreWin32HandleInfoKHR;
+
+typedef struct VkExportSemaphoreWin32HandleInfoKHR {
+ VkStructureType sType;
+ const void* pNext;
+ const SECURITY_ATTRIBUTES* pAttributes;
+ DWORD dwAccess;
+ LPCWSTR name;
+} VkExportSemaphoreWin32HandleInfoKHR;
+
+typedef struct VkD3D12FenceSubmitInfoKHR {
+ VkStructureType sType;
+ const void* pNext;
+ uint32_t waitSemaphoreValuesCount;
+ const uint64_t* pWaitSemaphoreValues;
+ uint32_t signalSemaphoreValuesCount;
+ const uint64_t* pSignalSemaphoreValues;
+} VkD3D12FenceSubmitInfoKHR;
+
+typedef struct VkSemaphoreGetWin32HandleInfoKHR {
+ VkStructureType sType;
+ const void* pNext;
+ VkSemaphore semaphore;
+ VkExternalSemaphoreHandleTypeFlagBits handleType;
+} VkSemaphoreGetWin32HandleInfoKHR;
+
+
+typedef VkResult (VKAPI_PTR *PFN_vkImportSemaphoreWin32HandleKHR)(VkDevice device, const VkImportSemaphoreWin32HandleInfoKHR* pImportSemaphoreWin32HandleInfo);
+typedef VkResult (VKAPI_PTR *PFN_vkGetSemaphoreWin32HandleKHR)(VkDevice device, const VkSemaphoreGetWin32HandleInfoKHR* pGetWin32HandleInfo, HANDLE* pHandle);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR VkResult VKAPI_CALL vkImportSemaphoreWin32HandleKHR(
+ VkDevice device,
+ const VkImportSemaphoreWin32HandleInfoKHR* pImportSemaphoreWin32HandleInfo);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkGetSemaphoreWin32HandleKHR(
+ VkDevice device,
+ const VkSemaphoreGetWin32HandleInfoKHR* pGetWin32HandleInfo,
+ HANDLE* pHandle);
+#endif
+#endif /* VK_USE_PLATFORM_WIN32_KHR */
+
+#define VK_KHR_external_semaphore_fd 1
+#define VK_KHR_EXTERNAL_SEMAPHORE_FD_SPEC_VERSION 1
+#define VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME "VK_KHR_external_semaphore_fd"
+
+typedef struct VkImportSemaphoreFdInfoKHR {
+ VkStructureType sType;
+ const void* pNext;
+ VkSemaphore semaphore;
+ VkSemaphoreImportFlags flags;
+ VkExternalSemaphoreHandleTypeFlagBits handleType;
+ int fd;
+} VkImportSemaphoreFdInfoKHR;
+
+typedef struct VkSemaphoreGetFdInfoKHR {
+ VkStructureType sType;
+ const void* pNext;
+ VkSemaphore semaphore;
+ VkExternalSemaphoreHandleTypeFlagBits handleType;
+} VkSemaphoreGetFdInfoKHR;
+
+
+typedef VkResult (VKAPI_PTR *PFN_vkImportSemaphoreFdKHR)(VkDevice device, const VkImportSemaphoreFdInfoKHR* pImportSemaphoreFdInfo);
+typedef VkResult (VKAPI_PTR *PFN_vkGetSemaphoreFdKHR)(VkDevice device, const VkSemaphoreGetFdInfoKHR* pGetFdInfo, int* pFd);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR VkResult VKAPI_CALL vkImportSemaphoreFdKHR(
+ VkDevice device,
+ const VkImportSemaphoreFdInfoKHR* pImportSemaphoreFdInfo);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkGetSemaphoreFdKHR(
+ VkDevice device,
+ const VkSemaphoreGetFdInfoKHR* pGetFdInfo,
+ int* pFd);
#endif
#define VK_KHR_push_descriptor 1
-#define VK_KHR_PUSH_DESCRIPTOR_SPEC_VERSION 1
+#define VK_KHR_PUSH_DESCRIPTOR_SPEC_VERSION 2
#define VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME "VK_KHR_push_descriptor"
typedef struct VkPhysicalDevicePushDescriptorPropertiesKHR {
@@ -4038,6 +5461,7 @@
typedef void (VKAPI_PTR *PFN_vkCmdPushDescriptorSetKHR)(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipelineLayout layout, uint32_t set, uint32_t descriptorWriteCount, const VkWriteDescriptorSet* pDescriptorWrites);
+typedef void (VKAPI_PTR *PFN_vkCmdPushDescriptorSetWithTemplateKHR)(VkCommandBuffer commandBuffer, VkDescriptorUpdateTemplate descriptorUpdateTemplate, VkPipelineLayout layout, uint32_t set, const void* pData);
#ifndef VK_NO_PROTOTYPES
VKAPI_ATTR void VKAPI_CALL vkCmdPushDescriptorSetKHR(
@@ -4047,8 +5471,23 @@
uint32_t set,
uint32_t descriptorWriteCount,
const VkWriteDescriptorSet* pDescriptorWrites);
+
+VKAPI_ATTR void VKAPI_CALL vkCmdPushDescriptorSetWithTemplateKHR(
+ VkCommandBuffer commandBuffer,
+ VkDescriptorUpdateTemplate descriptorUpdateTemplate,
+ VkPipelineLayout layout,
+ uint32_t set,
+ const void* pData);
#endif
+#define VK_KHR_16bit_storage 1
+typedef VkPhysicalDevice16BitStorageFeatures VkPhysicalDevice16BitStorageFeaturesKHR;
+
+#define VK_KHR_16BIT_STORAGE_SPEC_VERSION 1
+#define VK_KHR_16BIT_STORAGE_EXTENSION_NAME "VK_KHR_16bit_storage"
+#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES_KHR VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES
+
+
#define VK_KHR_incremental_present 1
#define VK_KHR_INCREMENTAL_PRESENT_SPEC_VERSION 1
#define VK_KHR_INCREMENTAL_PRESENT_EXTENSION_NAME "VK_KHR_incremental_present"
@@ -4074,74 +5513,39 @@
#define VK_KHR_descriptor_update_template 1
-VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDescriptorUpdateTemplateKHR)
+typedef VkDescriptorUpdateTemplateCreateFlags VkDescriptorUpdateTemplateCreateFlagsKHR;
+typedef VkDescriptorUpdateTemplateCreateInfo VkDescriptorUpdateTemplateCreateInfoKHR;
+typedef VkDescriptorUpdateTemplateEntry VkDescriptorUpdateTemplateEntryKHR;
+typedef VkDescriptorUpdateTemplate VkDescriptorUpdateTemplateKHR;
+typedef VkDescriptorUpdateTemplateType VkDescriptorUpdateTemplateTypeKHR;
#define VK_KHR_DESCRIPTOR_UPDATE_TEMPLATE_SPEC_VERSION 1
#define VK_KHR_DESCRIPTOR_UPDATE_TEMPLATE_EXTENSION_NAME "VK_KHR_descriptor_update_template"
+#define VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET_KHR VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET
+#define VK_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_KHR VK_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE
+#define VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO_KHR VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO
+#define VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_KHR_EXT VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_EXT
-
-typedef enum VkDescriptorUpdateTemplateTypeKHR {
- VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET_KHR = 0,
- VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_PUSH_DESCRIPTORS_KHR = 1,
- VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_BEGIN_RANGE_KHR = VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET_KHR,
- VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_END_RANGE_KHR = VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_PUSH_DESCRIPTORS_KHR,
- VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_RANGE_SIZE_KHR = (VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_PUSH_DESCRIPTORS_KHR - VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET_KHR + 1),
- VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_MAX_ENUM_KHR = 0x7FFFFFFF
-} VkDescriptorUpdateTemplateTypeKHR;
-
-typedef VkFlags VkDescriptorUpdateTemplateCreateFlagsKHR;
-
-typedef struct VkDescriptorUpdateTemplateEntryKHR {
- uint32_t dstBinding;
- uint32_t dstArrayElement;
- uint32_t descriptorCount;
- VkDescriptorType descriptorType;
- size_t offset;
- size_t stride;
-} VkDescriptorUpdateTemplateEntryKHR;
-
-typedef struct VkDescriptorUpdateTemplateCreateInfoKHR {
- VkStructureType sType;
- void* pNext;
- VkDescriptorUpdateTemplateCreateFlagsKHR flags;
- uint32_t descriptorUpdateEntryCount;
- const VkDescriptorUpdateTemplateEntryKHR* pDescriptorUpdateEntries;
- VkDescriptorUpdateTemplateTypeKHR templateType;
- VkDescriptorSetLayout descriptorSetLayout;
- VkPipelineBindPoint pipelineBindPoint;
- VkPipelineLayout pipelineLayout;
- uint32_t set;
-} VkDescriptorUpdateTemplateCreateInfoKHR;
-
-
-typedef VkResult (VKAPI_PTR *PFN_vkCreateDescriptorUpdateTemplateKHR)(VkDevice device, const VkDescriptorUpdateTemplateCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDescriptorUpdateTemplateKHR* pDescriptorUpdateTemplate);
-typedef void (VKAPI_PTR *PFN_vkDestroyDescriptorUpdateTemplateKHR)(VkDevice device, VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate, const VkAllocationCallbacks* pAllocator);
-typedef void (VKAPI_PTR *PFN_vkUpdateDescriptorSetWithTemplateKHR)(VkDevice device, VkDescriptorSet descriptorSet, VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate, const void* pData);
-typedef void (VKAPI_PTR *PFN_vkCmdPushDescriptorSetWithTemplateKHR)(VkCommandBuffer commandBuffer, VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate, VkPipelineLayout layout, uint32_t set, const void* pData);
+typedef VkResult (VKAPI_PTR *PFN_vkCreateDescriptorUpdateTemplateKHR)(VkDevice device, const VkDescriptorUpdateTemplateCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDescriptorUpdateTemplate* pDescriptorUpdateTemplate);
+typedef void (VKAPI_PTR *PFN_vkDestroyDescriptorUpdateTemplateKHR)(VkDevice device, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const VkAllocationCallbacks* pAllocator);
+typedef void (VKAPI_PTR *PFN_vkUpdateDescriptorSetWithTemplateKHR)(VkDevice device, VkDescriptorSet descriptorSet, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const void* pData);
#ifndef VK_NO_PROTOTYPES
VKAPI_ATTR VkResult VKAPI_CALL vkCreateDescriptorUpdateTemplateKHR(
VkDevice device,
- const VkDescriptorUpdateTemplateCreateInfoKHR* pCreateInfo,
+ const VkDescriptorUpdateTemplateCreateInfo* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
- VkDescriptorUpdateTemplateKHR* pDescriptorUpdateTemplate);
+ VkDescriptorUpdateTemplate* pDescriptorUpdateTemplate);
VKAPI_ATTR void VKAPI_CALL vkDestroyDescriptorUpdateTemplateKHR(
VkDevice device,
- VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate,
+ VkDescriptorUpdateTemplate descriptorUpdateTemplate,
const VkAllocationCallbacks* pAllocator);
VKAPI_ATTR void VKAPI_CALL vkUpdateDescriptorSetWithTemplateKHR(
VkDevice device,
VkDescriptorSet descriptorSet,
- VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate,
- const void* pData);
-
-VKAPI_ATTR void VKAPI_CALL vkCmdPushDescriptorSetWithTemplateKHR(
- VkCommandBuffer commandBuffer,
- VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate,
- VkPipelineLayout layout,
- uint32_t set,
+ VkDescriptorUpdateTemplate descriptorUpdateTemplate,
const void* pData);
#endif
@@ -4164,6 +5568,151 @@
VkSwapchainKHR swapchain);
#endif
+#define VK_KHR_external_fence_capabilities 1
+typedef VkExternalFenceFeatureFlagBits VkExternalFenceFeatureFlagBitsKHR;
+typedef VkExternalFenceFeatureFlags VkExternalFenceFeatureFlagsKHR;
+typedef VkExternalFenceHandleTypeFlagBits VkExternalFenceHandleTypeFlagBitsKHR;
+typedef VkExternalFenceHandleTypeFlags VkExternalFenceHandleTypeFlagsKHR;
+typedef VkExternalFenceProperties VkExternalFencePropertiesKHR;
+typedef VkPhysicalDeviceExternalFenceInfo VkPhysicalDeviceExternalFenceInfoKHR;
+
+#define VK_KHR_EXTERNAL_FENCE_CAPABILITIES_SPEC_VERSION 1
+#define VK_KHR_EXTERNAL_FENCE_CAPABILITIES_EXTENSION_NAME "VK_KHR_external_fence_capabilities"
+#define VK_EXTERNAL_FENCE_FEATURE_EXPORTABLE_BIT_KHR VK_EXTERNAL_FENCE_FEATURE_EXPORTABLE_BIT
+#define VK_EXTERNAL_FENCE_FEATURE_IMPORTABLE_BIT_KHR VK_EXTERNAL_FENCE_FEATURE_IMPORTABLE_BIT
+#define VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT_KHR VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT
+#define VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_BIT
+#define VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHR VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT
+#define VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT_KHR VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT
+#define VK_STRUCTURE_TYPE_EXTERNAL_FENCE_PROPERTIES_KHR VK_STRUCTURE_TYPE_EXTERNAL_FENCE_PROPERTIES
+#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_FENCE_INFO_KHR VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_FENCE_INFO
+
+typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceExternalFencePropertiesKHR)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalFenceInfo* pExternalFenceInfo, VkExternalFenceProperties* pExternalFenceProperties);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceExternalFencePropertiesKHR(
+ VkPhysicalDevice physicalDevice,
+ const VkPhysicalDeviceExternalFenceInfo* pExternalFenceInfo,
+ VkExternalFenceProperties* pExternalFenceProperties);
+#endif
+
+#define VK_KHR_external_fence 1
+typedef VkExportFenceCreateInfo VkExportFenceCreateInfoKHR;
+typedef VkFenceImportFlagBits VkFenceImportFlagBitsKHR;
+typedef VkFenceImportFlags VkFenceImportFlagsKHR;
+
+#define VK_KHR_EXTERNAL_FENCE_SPEC_VERSION 1
+#define VK_KHR_EXTERNAL_FENCE_EXTENSION_NAME "VK_KHR_external_fence"
+#define VK_FENCE_IMPORT_TEMPORARY_BIT_KHR VK_FENCE_IMPORT_TEMPORARY_BIT
+#define VK_STRUCTURE_TYPE_EXPORT_FENCE_CREATE_INFO_KHR VK_STRUCTURE_TYPE_EXPORT_FENCE_CREATE_INFO
+
+
+#ifdef VK_USE_PLATFORM_WIN32_KHR
+#define VK_KHR_external_fence_win32 1
+#define VK_KHR_EXTERNAL_FENCE_WIN32_SPEC_VERSION 1
+#define VK_KHR_EXTERNAL_FENCE_WIN32_EXTENSION_NAME "VK_KHR_external_fence_win32"
+
+typedef struct VkImportFenceWin32HandleInfoKHR {
+ VkStructureType sType;
+ const void* pNext;
+ VkFence fence;
+ VkFenceImportFlags flags;
+ VkExternalFenceHandleTypeFlagBits handleType;
+ HANDLE handle;
+ LPCWSTR name;
+} VkImportFenceWin32HandleInfoKHR;
+
+typedef struct VkExportFenceWin32HandleInfoKHR {
+ VkStructureType sType;
+ const void* pNext;
+ const SECURITY_ATTRIBUTES* pAttributes;
+ DWORD dwAccess;
+ LPCWSTR name;
+} VkExportFenceWin32HandleInfoKHR;
+
+typedef struct VkFenceGetWin32HandleInfoKHR {
+ VkStructureType sType;
+ const void* pNext;
+ VkFence fence;
+ VkExternalFenceHandleTypeFlagBits handleType;
+} VkFenceGetWin32HandleInfoKHR;
+
+
+typedef VkResult (VKAPI_PTR *PFN_vkImportFenceWin32HandleKHR)(VkDevice device, const VkImportFenceWin32HandleInfoKHR* pImportFenceWin32HandleInfo);
+typedef VkResult (VKAPI_PTR *PFN_vkGetFenceWin32HandleKHR)(VkDevice device, const VkFenceGetWin32HandleInfoKHR* pGetWin32HandleInfo, HANDLE* pHandle);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR VkResult VKAPI_CALL vkImportFenceWin32HandleKHR(
+ VkDevice device,
+ const VkImportFenceWin32HandleInfoKHR* pImportFenceWin32HandleInfo);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkGetFenceWin32HandleKHR(
+ VkDevice device,
+ const VkFenceGetWin32HandleInfoKHR* pGetWin32HandleInfo,
+ HANDLE* pHandle);
+#endif
+#endif /* VK_USE_PLATFORM_WIN32_KHR */
+
+#define VK_KHR_external_fence_fd 1
+#define VK_KHR_EXTERNAL_FENCE_FD_SPEC_VERSION 1
+#define VK_KHR_EXTERNAL_FENCE_FD_EXTENSION_NAME "VK_KHR_external_fence_fd"
+
+typedef struct VkImportFenceFdInfoKHR {
+ VkStructureType sType;
+ const void* pNext;
+ VkFence fence;
+ VkFenceImportFlags flags;
+ VkExternalFenceHandleTypeFlagBits handleType;
+ int fd;
+} VkImportFenceFdInfoKHR;
+
+typedef struct VkFenceGetFdInfoKHR {
+ VkStructureType sType;
+ const void* pNext;
+ VkFence fence;
+ VkExternalFenceHandleTypeFlagBits handleType;
+} VkFenceGetFdInfoKHR;
+
+
+typedef VkResult (VKAPI_PTR *PFN_vkImportFenceFdKHR)(VkDevice device, const VkImportFenceFdInfoKHR* pImportFenceFdInfo);
+typedef VkResult (VKAPI_PTR *PFN_vkGetFenceFdKHR)(VkDevice device, const VkFenceGetFdInfoKHR* pGetFdInfo, int* pFd);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR VkResult VKAPI_CALL vkImportFenceFdKHR(
+ VkDevice device,
+ const VkImportFenceFdInfoKHR* pImportFenceFdInfo);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkGetFenceFdKHR(
+ VkDevice device,
+ const VkFenceGetFdInfoKHR* pGetFdInfo,
+ int* pFd);
+#endif
+
+#define VK_KHR_maintenance2 1
+typedef VkImageViewUsageCreateInfo VkImageViewUsageCreateInfoKHR;
+typedef VkInputAttachmentAspectReference VkInputAttachmentAspectReferenceKHR;
+typedef VkPhysicalDevicePointClippingProperties VkPhysicalDevicePointClippingPropertiesKHR;
+typedef VkPipelineTessellationDomainOriginStateCreateInfo VkPipelineTessellationDomainOriginStateCreateInfoKHR;
+typedef VkPointClippingBehavior VkPointClippingBehaviorKHR;
+typedef VkRenderPassInputAttachmentAspectCreateInfo VkRenderPassInputAttachmentAspectCreateInfoKHR;
+typedef VkTessellationDomainOrigin VkTessellationDomainOriginKHR;
+
+#define VK_KHR_MAINTENANCE2_SPEC_VERSION 1
+#define VK_KHR_MAINTENANCE2_EXTENSION_NAME "VK_KHR_maintenance2"
+#define VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT_KHR VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT
+#define VK_IMAGE_CREATE_EXTENDED_USAGE_BIT_KHR VK_IMAGE_CREATE_EXTENDED_USAGE_BIT
+#define VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL_KHR VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL
+#define VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL_KHR VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL
+#define VK_POINT_CLIPPING_BEHAVIOR_ALL_CLIP_PLANES_KHR VK_POINT_CLIPPING_BEHAVIOR_ALL_CLIP_PLANES
+#define VK_POINT_CLIPPING_BEHAVIOR_USER_CLIP_PLANES_ONLY_KHR VK_POINT_CLIPPING_BEHAVIOR_USER_CLIP_PLANES_ONLY
+#define VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO_KHR VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO
+#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_POINT_CLIPPING_PROPERTIES_KHR VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_POINT_CLIPPING_PROPERTIES
+#define VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_DOMAIN_ORIGIN_STATE_CREATE_INFO_KHR VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_DOMAIN_ORIGIN_STATE_CREATE_INFO
+#define VK_STRUCTURE_TYPE_RENDER_PASS_INPUT_ATTACHMENT_ASPECT_CREATE_INFO_KHR VK_STRUCTURE_TYPE_RENDER_PASS_INPUT_ATTACHMENT_ASPECT_CREATE_INFO
+#define VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT_KHR VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT
+#define VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT_KHR VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT
+
+
#define VK_KHR_get_surface_capabilities2 1
#define VK_KHR_GET_SURFACE_CAPABILITIES_2_SPEC_VERSION 1
#define VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME "VK_KHR_get_surface_capabilities2"
@@ -4203,12 +5752,227 @@
VkSurfaceFormat2KHR* pSurfaceFormats);
#endif
+#define VK_KHR_variable_pointers 1
+typedef VkPhysicalDeviceVariablePointerFeatures VkPhysicalDeviceVariablePointerFeaturesKHR;
+
+#define VK_KHR_VARIABLE_POINTERS_SPEC_VERSION 1
+#define VK_KHR_VARIABLE_POINTERS_EXTENSION_NAME "VK_KHR_variable_pointers"
+#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTER_FEATURES_KHR VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTER_FEATURES
+
+
+#define VK_KHR_dedicated_allocation 1
+typedef VkMemoryDedicatedAllocateInfo VkMemoryDedicatedAllocateInfoKHR;
+typedef VkMemoryDedicatedRequirements VkMemoryDedicatedRequirementsKHR;
+
+#define VK_KHR_DEDICATED_ALLOCATION_SPEC_VERSION 3
+#define VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME "VK_KHR_dedicated_allocation"
+#define VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO
+#define VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS_KHR VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS
+
+
+#define VK_KHR_storage_buffer_storage_class 1
+#define VK_KHR_STORAGE_BUFFER_STORAGE_CLASS_SPEC_VERSION 1
+#define VK_KHR_STORAGE_BUFFER_STORAGE_CLASS_EXTENSION_NAME "VK_KHR_storage_buffer_storage_class"
+
+
+#define VK_KHR_relaxed_block_layout 1
+#define VK_KHR_RELAXED_BLOCK_LAYOUT_SPEC_VERSION 1
+#define VK_KHR_RELAXED_BLOCK_LAYOUT_EXTENSION_NAME "VK_KHR_relaxed_block_layout"
+
+
+#define VK_KHR_get_memory_requirements2 1
+typedef VkBufferMemoryRequirementsInfo2 VkBufferMemoryRequirementsInfo2KHR;
+typedef VkImageMemoryRequirementsInfo2 VkImageMemoryRequirementsInfo2KHR;
+typedef VkImageSparseMemoryRequirementsInfo2 VkImageSparseMemoryRequirementsInfo2KHR;
+typedef VkMemoryRequirements2 VkMemoryRequirements2KHR;
+typedef VkSparseImageMemoryRequirements2 VkSparseImageMemoryRequirements2KHR;
+
+#define VK_KHR_GET_MEMORY_REQUIREMENTS_2_SPEC_VERSION 1
+#define VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME "VK_KHR_get_memory_requirements2"
+#define VK_STRUCTURE_TYPE_BUFFER_MEMORY_REQUIREMENTS_INFO_2_KHR VK_STRUCTURE_TYPE_BUFFER_MEMORY_REQUIREMENTS_INFO_2
+#define VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2_KHR VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2
+#define VK_STRUCTURE_TYPE_IMAGE_SPARSE_MEMORY_REQUIREMENTS_INFO_2_KHR VK_STRUCTURE_TYPE_IMAGE_SPARSE_MEMORY_REQUIREMENTS_INFO_2
+#define VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2_KHR VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2
+#define VK_STRUCTURE_TYPE_SPARSE_IMAGE_MEMORY_REQUIREMENTS_2_KHR VK_STRUCTURE_TYPE_SPARSE_IMAGE_MEMORY_REQUIREMENTS_2
+
+typedef void (VKAPI_PTR *PFN_vkGetBufferMemoryRequirements2KHR)(VkDevice device, const VkBufferMemoryRequirementsInfo2* pInfo, VkMemoryRequirements2* pMemoryRequirements);
+typedef void (VKAPI_PTR *PFN_vkGetImageMemoryRequirements2KHR)(VkDevice device, const VkImageMemoryRequirementsInfo2* pInfo, VkMemoryRequirements2* pMemoryRequirements);
+typedef void (VKAPI_PTR *PFN_vkGetImageSparseMemoryRequirements2KHR)(VkDevice device, const VkImageSparseMemoryRequirementsInfo2* pInfo, uint32_t* pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements2* pSparseMemoryRequirements);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR void VKAPI_CALL vkGetBufferMemoryRequirements2KHR(
+ VkDevice device,
+ const VkBufferMemoryRequirementsInfo2* pInfo,
+ VkMemoryRequirements2* pMemoryRequirements);
+
+VKAPI_ATTR void VKAPI_CALL vkGetImageMemoryRequirements2KHR(
+ VkDevice device,
+ const VkImageMemoryRequirementsInfo2* pInfo,
+ VkMemoryRequirements2* pMemoryRequirements);
+
+VKAPI_ATTR void VKAPI_CALL vkGetImageSparseMemoryRequirements2KHR(
+ VkDevice device,
+ const VkImageSparseMemoryRequirementsInfo2* pInfo,
+ uint32_t* pSparseMemoryRequirementCount,
+ VkSparseImageMemoryRequirements2* pSparseMemoryRequirements);
+#endif
+
+#define VK_KHR_image_format_list 1
+#define VK_KHR_IMAGE_FORMAT_LIST_SPEC_VERSION 1
+#define VK_KHR_IMAGE_FORMAT_LIST_EXTENSION_NAME "VK_KHR_image_format_list"
+
+typedef struct VkImageFormatListCreateInfoKHR {
+ VkStructureType sType;
+ const void* pNext;
+ uint32_t viewFormatCount;
+ const VkFormat* pViewFormats;
+} VkImageFormatListCreateInfoKHR;
+
+
+
+#define VK_KHR_sampler_ycbcr_conversion 1
+typedef VkBindImagePlaneMemoryInfo VkBindImagePlaneMemoryInfoKHR;
+typedef VkChromaLocation VkChromaLocationKHR;
+typedef VkImagePlaneMemoryRequirementsInfo VkImagePlaneMemoryRequirementsInfoKHR;
+typedef VkPhysicalDeviceSamplerYcbcrConversionFeatures VkPhysicalDeviceSamplerYcbcrConversionFeaturesKHR;
+typedef VkSamplerYcbcrConversionCreateInfo VkSamplerYcbcrConversionCreateInfoKHR;
+typedef VkSamplerYcbcrConversionImageFormatProperties VkSamplerYcbcrConversionImageFormatPropertiesKHR;
+typedef VkSamplerYcbcrConversionInfo VkSamplerYcbcrConversionInfoKHR;
+typedef VkSamplerYcbcrConversion VkSamplerYcbcrConversionKHR;
+typedef VkSamplerYcbcrModelConversion VkSamplerYcbcrModelConversionKHR;
+typedef VkSamplerYcbcrRange VkSamplerYcbcrRangeKHR;
+
+#define VK_KHR_SAMPLER_YCBCR_CONVERSION_SPEC_VERSION 1
+#define VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME "VK_KHR_sampler_ycbcr_conversion"
+#define VK_CHROMA_LOCATION_COSITED_EVEN_KHR VK_CHROMA_LOCATION_COSITED_EVEN
+#define VK_CHROMA_LOCATION_MIDPOINT_KHR VK_CHROMA_LOCATION_MIDPOINT
+#define VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION_KHR_EXT VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION_EXT
+#define VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16_KHR VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16
+#define VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16_KHR VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16
+#define VK_FORMAT_B16G16R16G16_422_UNORM_KHR VK_FORMAT_B16G16R16G16_422_UNORM
+#define VK_FORMAT_B8G8R8G8_422_UNORM_KHR VK_FORMAT_B8G8R8G8_422_UNORM
+#define VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT_KHR VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT
+#define VK_FORMAT_FEATURE_DISJOINT_BIT_KHR VK_FORMAT_FEATURE_DISJOINT_BIT
+#define VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT_KHR VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT
+#define VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_BIT_KHR VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_BIT
+#define VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE_BIT_KHR VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE_BIT
+#define VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT_KHR VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT
+#define VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER_BIT_KHR VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER_BIT
+#define VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16_KHR VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16
+#define VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16_KHR VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16
+#define VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16_KHR VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16
+#define VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16_KHR VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16
+#define VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16_KHR VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16
+#define VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16_KHR VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16
+#define VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16_KHR VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16
+#define VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16_KHR VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16
+#define VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16_KHR VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16
+#define VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16_KHR VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16
+#define VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16_KHR VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16
+#define VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16_KHR VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16
+#define VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM_KHR VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM
+#define VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM_KHR VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM
+#define VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM_KHR VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM
+#define VK_FORMAT_G16_B16R16_2PLANE_420_UNORM_KHR VK_FORMAT_G16_B16R16_2PLANE_420_UNORM
+#define VK_FORMAT_G16_B16R16_2PLANE_422_UNORM_KHR VK_FORMAT_G16_B16R16_2PLANE_422_UNORM
+#define VK_FORMAT_G16B16G16R16_422_UNORM_KHR VK_FORMAT_G16B16G16R16_422_UNORM
+#define VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM_KHR VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM
+#define VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM_KHR VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM
+#define VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM_KHR VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM
+#define VK_FORMAT_G8_B8R8_2PLANE_420_UNORM_KHR VK_FORMAT_G8_B8R8_2PLANE_420_UNORM
+#define VK_FORMAT_G8_B8R8_2PLANE_422_UNORM_KHR VK_FORMAT_G8_B8R8_2PLANE_422_UNORM
+#define VK_FORMAT_G8B8G8R8_422_UNORM_KHR VK_FORMAT_G8B8G8R8_422_UNORM
+#define VK_FORMAT_R10X6_UNORM_PACK16_KHR VK_FORMAT_R10X6_UNORM_PACK16
+#define VK_FORMAT_R10X6G10X6_UNORM_2PACK16_KHR VK_FORMAT_R10X6G10X6_UNORM_2PACK16
+#define VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16_KHR VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16
+#define VK_FORMAT_R12X4_UNORM_PACK16_KHR VK_FORMAT_R12X4_UNORM_PACK16
+#define VK_FORMAT_R12X4G12X4_UNORM_2PACK16_KHR VK_FORMAT_R12X4G12X4_UNORM_2PACK16
+#define VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16_KHR VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16
+#define VK_IMAGE_ASPECT_PLANE_0_BIT_KHR VK_IMAGE_ASPECT_PLANE_0_BIT
+#define VK_IMAGE_ASPECT_PLANE_1_BIT_KHR VK_IMAGE_ASPECT_PLANE_1_BIT
+#define VK_IMAGE_ASPECT_PLANE_2_BIT_KHR VK_IMAGE_ASPECT_PLANE_2_BIT
+#define VK_IMAGE_CREATE_DISJOINT_BIT_KHR VK_IMAGE_CREATE_DISJOINT_BIT
+#define VK_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION_KHR VK_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION
+#define VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY_KHR VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY
+#define VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020_KHR VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020
+#define VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601_KHR VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601
+#define VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_709_KHR VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_709
+#define VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_IDENTITY_KHR VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_IDENTITY
+#define VK_SAMPLER_YCBCR_RANGE_ITU_FULL_KHR VK_SAMPLER_YCBCR_RANGE_ITU_FULL
+#define VK_SAMPLER_YCBCR_RANGE_ITU_NARROW_KHR VK_SAMPLER_YCBCR_RANGE_ITU_NARROW
+#define VK_STRUCTURE_TYPE_BIND_IMAGE_PLANE_MEMORY_INFO_KHR VK_STRUCTURE_TYPE_BIND_IMAGE_PLANE_MEMORY_INFO
+#define VK_STRUCTURE_TYPE_IMAGE_PLANE_MEMORY_REQUIREMENTS_INFO_KHR VK_STRUCTURE_TYPE_IMAGE_PLANE_MEMORY_REQUIREMENTS_INFO
+#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES_KHR VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES
+#define VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO_KHR VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO
+#define VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_IMAGE_FORMAT_PROPERTIES_KHR VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_IMAGE_FORMAT_PROPERTIES
+#define VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO_KHR VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO
+
+typedef VkResult (VKAPI_PTR *PFN_vkCreateSamplerYcbcrConversionKHR)(VkDevice device, const VkSamplerYcbcrConversionCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSamplerYcbcrConversion* pYcbcrConversion);
+typedef void (VKAPI_PTR *PFN_vkDestroySamplerYcbcrConversionKHR)(VkDevice device, VkSamplerYcbcrConversion ycbcrConversion, const VkAllocationCallbacks* pAllocator);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR VkResult VKAPI_CALL vkCreateSamplerYcbcrConversionKHR(
+ VkDevice device,
+ const VkSamplerYcbcrConversionCreateInfo* pCreateInfo,
+ const VkAllocationCallbacks* pAllocator,
+ VkSamplerYcbcrConversion* pYcbcrConversion);
+
+VKAPI_ATTR void VKAPI_CALL vkDestroySamplerYcbcrConversionKHR(
+ VkDevice device,
+ VkSamplerYcbcrConversion ycbcrConversion,
+ const VkAllocationCallbacks* pAllocator);
+#endif
+
+#define VK_KHR_bind_memory2 1
+typedef VkBindBufferMemoryInfo VkBindBufferMemoryInfoKHR;
+typedef VkBindImageMemoryInfo VkBindImageMemoryInfoKHR;
+
+#define VK_KHR_BIND_MEMORY_2_SPEC_VERSION 1
+#define VK_KHR_BIND_MEMORY_2_EXTENSION_NAME "VK_KHR_bind_memory2"
+#define VK_IMAGE_CREATE_ALIAS_BIT_KHR VK_IMAGE_CREATE_ALIAS_BIT
+#define VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_INFO_KHR VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_INFO
+#define VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO_KHR VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO
+
+typedef VkResult (VKAPI_PTR *PFN_vkBindBufferMemory2KHR)(VkDevice device, uint32_t bindInfoCount, const VkBindBufferMemoryInfo* pBindInfos);
+typedef VkResult (VKAPI_PTR *PFN_vkBindImageMemory2KHR)(VkDevice device, uint32_t bindInfoCount, const VkBindImageMemoryInfo* pBindInfos);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR VkResult VKAPI_CALL vkBindBufferMemory2KHR(
+ VkDevice device,
+ uint32_t bindInfoCount,
+ const VkBindBufferMemoryInfo* pBindInfos);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkBindImageMemory2KHR(
+ VkDevice device,
+ uint32_t bindInfoCount,
+ const VkBindImageMemoryInfo* pBindInfos);
+#endif
+
+#define VK_KHR_maintenance3 1
+typedef VkDescriptorSetLayoutSupport VkDescriptorSetLayoutSupportKHR;
+typedef VkPhysicalDeviceMaintenance3Properties VkPhysicalDeviceMaintenance3PropertiesKHR;
+
+#define VK_KHR_MAINTENANCE3_SPEC_VERSION 1
+#define VK_KHR_MAINTENANCE3_EXTENSION_NAME "VK_KHR_maintenance3"
+#define VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_SUPPORT_KHR VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_SUPPORT
+#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES_KHR VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES
+
+typedef void (VKAPI_PTR *PFN_vkGetDescriptorSetLayoutSupportKHR)(VkDevice device, const VkDescriptorSetLayoutCreateInfo* pCreateInfo, VkDescriptorSetLayoutSupport* pSupport);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR void VKAPI_CALL vkGetDescriptorSetLayoutSupportKHR(
+ VkDevice device,
+ const VkDescriptorSetLayoutCreateInfo* pCreateInfo,
+ VkDescriptorSetLayoutSupport* pSupport);
+#endif
+
#define VK_EXT_debug_report 1
VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDebugReportCallbackEXT)
-#define VK_EXT_DEBUG_REPORT_SPEC_VERSION 6
+#define VK_EXT_DEBUG_REPORT_SPEC_VERSION 9
#define VK_EXT_DEBUG_REPORT_EXTENSION_NAME "VK_EXT_debug_report"
#define VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT
+#define VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_CALLBACK_EXT_EXT
typedef enum VkDebugReportObjectTypeEXT {
@@ -4240,27 +6004,20 @@
VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_POOL_EXT = 25,
VK_DEBUG_REPORT_OBJECT_TYPE_SURFACE_KHR_EXT = 26,
VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT = 27,
- VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT = 28,
+ VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_CALLBACK_EXT_EXT = 28,
VK_DEBUG_REPORT_OBJECT_TYPE_DISPLAY_KHR_EXT = 29,
VK_DEBUG_REPORT_OBJECT_TYPE_DISPLAY_MODE_KHR_EXT = 30,
VK_DEBUG_REPORT_OBJECT_TYPE_OBJECT_TABLE_NVX_EXT = 31,
VK_DEBUG_REPORT_OBJECT_TYPE_INDIRECT_COMMANDS_LAYOUT_NVX_EXT = 32,
- VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_KHR_EXT = 1000085000,
+ VK_DEBUG_REPORT_OBJECT_TYPE_VALIDATION_CACHE_EXT = 33,
+ VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION_EXT = 1000156000,
+ VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_EXT = 1000085000,
VK_DEBUG_REPORT_OBJECT_TYPE_BEGIN_RANGE_EXT = VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT,
- VK_DEBUG_REPORT_OBJECT_TYPE_END_RANGE_EXT = VK_DEBUG_REPORT_OBJECT_TYPE_INDIRECT_COMMANDS_LAYOUT_NVX_EXT,
- VK_DEBUG_REPORT_OBJECT_TYPE_RANGE_SIZE_EXT = (VK_DEBUG_REPORT_OBJECT_TYPE_INDIRECT_COMMANDS_LAYOUT_NVX_EXT - VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT + 1),
+ VK_DEBUG_REPORT_OBJECT_TYPE_END_RANGE_EXT = VK_DEBUG_REPORT_OBJECT_TYPE_VALIDATION_CACHE_EXT,
+ VK_DEBUG_REPORT_OBJECT_TYPE_RANGE_SIZE_EXT = (VK_DEBUG_REPORT_OBJECT_TYPE_VALIDATION_CACHE_EXT - VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT + 1),
VK_DEBUG_REPORT_OBJECT_TYPE_MAX_ENUM_EXT = 0x7FFFFFFF
} VkDebugReportObjectTypeEXT;
-typedef enum VkDebugReportErrorEXT {
- VK_DEBUG_REPORT_ERROR_NONE_EXT = 0,
- VK_DEBUG_REPORT_ERROR_CALLBACK_REF_EXT = 1,
- VK_DEBUG_REPORT_ERROR_BEGIN_RANGE_EXT = VK_DEBUG_REPORT_ERROR_NONE_EXT,
- VK_DEBUG_REPORT_ERROR_END_RANGE_EXT = VK_DEBUG_REPORT_ERROR_CALLBACK_REF_EXT,
- VK_DEBUG_REPORT_ERROR_RANGE_SIZE_EXT = (VK_DEBUG_REPORT_ERROR_CALLBACK_REF_EXT - VK_DEBUG_REPORT_ERROR_NONE_EXT + 1),
- VK_DEBUG_REPORT_ERROR_MAX_ENUM_EXT = 0x7FFFFFFF
-} VkDebugReportErrorEXT;
-
typedef enum VkDebugReportFlagBitsEXT {
VK_DEBUG_REPORT_INFORMATION_BIT_EXT = 0x00000001,
@@ -4324,6 +6081,11 @@
#define VK_NV_GLSL_SHADER_EXTENSION_NAME "VK_NV_glsl_shader"
+#define VK_EXT_depth_range_unrestricted 1
+#define VK_EXT_DEPTH_RANGE_UNRESTRICTED_SPEC_VERSION 1
+#define VK_EXT_DEPTH_RANGE_UNRESTRICTED_EXTENSION_NAME "VK_EXT_depth_range_unrestricted"
+
+
#define VK_IMG_filter_cubic 1
#define VK_IMG_FILTER_CUBIC_SPEC_VERSION 1
#define VK_IMG_FILTER_CUBIC_EXTENSION_NAME "VK_IMG_filter_cubic"
@@ -4391,31 +6153,31 @@
} VkDebugMarkerMarkerInfoEXT;
-typedef VkResult (VKAPI_PTR *PFN_vkDebugMarkerSetObjectTagEXT)(VkDevice device, VkDebugMarkerObjectTagInfoEXT* pTagInfo);
-typedef VkResult (VKAPI_PTR *PFN_vkDebugMarkerSetObjectNameEXT)(VkDevice device, VkDebugMarkerObjectNameInfoEXT* pNameInfo);
-typedef void (VKAPI_PTR *PFN_vkCmdDebugMarkerBeginEXT)(VkCommandBuffer commandBuffer, VkDebugMarkerMarkerInfoEXT* pMarkerInfo);
+typedef VkResult (VKAPI_PTR *PFN_vkDebugMarkerSetObjectTagEXT)(VkDevice device, const VkDebugMarkerObjectTagInfoEXT* pTagInfo);
+typedef VkResult (VKAPI_PTR *PFN_vkDebugMarkerSetObjectNameEXT)(VkDevice device, const VkDebugMarkerObjectNameInfoEXT* pNameInfo);
+typedef void (VKAPI_PTR *PFN_vkCmdDebugMarkerBeginEXT)(VkCommandBuffer commandBuffer, const VkDebugMarkerMarkerInfoEXT* pMarkerInfo);
typedef void (VKAPI_PTR *PFN_vkCmdDebugMarkerEndEXT)(VkCommandBuffer commandBuffer);
-typedef void (VKAPI_PTR *PFN_vkCmdDebugMarkerInsertEXT)(VkCommandBuffer commandBuffer, VkDebugMarkerMarkerInfoEXT* pMarkerInfo);
+typedef void (VKAPI_PTR *PFN_vkCmdDebugMarkerInsertEXT)(VkCommandBuffer commandBuffer, const VkDebugMarkerMarkerInfoEXT* pMarkerInfo);
#ifndef VK_NO_PROTOTYPES
VKAPI_ATTR VkResult VKAPI_CALL vkDebugMarkerSetObjectTagEXT(
VkDevice device,
- VkDebugMarkerObjectTagInfoEXT* pTagInfo);
+ const VkDebugMarkerObjectTagInfoEXT* pTagInfo);
VKAPI_ATTR VkResult VKAPI_CALL vkDebugMarkerSetObjectNameEXT(
VkDevice device,
- VkDebugMarkerObjectNameInfoEXT* pNameInfo);
+ const VkDebugMarkerObjectNameInfoEXT* pNameInfo);
VKAPI_ATTR void VKAPI_CALL vkCmdDebugMarkerBeginEXT(
VkCommandBuffer commandBuffer,
- VkDebugMarkerMarkerInfoEXT* pMarkerInfo);
+ const VkDebugMarkerMarkerInfoEXT* pMarkerInfo);
VKAPI_ATTR void VKAPI_CALL vkCmdDebugMarkerEndEXT(
VkCommandBuffer commandBuffer);
VKAPI_ATTR void VKAPI_CALL vkCmdDebugMarkerInsertEXT(
VkCommandBuffer commandBuffer,
- VkDebugMarkerMarkerInfoEXT* pMarkerInfo);
+ const VkDebugMarkerMarkerInfoEXT* pMarkerInfo);
#endif
#define VK_AMD_gcn_shader 1
@@ -4490,35 +6252,15 @@
#define VK_AMD_SHADER_BALLOT_EXTENSION_NAME "VK_AMD_shader_ballot"
-#define VK_KHX_multiview 1
-#define VK_KHX_MULTIVIEW_SPEC_VERSION 1
-#define VK_KHX_MULTIVIEW_EXTENSION_NAME "VK_KHX_multiview"
+#define VK_AMD_texture_gather_bias_lod 1
+#define VK_AMD_TEXTURE_GATHER_BIAS_LOD_SPEC_VERSION 1
+#define VK_AMD_TEXTURE_GATHER_BIAS_LOD_EXTENSION_NAME "VK_AMD_texture_gather_bias_lod"
-typedef struct VkRenderPassMultiviewCreateInfoKHX {
- VkStructureType sType;
- const void* pNext;
- uint32_t subpassCount;
- const uint32_t* pViewMasks;
- uint32_t dependencyCount;
- const int32_t* pViewOffsets;
- uint32_t correlationMaskCount;
- const uint32_t* pCorrelationMasks;
-} VkRenderPassMultiviewCreateInfoKHX;
-
-typedef struct VkPhysicalDeviceMultiviewFeaturesKHX {
+typedef struct VkTextureLODGatherFormatPropertiesAMD {
VkStructureType sType;
void* pNext;
- VkBool32 multiview;
- VkBool32 multiviewGeometryShader;
- VkBool32 multiviewTessellationShader;
-} VkPhysicalDeviceMultiviewFeaturesKHX;
-
-typedef struct VkPhysicalDeviceMultiviewPropertiesKHX {
- VkStructureType sType;
- void* pNext;
- uint32_t maxMultiviewViewCount;
- uint32_t maxMultiviewInstanceIndex;
-} VkPhysicalDeviceMultiviewPropertiesKHX;
+ VkBool32 supportsTextureGatherLODBiasAMD;
+} VkTextureLODGatherFormatPropertiesAMD;
@@ -4640,204 +6382,6 @@
#endif /* VK_USE_PLATFORM_WIN32_KHR */
-#define VK_KHX_device_group 1
-#define VK_MAX_DEVICE_GROUP_SIZE_KHX 32
-#define VK_KHX_DEVICE_GROUP_SPEC_VERSION 1
-#define VK_KHX_DEVICE_GROUP_EXTENSION_NAME "VK_KHX_device_group"
-
-
-typedef enum VkPeerMemoryFeatureFlagBitsKHX {
- VK_PEER_MEMORY_FEATURE_COPY_SRC_BIT_KHX = 0x00000001,
- VK_PEER_MEMORY_FEATURE_COPY_DST_BIT_KHX = 0x00000002,
- VK_PEER_MEMORY_FEATURE_GENERIC_SRC_BIT_KHX = 0x00000004,
- VK_PEER_MEMORY_FEATURE_GENERIC_DST_BIT_KHX = 0x00000008,
- VK_PEER_MEMORY_FEATURE_FLAG_BITS_MAX_ENUM_KHX = 0x7FFFFFFF
-} VkPeerMemoryFeatureFlagBitsKHX;
-typedef VkFlags VkPeerMemoryFeatureFlagsKHX;
-
-typedef enum VkMemoryAllocateFlagBitsKHX {
- VK_MEMORY_ALLOCATE_DEVICE_MASK_BIT_KHX = 0x00000001,
- VK_MEMORY_ALLOCATE_FLAG_BITS_MAX_ENUM_KHX = 0x7FFFFFFF
-} VkMemoryAllocateFlagBitsKHX;
-typedef VkFlags VkMemoryAllocateFlagsKHX;
-
-typedef enum VkDeviceGroupPresentModeFlagBitsKHX {
- VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_BIT_KHX = 0x00000001,
- VK_DEVICE_GROUP_PRESENT_MODE_REMOTE_BIT_KHX = 0x00000002,
- VK_DEVICE_GROUP_PRESENT_MODE_SUM_BIT_KHX = 0x00000004,
- VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_MULTI_DEVICE_BIT_KHX = 0x00000008,
- VK_DEVICE_GROUP_PRESENT_MODE_FLAG_BITS_MAX_ENUM_KHX = 0x7FFFFFFF
-} VkDeviceGroupPresentModeFlagBitsKHX;
-typedef VkFlags VkDeviceGroupPresentModeFlagsKHX;
-
-typedef struct VkMemoryAllocateFlagsInfoKHX {
- VkStructureType sType;
- const void* pNext;
- VkMemoryAllocateFlagsKHX flags;
- uint32_t deviceMask;
-} VkMemoryAllocateFlagsInfoKHX;
-
-typedef struct VkBindBufferMemoryInfoKHX {
- VkStructureType sType;
- const void* pNext;
- VkBuffer buffer;
- VkDeviceMemory memory;
- VkDeviceSize memoryOffset;
- uint32_t deviceIndexCount;
- const uint32_t* pDeviceIndices;
-} VkBindBufferMemoryInfoKHX;
-
-typedef struct VkBindImageMemoryInfoKHX {
- VkStructureType sType;
- const void* pNext;
- VkImage image;
- VkDeviceMemory memory;
- VkDeviceSize memoryOffset;
- uint32_t deviceIndexCount;
- const uint32_t* pDeviceIndices;
- uint32_t SFRRectCount;
- const VkRect2D* pSFRRects;
-} VkBindImageMemoryInfoKHX;
-
-typedef struct VkDeviceGroupRenderPassBeginInfoKHX {
- VkStructureType sType;
- const void* pNext;
- uint32_t deviceMask;
- uint32_t deviceRenderAreaCount;
- const VkRect2D* pDeviceRenderAreas;
-} VkDeviceGroupRenderPassBeginInfoKHX;
-
-typedef struct VkDeviceGroupCommandBufferBeginInfoKHX {
- VkStructureType sType;
- const void* pNext;
- uint32_t deviceMask;
-} VkDeviceGroupCommandBufferBeginInfoKHX;
-
-typedef struct VkDeviceGroupSubmitInfoKHX {
- VkStructureType sType;
- const void* pNext;
- uint32_t waitSemaphoreCount;
- const uint32_t* pWaitSemaphoreDeviceIndices;
- uint32_t commandBufferCount;
- const uint32_t* pCommandBufferDeviceMasks;
- uint32_t signalSemaphoreCount;
- const uint32_t* pSignalSemaphoreDeviceIndices;
-} VkDeviceGroupSubmitInfoKHX;
-
-typedef struct VkDeviceGroupBindSparseInfoKHX {
- VkStructureType sType;
- const void* pNext;
- uint32_t resourceDeviceIndex;
- uint32_t memoryDeviceIndex;
-} VkDeviceGroupBindSparseInfoKHX;
-
-typedef struct VkDeviceGroupPresentCapabilitiesKHX {
- VkStructureType sType;
- const void* pNext;
- uint32_t presentMask[VK_MAX_DEVICE_GROUP_SIZE_KHX];
- VkDeviceGroupPresentModeFlagsKHX modes;
-} VkDeviceGroupPresentCapabilitiesKHX;
-
-typedef struct VkImageSwapchainCreateInfoKHX {
- VkStructureType sType;
- const void* pNext;
- VkSwapchainKHR swapchain;
-} VkImageSwapchainCreateInfoKHX;
-
-typedef struct VkBindImageMemorySwapchainInfoKHX {
- VkStructureType sType;
- const void* pNext;
- VkSwapchainKHR swapchain;
- uint32_t imageIndex;
-} VkBindImageMemorySwapchainInfoKHX;
-
-typedef struct VkAcquireNextImageInfoKHX {
- VkStructureType sType;
- const void* pNext;
- VkSwapchainKHR swapchain;
- uint64_t timeout;
- VkSemaphore semaphore;
- VkFence fence;
- uint32_t deviceMask;
-} VkAcquireNextImageInfoKHX;
-
-typedef struct VkDeviceGroupPresentInfoKHX {
- VkStructureType sType;
- const void* pNext;
- uint32_t swapchainCount;
- const uint32_t* pDeviceMasks;
- VkDeviceGroupPresentModeFlagBitsKHX mode;
-} VkDeviceGroupPresentInfoKHX;
-
-typedef struct VkDeviceGroupSwapchainCreateInfoKHX {
- VkStructureType sType;
- const void* pNext;
- VkDeviceGroupPresentModeFlagsKHX modes;
-} VkDeviceGroupSwapchainCreateInfoKHX;
-
-
-typedef void (VKAPI_PTR *PFN_vkGetDeviceGroupPeerMemoryFeaturesKHX)(VkDevice device, uint32_t heapIndex, uint32_t localDeviceIndex, uint32_t remoteDeviceIndex, VkPeerMemoryFeatureFlagsKHX* pPeerMemoryFeatures);
-typedef VkResult (VKAPI_PTR *PFN_vkBindBufferMemory2KHX)(VkDevice device, uint32_t bindInfoCount, const VkBindBufferMemoryInfoKHX* pBindInfos);
-typedef VkResult (VKAPI_PTR *PFN_vkBindImageMemory2KHX)(VkDevice device, uint32_t bindInfoCount, const VkBindImageMemoryInfoKHX* pBindInfos);
-typedef void (VKAPI_PTR *PFN_vkCmdSetDeviceMaskKHX)(VkCommandBuffer commandBuffer, uint32_t deviceMask);
-typedef VkResult (VKAPI_PTR *PFN_vkGetDeviceGroupPresentCapabilitiesKHX)(VkDevice device, VkDeviceGroupPresentCapabilitiesKHX* pDeviceGroupPresentCapabilities);
-typedef VkResult (VKAPI_PTR *PFN_vkGetDeviceGroupSurfacePresentModesKHX)(VkDevice device, VkSurfaceKHR surface, VkDeviceGroupPresentModeFlagsKHX* pModes);
-typedef VkResult (VKAPI_PTR *PFN_vkAcquireNextImage2KHX)(VkDevice device, const VkAcquireNextImageInfoKHX* pAcquireInfo, uint32_t* pImageIndex);
-typedef void (VKAPI_PTR *PFN_vkCmdDispatchBaseKHX)(VkCommandBuffer commandBuffer, uint32_t baseGroupX, uint32_t baseGroupY, uint32_t baseGroupZ, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ);
-typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDevicePresentRectanglesKHX)(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t* pRectCount, VkRect2D* pRects);
-
-#ifndef VK_NO_PROTOTYPES
-VKAPI_ATTR void VKAPI_CALL vkGetDeviceGroupPeerMemoryFeaturesKHX(
- VkDevice device,
- uint32_t heapIndex,
- uint32_t localDeviceIndex,
- uint32_t remoteDeviceIndex,
- VkPeerMemoryFeatureFlagsKHX* pPeerMemoryFeatures);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkBindBufferMemory2KHX(
- VkDevice device,
- uint32_t bindInfoCount,
- const VkBindBufferMemoryInfoKHX* pBindInfos);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkBindImageMemory2KHX(
- VkDevice device,
- uint32_t bindInfoCount,
- const VkBindImageMemoryInfoKHX* pBindInfos);
-
-VKAPI_ATTR void VKAPI_CALL vkCmdSetDeviceMaskKHX(
- VkCommandBuffer commandBuffer,
- uint32_t deviceMask);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkGetDeviceGroupPresentCapabilitiesKHX(
- VkDevice device,
- VkDeviceGroupPresentCapabilitiesKHX* pDeviceGroupPresentCapabilities);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkGetDeviceGroupSurfacePresentModesKHX(
- VkDevice device,
- VkSurfaceKHR surface,
- VkDeviceGroupPresentModeFlagsKHX* pModes);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkAcquireNextImage2KHX(
- VkDevice device,
- const VkAcquireNextImageInfoKHX* pAcquireInfo,
- uint32_t* pImageIndex);
-
-VKAPI_ATTR void VKAPI_CALL vkCmdDispatchBaseKHX(
- VkCommandBuffer commandBuffer,
- uint32_t baseGroupX,
- uint32_t baseGroupY,
- uint32_t baseGroupZ,
- uint32_t groupCountX,
- uint32_t groupCountY,
- uint32_t groupCountZ);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDevicePresentRectanglesKHX(
- VkPhysicalDevice physicalDevice,
- VkSurfaceKHR surface,
- uint32_t* pRectCount,
- VkRect2D* pRects);
-#endif
-
#define VK_EXT_validation_flags 1
#define VK_EXT_VALIDATION_FLAGS_SPEC_VERSION 1
#define VK_EXT_VALIDATION_FLAGS_EXTENSION_NAME "VK_EXT_validation_flags"
@@ -4845,9 +6389,10 @@
typedef enum VkValidationCheckEXT {
VK_VALIDATION_CHECK_ALL_EXT = 0,
+ VK_VALIDATION_CHECK_SHADERS_EXT = 1,
VK_VALIDATION_CHECK_BEGIN_RANGE_EXT = VK_VALIDATION_CHECK_ALL_EXT,
- VK_VALIDATION_CHECK_END_RANGE_EXT = VK_VALIDATION_CHECK_ALL_EXT,
- VK_VALIDATION_CHECK_RANGE_SIZE_EXT = (VK_VALIDATION_CHECK_ALL_EXT - VK_VALIDATION_CHECK_ALL_EXT + 1),
+ VK_VALIDATION_CHECK_END_RANGE_EXT = VK_VALIDATION_CHECK_SHADERS_EXT,
+ VK_VALIDATION_CHECK_RANGE_SIZE_EXT = (VK_VALIDATION_CHECK_SHADERS_EXT - VK_VALIDATION_CHECK_ALL_EXT + 1),
VK_VALIDATION_CHECK_MAX_ENUM_EXT = 0x7FFFFFFF
} VkValidationCheckEXT;
@@ -4896,402 +6441,38 @@
#define VK_EXT_SHADER_SUBGROUP_VOTE_EXTENSION_NAME "VK_EXT_shader_subgroup_vote"
-#define VK_KHX_device_group_creation 1
-#define VK_KHX_DEVICE_GROUP_CREATION_SPEC_VERSION 1
-#define VK_KHX_DEVICE_GROUP_CREATION_EXTENSION_NAME "VK_KHX_device_group_creation"
-
-typedef struct VkPhysicalDeviceGroupPropertiesKHX {
- VkStructureType sType;
- void* pNext;
- uint32_t physicalDeviceCount;
- VkPhysicalDevice physicalDevices[VK_MAX_DEVICE_GROUP_SIZE_KHX];
- VkBool32 subsetAllocation;
-} VkPhysicalDeviceGroupPropertiesKHX;
-
-typedef struct VkDeviceGroupDeviceCreateInfoKHX {
- VkStructureType sType;
- const void* pNext;
- uint32_t physicalDeviceCount;
- const VkPhysicalDevice* pPhysicalDevices;
-} VkDeviceGroupDeviceCreateInfoKHX;
-
-
-typedef VkResult (VKAPI_PTR *PFN_vkEnumeratePhysicalDeviceGroupsKHX)(VkInstance instance, uint32_t* pPhysicalDeviceGroupCount, VkPhysicalDeviceGroupPropertiesKHX* pPhysicalDeviceGroupProperties);
-
-#ifndef VK_NO_PROTOTYPES
-VKAPI_ATTR VkResult VKAPI_CALL vkEnumeratePhysicalDeviceGroupsKHX(
- VkInstance instance,
- uint32_t* pPhysicalDeviceGroupCount,
- VkPhysicalDeviceGroupPropertiesKHX* pPhysicalDeviceGroupProperties);
-#endif
-
-#define VK_KHX_external_memory_capabilities 1
-#define VK_LUID_SIZE_KHX 8
-#define VK_KHX_EXTERNAL_MEMORY_CAPABILITIES_SPEC_VERSION 1
-#define VK_KHX_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME "VK_KHX_external_memory_capabilities"
-
-
-typedef enum VkExternalMemoryHandleTypeFlagBitsKHX {
- VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHX = 0x00000001,
- VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHX = 0x00000002,
- VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHX = 0x00000004,
- VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT_KHX = 0x00000008,
- VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_KMT_BIT_KHX = 0x00000010,
- VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_HEAP_BIT_KHX = 0x00000020,
- VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_RESOURCE_BIT_KHX = 0x00000040,
- VK_EXTERNAL_MEMORY_HANDLE_TYPE_FLAG_BITS_MAX_ENUM_KHX = 0x7FFFFFFF
-} VkExternalMemoryHandleTypeFlagBitsKHX;
-typedef VkFlags VkExternalMemoryHandleTypeFlagsKHX;
-
-typedef enum VkExternalMemoryFeatureFlagBitsKHX {
- VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT_KHX = 0x00000001,
- VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT_KHX = 0x00000002,
- VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT_KHX = 0x00000004,
- VK_EXTERNAL_MEMORY_FEATURE_FLAG_BITS_MAX_ENUM_KHX = 0x7FFFFFFF
-} VkExternalMemoryFeatureFlagBitsKHX;
-typedef VkFlags VkExternalMemoryFeatureFlagsKHX;
-
-typedef struct VkExternalMemoryPropertiesKHX {
- VkExternalMemoryFeatureFlagsKHX externalMemoryFeatures;
- VkExternalMemoryHandleTypeFlagsKHX exportFromImportedHandleTypes;
- VkExternalMemoryHandleTypeFlagsKHX compatibleHandleTypes;
-} VkExternalMemoryPropertiesKHX;
-
-typedef struct VkPhysicalDeviceExternalImageFormatInfoKHX {
- VkStructureType sType;
- const void* pNext;
- VkExternalMemoryHandleTypeFlagBitsKHX handleType;
-} VkPhysicalDeviceExternalImageFormatInfoKHX;
-
-typedef struct VkExternalImageFormatPropertiesKHX {
- VkStructureType sType;
- void* pNext;
- VkExternalMemoryPropertiesKHX externalMemoryProperties;
-} VkExternalImageFormatPropertiesKHX;
-
-typedef struct VkPhysicalDeviceExternalBufferInfoKHX {
- VkStructureType sType;
- const void* pNext;
- VkBufferCreateFlags flags;
- VkBufferUsageFlags usage;
- VkExternalMemoryHandleTypeFlagBitsKHX handleType;
-} VkPhysicalDeviceExternalBufferInfoKHX;
-
-typedef struct VkExternalBufferPropertiesKHX {
- VkStructureType sType;
- void* pNext;
- VkExternalMemoryPropertiesKHX externalMemoryProperties;
-} VkExternalBufferPropertiesKHX;
-
-typedef struct VkPhysicalDeviceIDPropertiesKHX {
- VkStructureType sType;
- void* pNext;
- uint8_t deviceUUID[VK_UUID_SIZE];
- uint8_t driverUUID[VK_UUID_SIZE];
- uint8_t deviceLUID[VK_LUID_SIZE_KHX];
- VkBool32 deviceLUIDValid;
-} VkPhysicalDeviceIDPropertiesKHX;
-
-
-typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceExternalBufferPropertiesKHX)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalBufferInfoKHX* pExternalBufferInfo, VkExternalBufferPropertiesKHX* pExternalBufferProperties);
-
-#ifndef VK_NO_PROTOTYPES
-VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceExternalBufferPropertiesKHX(
- VkPhysicalDevice physicalDevice,
- const VkPhysicalDeviceExternalBufferInfoKHX* pExternalBufferInfo,
- VkExternalBufferPropertiesKHX* pExternalBufferProperties);
-#endif
-
-#define VK_KHX_external_memory 1
-#define VK_KHX_EXTERNAL_MEMORY_SPEC_VERSION 1
-#define VK_KHX_EXTERNAL_MEMORY_EXTENSION_NAME "VK_KHX_external_memory"
-#define VK_QUEUE_FAMILY_EXTERNAL_KHX (~0U-1)
-
-typedef struct VkExternalMemoryImageCreateInfoKHX {
- VkStructureType sType;
- const void* pNext;
- VkExternalMemoryHandleTypeFlagsKHX handleTypes;
-} VkExternalMemoryImageCreateInfoKHX;
-
-typedef struct VkExternalMemoryBufferCreateInfoKHX {
- VkStructureType sType;
- const void* pNext;
- VkExternalMemoryHandleTypeFlagsKHX handleTypes;
-} VkExternalMemoryBufferCreateInfoKHX;
-
-typedef struct VkExportMemoryAllocateInfoKHX {
- VkStructureType sType;
- const void* pNext;
- VkExternalMemoryHandleTypeFlagsKHX handleTypes;
-} VkExportMemoryAllocateInfoKHX;
-
-
-
-#ifdef VK_USE_PLATFORM_WIN32_KHX
-#define VK_KHX_external_memory_win32 1
-#define VK_KHX_EXTERNAL_MEMORY_WIN32_SPEC_VERSION 1
-#define VK_KHX_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME "VK_KHX_external_memory_win32"
-
-typedef struct VkImportMemoryWin32HandleInfoKHX {
- VkStructureType sType;
- const void* pNext;
- VkExternalMemoryHandleTypeFlagBitsKHX handleType;
- HANDLE handle;
-} VkImportMemoryWin32HandleInfoKHX;
-
-typedef struct VkExportMemoryWin32HandleInfoKHX {
- VkStructureType sType;
- const void* pNext;
- const SECURITY_ATTRIBUTES* pAttributes;
- DWORD dwAccess;
- LPCWSTR name;
-} VkExportMemoryWin32HandleInfoKHX;
-
-typedef struct VkMemoryWin32HandlePropertiesKHX {
- VkStructureType sType;
- void* pNext;
- uint32_t memoryTypeBits;
-} VkMemoryWin32HandlePropertiesKHX;
-
-
-typedef VkResult (VKAPI_PTR *PFN_vkGetMemoryWin32HandleKHX)(VkDevice device, VkDeviceMemory memory, VkExternalMemoryHandleTypeFlagBitsKHX handleType, HANDLE* pHandle);
-typedef VkResult (VKAPI_PTR *PFN_vkGetMemoryWin32HandlePropertiesKHX)(VkDevice device, VkExternalMemoryHandleTypeFlagBitsKHX handleType, HANDLE handle, VkMemoryWin32HandlePropertiesKHX* pMemoryWin32HandleProperties);
-
-#ifndef VK_NO_PROTOTYPES
-VKAPI_ATTR VkResult VKAPI_CALL vkGetMemoryWin32HandleKHX(
- VkDevice device,
- VkDeviceMemory memory,
- VkExternalMemoryHandleTypeFlagBitsKHX handleType,
- HANDLE* pHandle);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkGetMemoryWin32HandlePropertiesKHX(
- VkDevice device,
- VkExternalMemoryHandleTypeFlagBitsKHX handleType,
- HANDLE handle,
- VkMemoryWin32HandlePropertiesKHX* pMemoryWin32HandleProperties);
-#endif
-#endif /* VK_USE_PLATFORM_WIN32_KHX */
-
-#define VK_KHX_external_memory_fd 1
-#define VK_KHX_EXTERNAL_MEMORY_FD_SPEC_VERSION 1
-#define VK_KHX_EXTERNAL_MEMORY_FD_EXTENSION_NAME "VK_KHX_external_memory_fd"
-
-typedef struct VkImportMemoryFdInfoKHX {
- VkStructureType sType;
- const void* pNext;
- VkExternalMemoryHandleTypeFlagBitsKHX handleType;
- int fd;
-} VkImportMemoryFdInfoKHX;
-
-typedef struct VkMemoryFdPropertiesKHX {
- VkStructureType sType;
- void* pNext;
- uint32_t memoryTypeBits;
-} VkMemoryFdPropertiesKHX;
-
-
-typedef VkResult (VKAPI_PTR *PFN_vkGetMemoryFdKHX)(VkDevice device, VkDeviceMemory memory, VkExternalMemoryHandleTypeFlagBitsKHX handleType, int* pFd);
-typedef VkResult (VKAPI_PTR *PFN_vkGetMemoryFdPropertiesKHX)(VkDevice device, VkExternalMemoryHandleTypeFlagBitsKHX handleType, int fd, VkMemoryFdPropertiesKHX* pMemoryFdProperties);
-
-#ifndef VK_NO_PROTOTYPES
-VKAPI_ATTR VkResult VKAPI_CALL vkGetMemoryFdKHX(
- VkDevice device,
- VkDeviceMemory memory,
- VkExternalMemoryHandleTypeFlagBitsKHX handleType,
- int* pFd);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkGetMemoryFdPropertiesKHX(
- VkDevice device,
- VkExternalMemoryHandleTypeFlagBitsKHX handleType,
- int fd,
- VkMemoryFdPropertiesKHX* pMemoryFdProperties);
-#endif
-
-#ifdef VK_USE_PLATFORM_WIN32_KHR
-#define VK_KHX_win32_keyed_mutex 1
-#define VK_KHX_WIN32_KEYED_MUTEX_SPEC_VERSION 1
-#define VK_KHX_WIN32_KEYED_MUTEX_EXTENSION_NAME "VK_KHX_win32_keyed_mutex"
-
-typedef struct VkWin32KeyedMutexAcquireReleaseInfoKHX {
- VkStructureType sType;
- const void* pNext;
- uint32_t acquireCount;
- const VkDeviceMemory* pAcquireSyncs;
- const uint64_t* pAcquireKeys;
- const uint32_t* pAcquireTimeouts;
- uint32_t releaseCount;
- const VkDeviceMemory* pReleaseSyncs;
- const uint64_t* pReleaseKeys;
-} VkWin32KeyedMutexAcquireReleaseInfoKHX;
-
-
-#endif /* VK_USE_PLATFORM_WIN32_KHR */
-
-#define VK_KHX_external_semaphore_capabilities 1
-#define VK_KHX_EXTERNAL_SEMAPHORE_CAPABILITIES_SPEC_VERSION 1
-#define VK_KHX_EXTERNAL_SEMAPHORE_CAPABILITIES_EXTENSION_NAME "VK_KHX_external_semaphore_capabilities"
-
-
-typedef enum VkExternalSemaphoreHandleTypeFlagBitsKHX {
- VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT_KHX = 0x00000001,
- VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHX = 0x00000002,
- VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHX = 0x00000004,
- VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT_KHX = 0x00000008,
- VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_FENCE_FD_BIT_KHX = 0x00000010,
- VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_FLAG_BITS_MAX_ENUM_KHX = 0x7FFFFFFF
-} VkExternalSemaphoreHandleTypeFlagBitsKHX;
-typedef VkFlags VkExternalSemaphoreHandleTypeFlagsKHX;
-
-typedef enum VkExternalSemaphoreFeatureFlagBitsKHX {
- VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT_KHX = 0x00000001,
- VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT_KHX = 0x00000002,
- VK_EXTERNAL_SEMAPHORE_FEATURE_FLAG_BITS_MAX_ENUM_KHX = 0x7FFFFFFF
-} VkExternalSemaphoreFeatureFlagBitsKHX;
-typedef VkFlags VkExternalSemaphoreFeatureFlagsKHX;
-
-typedef struct VkPhysicalDeviceExternalSemaphoreInfoKHX {
- VkStructureType sType;
- const void* pNext;
- VkExternalSemaphoreHandleTypeFlagBitsKHX handleType;
-} VkPhysicalDeviceExternalSemaphoreInfoKHX;
-
-typedef struct VkExternalSemaphorePropertiesKHX {
- VkStructureType sType;
- void* pNext;
- VkExternalSemaphoreHandleTypeFlagsKHX exportFromImportedHandleTypes;
- VkExternalSemaphoreHandleTypeFlagsKHX compatibleHandleTypes;
- VkExternalSemaphoreFeatureFlagsKHX externalSemaphoreFeatures;
-} VkExternalSemaphorePropertiesKHX;
-
-
-typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceExternalSemaphorePropertiesKHX)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalSemaphoreInfoKHX* pExternalSemaphoreInfo, VkExternalSemaphorePropertiesKHX* pExternalSemaphoreProperties);
-
-#ifndef VK_NO_PROTOTYPES
-VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceExternalSemaphorePropertiesKHX(
- VkPhysicalDevice physicalDevice,
- const VkPhysicalDeviceExternalSemaphoreInfoKHX* pExternalSemaphoreInfo,
- VkExternalSemaphorePropertiesKHX* pExternalSemaphoreProperties);
-#endif
-
-#define VK_KHX_external_semaphore 1
-#define VK_KHX_EXTERNAL_SEMAPHORE_SPEC_VERSION 1
-#define VK_KHX_EXTERNAL_SEMAPHORE_EXTENSION_NAME "VK_KHX_external_semaphore"
-
-typedef struct VkExportSemaphoreCreateInfoKHX {
- VkStructureType sType;
- const void* pNext;
- VkExternalSemaphoreHandleTypeFlagsKHX handleTypes;
-} VkExportSemaphoreCreateInfoKHX;
-
-
-
-#ifdef VK_USE_PLATFORM_WIN32_KHX
-#define VK_KHX_external_semaphore_win32 1
-#define VK_KHX_EXTERNAL_SEMAPHORE_WIN32_SPEC_VERSION 1
-#define VK_KHX_EXTERNAL_SEMAPHORE_WIN32_EXTENSION_NAME "VK_KHX_external_semaphore_win32"
-
-typedef struct VkImportSemaphoreWin32HandleInfoKHX {
- VkStructureType sType;
- const void* pNext;
- VkSemaphore semaphore;
- VkExternalSemaphoreHandleTypeFlagsKHX handleType;
- HANDLE handle;
-} VkImportSemaphoreWin32HandleInfoKHX;
-
-typedef struct VkExportSemaphoreWin32HandleInfoKHX {
- VkStructureType sType;
- const void* pNext;
- const SECURITY_ATTRIBUTES* pAttributes;
- DWORD dwAccess;
- LPCWSTR name;
-} VkExportSemaphoreWin32HandleInfoKHX;
-
-typedef struct VkD3D12FenceSubmitInfoKHX {
- VkStructureType sType;
- const void* pNext;
- uint32_t waitSemaphoreValuesCount;
- const uint64_t* pWaitSemaphoreValues;
- uint32_t signalSemaphoreValuesCount;
- const uint64_t* pSignalSemaphoreValues;
-} VkD3D12FenceSubmitInfoKHX;
-
-
-typedef VkResult (VKAPI_PTR *PFN_vkImportSemaphoreWin32HandleKHX)(VkDevice device, const VkImportSemaphoreWin32HandleInfoKHX* pImportSemaphoreWin32HandleInfo);
-typedef VkResult (VKAPI_PTR *PFN_vkGetSemaphoreWin32HandleKHX)(VkDevice device, VkSemaphore semaphore, VkExternalSemaphoreHandleTypeFlagBitsKHX handleType, HANDLE* pHandle);
-
-#ifndef VK_NO_PROTOTYPES
-VKAPI_ATTR VkResult VKAPI_CALL vkImportSemaphoreWin32HandleKHX(
- VkDevice device,
- const VkImportSemaphoreWin32HandleInfoKHX* pImportSemaphoreWin32HandleInfo);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkGetSemaphoreWin32HandleKHX(
- VkDevice device,
- VkSemaphore semaphore,
- VkExternalSemaphoreHandleTypeFlagBitsKHX handleType,
- HANDLE* pHandle);
-#endif
-#endif /* VK_USE_PLATFORM_WIN32_KHX */
-
-#define VK_KHX_external_semaphore_fd 1
-#define VK_KHX_EXTERNAL_SEMAPHORE_FD_SPEC_VERSION 1
-#define VK_KHX_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME "VK_KHX_external_semaphore_fd"
-
-typedef struct VkImportSemaphoreFdInfoKHX {
- VkStructureType sType;
- const void* pNext;
- VkSemaphore semaphore;
- VkExternalSemaphoreHandleTypeFlagBitsKHX handleType;
- int fd;
-} VkImportSemaphoreFdInfoKHX;
-
-
-typedef VkResult (VKAPI_PTR *PFN_vkImportSemaphoreFdKHX)(VkDevice device, const VkImportSemaphoreFdInfoKHX* pImportSemaphoreFdInfo);
-typedef VkResult (VKAPI_PTR *PFN_vkGetSemaphoreFdKHX)(VkDevice device, VkSemaphore semaphore, VkExternalSemaphoreHandleTypeFlagBitsKHX handleType, int* pFd);
-
-#ifndef VK_NO_PROTOTYPES
-VKAPI_ATTR VkResult VKAPI_CALL vkImportSemaphoreFdKHX(
- VkDevice device,
- const VkImportSemaphoreFdInfoKHX* pImportSemaphoreFdInfo);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkGetSemaphoreFdKHX(
- VkDevice device,
- VkSemaphore semaphore,
- VkExternalSemaphoreHandleTypeFlagBitsKHX handleType,
- int* pFd);
-#endif
-
#define VK_NVX_device_generated_commands 1
VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkObjectTableNVX)
VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkIndirectCommandsLayoutNVX)
-#define VK_NVX_DEVICE_GENERATED_COMMANDS_SPEC_VERSION 1
+#define VK_NVX_DEVICE_GENERATED_COMMANDS_SPEC_VERSION 3
#define VK_NVX_DEVICE_GENERATED_COMMANDS_EXTENSION_NAME "VK_NVX_device_generated_commands"
typedef enum VkIndirectCommandsTokenTypeNVX {
- VK_INDIRECT_COMMANDS_TOKEN_PIPELINE_NVX = 0,
- VK_INDIRECT_COMMANDS_TOKEN_DESCRIPTOR_SET_NVX = 1,
- VK_INDIRECT_COMMANDS_TOKEN_INDEX_BUFFER_NVX = 2,
- VK_INDIRECT_COMMANDS_TOKEN_VERTEX_BUFFER_NVX = 3,
- VK_INDIRECT_COMMANDS_TOKEN_PUSH_CONSTANT_NVX = 4,
- VK_INDIRECT_COMMANDS_TOKEN_DRAW_INDEXED_NVX = 5,
- VK_INDIRECT_COMMANDS_TOKEN_DRAW_NVX = 6,
- VK_INDIRECT_COMMANDS_TOKEN_DISPATCH_NVX = 7,
- VK_INDIRECT_COMMANDS_TOKEN_TYPE_BEGIN_RANGE_NVX = VK_INDIRECT_COMMANDS_TOKEN_PIPELINE_NVX,
- VK_INDIRECT_COMMANDS_TOKEN_TYPE_END_RANGE_NVX = VK_INDIRECT_COMMANDS_TOKEN_DISPATCH_NVX,
- VK_INDIRECT_COMMANDS_TOKEN_TYPE_RANGE_SIZE_NVX = (VK_INDIRECT_COMMANDS_TOKEN_DISPATCH_NVX - VK_INDIRECT_COMMANDS_TOKEN_PIPELINE_NVX + 1),
+ VK_INDIRECT_COMMANDS_TOKEN_TYPE_PIPELINE_NVX = 0,
+ VK_INDIRECT_COMMANDS_TOKEN_TYPE_DESCRIPTOR_SET_NVX = 1,
+ VK_INDIRECT_COMMANDS_TOKEN_TYPE_INDEX_BUFFER_NVX = 2,
+ VK_INDIRECT_COMMANDS_TOKEN_TYPE_VERTEX_BUFFER_NVX = 3,
+ VK_INDIRECT_COMMANDS_TOKEN_TYPE_PUSH_CONSTANT_NVX = 4,
+ VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_INDEXED_NVX = 5,
+ VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_NVX = 6,
+ VK_INDIRECT_COMMANDS_TOKEN_TYPE_DISPATCH_NVX = 7,
+ VK_INDIRECT_COMMANDS_TOKEN_TYPE_BEGIN_RANGE_NVX = VK_INDIRECT_COMMANDS_TOKEN_TYPE_PIPELINE_NVX,
+ VK_INDIRECT_COMMANDS_TOKEN_TYPE_END_RANGE_NVX = VK_INDIRECT_COMMANDS_TOKEN_TYPE_DISPATCH_NVX,
+ VK_INDIRECT_COMMANDS_TOKEN_TYPE_RANGE_SIZE_NVX = (VK_INDIRECT_COMMANDS_TOKEN_TYPE_DISPATCH_NVX - VK_INDIRECT_COMMANDS_TOKEN_TYPE_PIPELINE_NVX + 1),
VK_INDIRECT_COMMANDS_TOKEN_TYPE_MAX_ENUM_NVX = 0x7FFFFFFF
} VkIndirectCommandsTokenTypeNVX;
typedef enum VkObjectEntryTypeNVX {
- VK_OBJECT_ENTRY_DESCRIPTOR_SET_NVX = 0,
- VK_OBJECT_ENTRY_PIPELINE_NVX = 1,
- VK_OBJECT_ENTRY_INDEX_BUFFER_NVX = 2,
- VK_OBJECT_ENTRY_VERTEX_BUFFER_NVX = 3,
- VK_OBJECT_ENTRY_PUSH_CONSTANT_NVX = 4,
- VK_OBJECT_ENTRY_TYPE_BEGIN_RANGE_NVX = VK_OBJECT_ENTRY_DESCRIPTOR_SET_NVX,
- VK_OBJECT_ENTRY_TYPE_END_RANGE_NVX = VK_OBJECT_ENTRY_PUSH_CONSTANT_NVX,
- VK_OBJECT_ENTRY_TYPE_RANGE_SIZE_NVX = (VK_OBJECT_ENTRY_PUSH_CONSTANT_NVX - VK_OBJECT_ENTRY_DESCRIPTOR_SET_NVX + 1),
+ VK_OBJECT_ENTRY_TYPE_DESCRIPTOR_SET_NVX = 0,
+ VK_OBJECT_ENTRY_TYPE_PIPELINE_NVX = 1,
+ VK_OBJECT_ENTRY_TYPE_INDEX_BUFFER_NVX = 2,
+ VK_OBJECT_ENTRY_TYPE_VERTEX_BUFFER_NVX = 3,
+ VK_OBJECT_ENTRY_TYPE_PUSH_CONSTANT_NVX = 4,
+ VK_OBJECT_ENTRY_TYPE_BEGIN_RANGE_NVX = VK_OBJECT_ENTRY_TYPE_DESCRIPTOR_SET_NVX,
+ VK_OBJECT_ENTRY_TYPE_END_RANGE_NVX = VK_OBJECT_ENTRY_TYPE_PUSH_CONSTANT_NVX,
+ VK_OBJECT_ENTRY_TYPE_RANGE_SIZE_NVX = (VK_OBJECT_ENTRY_TYPE_PUSH_CONSTANT_NVX - VK_OBJECT_ENTRY_TYPE_DESCRIPTOR_SET_NVX + 1),
VK_OBJECT_ENTRY_TYPE_MAX_ENUM_NVX = 0x7FFFFFFF
} VkObjectEntryTypeNVX;
@@ -5554,6 +6735,7 @@
#define VK_EXT_display_surface_counter 1
#define VK_EXT_DISPLAY_SURFACE_COUNTER_SPEC_VERSION 1
#define VK_EXT_DISPLAY_SURFACE_COUNTER_EXTENSION_NAME "VK_EXT_display_surface_counter"
+#define VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES2_EXT VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_EXT
typedef enum VkSurfaceCounterFlagBitsEXT {
@@ -5829,7 +7011,7 @@
#endif
#define VK_EXT_swapchain_colorspace 1
-#define VK_EXT_SWAPCHAIN_COLOR_SPACE_SPEC_VERSION 2
+#define VK_EXT_SWAPCHAIN_COLOR_SPACE_SPEC_VERSION 3
#define VK_EXT_SWAPCHAIN_COLOR_SPACE_EXTENSION_NAME "VK_EXT_swapchain_colorspace"
@@ -5918,6 +7100,296 @@
#endif
#endif /* VK_USE_PLATFORM_MACOS_MVK */
+#define VK_EXT_sampler_filter_minmax 1
+#define VK_EXT_SAMPLER_FILTER_MINMAX_SPEC_VERSION 1
+#define VK_EXT_SAMPLER_FILTER_MINMAX_EXTENSION_NAME "VK_EXT_sampler_filter_minmax"
+
+
+typedef enum VkSamplerReductionModeEXT {
+ VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE_EXT = 0,
+ VK_SAMPLER_REDUCTION_MODE_MIN_EXT = 1,
+ VK_SAMPLER_REDUCTION_MODE_MAX_EXT = 2,
+ VK_SAMPLER_REDUCTION_MODE_BEGIN_RANGE_EXT = VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE_EXT,
+ VK_SAMPLER_REDUCTION_MODE_END_RANGE_EXT = VK_SAMPLER_REDUCTION_MODE_MAX_EXT,
+ VK_SAMPLER_REDUCTION_MODE_RANGE_SIZE_EXT = (VK_SAMPLER_REDUCTION_MODE_MAX_EXT - VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE_EXT + 1),
+ VK_SAMPLER_REDUCTION_MODE_MAX_ENUM_EXT = 0x7FFFFFFF
+} VkSamplerReductionModeEXT;
+
+typedef struct VkSamplerReductionModeCreateInfoEXT {
+ VkStructureType sType;
+ const void* pNext;
+ VkSamplerReductionModeEXT reductionMode;
+} VkSamplerReductionModeCreateInfoEXT;
+
+typedef struct VkPhysicalDeviceSamplerFilterMinmaxPropertiesEXT {
+ VkStructureType sType;
+ void* pNext;
+ VkBool32 filterMinmaxSingleComponentFormats;
+ VkBool32 filterMinmaxImageComponentMapping;
+} VkPhysicalDeviceSamplerFilterMinmaxPropertiesEXT;
+
+
+
+#define VK_AMD_gpu_shader_int16 1
+#define VK_AMD_GPU_SHADER_INT16_SPEC_VERSION 1
+#define VK_AMD_GPU_SHADER_INT16_EXTENSION_NAME "VK_AMD_gpu_shader_int16"
+
+
+#define VK_AMD_mixed_attachment_samples 1
+#define VK_AMD_MIXED_ATTACHMENT_SAMPLES_SPEC_VERSION 1
+#define VK_AMD_MIXED_ATTACHMENT_SAMPLES_EXTENSION_NAME "VK_AMD_mixed_attachment_samples"
+
+
+#define VK_AMD_shader_fragment_mask 1
+#define VK_AMD_SHADER_FRAGMENT_MASK_SPEC_VERSION 1
+#define VK_AMD_SHADER_FRAGMENT_MASK_EXTENSION_NAME "VK_AMD_shader_fragment_mask"
+
+
+#define VK_EXT_shader_stencil_export 1
+#define VK_EXT_SHADER_STENCIL_EXPORT_SPEC_VERSION 1
+#define VK_EXT_SHADER_STENCIL_EXPORT_EXTENSION_NAME "VK_EXT_shader_stencil_export"
+
+
+#define VK_EXT_sample_locations 1
+#define VK_EXT_SAMPLE_LOCATIONS_SPEC_VERSION 1
+#define VK_EXT_SAMPLE_LOCATIONS_EXTENSION_NAME "VK_EXT_sample_locations"
+
+typedef struct VkSampleLocationEXT {
+ float x;
+ float y;
+} VkSampleLocationEXT;
+
+typedef struct VkSampleLocationsInfoEXT {
+ VkStructureType sType;
+ const void* pNext;
+ VkSampleCountFlagBits sampleLocationsPerPixel;
+ VkExtent2D sampleLocationGridSize;
+ uint32_t sampleLocationsCount;
+ const VkSampleLocationEXT* pSampleLocations;
+} VkSampleLocationsInfoEXT;
+
+typedef struct VkAttachmentSampleLocationsEXT {
+ uint32_t attachmentIndex;
+ VkSampleLocationsInfoEXT sampleLocationsInfo;
+} VkAttachmentSampleLocationsEXT;
+
+typedef struct VkSubpassSampleLocationsEXT {
+ uint32_t subpassIndex;
+ VkSampleLocationsInfoEXT sampleLocationsInfo;
+} VkSubpassSampleLocationsEXT;
+
+typedef struct VkRenderPassSampleLocationsBeginInfoEXT {
+ VkStructureType sType;
+ const void* pNext;
+ uint32_t attachmentInitialSampleLocationsCount;
+ const VkAttachmentSampleLocationsEXT* pAttachmentInitialSampleLocations;
+ uint32_t postSubpassSampleLocationsCount;
+ const VkSubpassSampleLocationsEXT* pSubpassSampleLocations;
+} VkRenderPassSampleLocationsBeginInfoEXT;
+
+typedef struct VkPipelineSampleLocationsStateCreateInfoEXT {
+ VkStructureType sType;
+ const void* pNext;
+ VkBool32 sampleLocationsEnable;
+ VkSampleLocationsInfoEXT sampleLocationsInfo;
+} VkPipelineSampleLocationsStateCreateInfoEXT;
+
+typedef struct VkPhysicalDeviceSampleLocationsPropertiesEXT {
+ VkStructureType sType;
+ void* pNext;
+ VkSampleCountFlags sampleLocationSampleCounts;
+ VkExtent2D maxSampleLocationGridSize;
+ float sampleLocationCoordinateRange[2];
+ uint32_t sampleLocationSubPixelBits;
+ VkBool32 variableSampleLocations;
+} VkPhysicalDeviceSampleLocationsPropertiesEXT;
+
+typedef struct VkMultisamplePropertiesEXT {
+ VkStructureType sType;
+ void* pNext;
+ VkExtent2D maxSampleLocationGridSize;
+} VkMultisamplePropertiesEXT;
+
+
+typedef void (VKAPI_PTR *PFN_vkCmdSetSampleLocationsEXT)(VkCommandBuffer commandBuffer, const VkSampleLocationsInfoEXT* pSampleLocationsInfo);
+typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceMultisamplePropertiesEXT)(VkPhysicalDevice physicalDevice, VkSampleCountFlagBits samples, VkMultisamplePropertiesEXT* pMultisampleProperties);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR void VKAPI_CALL vkCmdSetSampleLocationsEXT(
+ VkCommandBuffer commandBuffer,
+ const VkSampleLocationsInfoEXT* pSampleLocationsInfo);
+
+VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceMultisamplePropertiesEXT(
+ VkPhysicalDevice physicalDevice,
+ VkSampleCountFlagBits samples,
+ VkMultisamplePropertiesEXT* pMultisampleProperties);
+#endif
+
+#define VK_EXT_blend_operation_advanced 1
+#define VK_EXT_BLEND_OPERATION_ADVANCED_SPEC_VERSION 2
+#define VK_EXT_BLEND_OPERATION_ADVANCED_EXTENSION_NAME "VK_EXT_blend_operation_advanced"
+
+
+typedef enum VkBlendOverlapEXT {
+ VK_BLEND_OVERLAP_UNCORRELATED_EXT = 0,
+ VK_BLEND_OVERLAP_DISJOINT_EXT = 1,
+ VK_BLEND_OVERLAP_CONJOINT_EXT = 2,
+ VK_BLEND_OVERLAP_BEGIN_RANGE_EXT = VK_BLEND_OVERLAP_UNCORRELATED_EXT,
+ VK_BLEND_OVERLAP_END_RANGE_EXT = VK_BLEND_OVERLAP_CONJOINT_EXT,
+ VK_BLEND_OVERLAP_RANGE_SIZE_EXT = (VK_BLEND_OVERLAP_CONJOINT_EXT - VK_BLEND_OVERLAP_UNCORRELATED_EXT + 1),
+ VK_BLEND_OVERLAP_MAX_ENUM_EXT = 0x7FFFFFFF
+} VkBlendOverlapEXT;
+
+typedef struct VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT {
+ VkStructureType sType;
+ void* pNext;
+ VkBool32 advancedBlendCoherentOperations;
+} VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT;
+
+typedef struct VkPhysicalDeviceBlendOperationAdvancedPropertiesEXT {
+ VkStructureType sType;
+ void* pNext;
+ uint32_t advancedBlendMaxColorAttachments;
+ VkBool32 advancedBlendIndependentBlend;
+ VkBool32 advancedBlendNonPremultipliedSrcColor;
+ VkBool32 advancedBlendNonPremultipliedDstColor;
+ VkBool32 advancedBlendCorrelatedOverlap;
+ VkBool32 advancedBlendAllOperations;
+} VkPhysicalDeviceBlendOperationAdvancedPropertiesEXT;
+
+typedef struct VkPipelineColorBlendAdvancedStateCreateInfoEXT {
+ VkStructureType sType;
+ const void* pNext;
+ VkBool32 srcPremultiplied;
+ VkBool32 dstPremultiplied;
+ VkBlendOverlapEXT blendOverlap;
+} VkPipelineColorBlendAdvancedStateCreateInfoEXT;
+
+
+
+#define VK_NV_fragment_coverage_to_color 1
+#define VK_NV_FRAGMENT_COVERAGE_TO_COLOR_SPEC_VERSION 1
+#define VK_NV_FRAGMENT_COVERAGE_TO_COLOR_EXTENSION_NAME "VK_NV_fragment_coverage_to_color"
+
+typedef VkFlags VkPipelineCoverageToColorStateCreateFlagsNV;
+
+typedef struct VkPipelineCoverageToColorStateCreateInfoNV {
+ VkStructureType sType;
+ const void* pNext;
+ VkPipelineCoverageToColorStateCreateFlagsNV flags;
+ VkBool32 coverageToColorEnable;
+ uint32_t coverageToColorLocation;
+} VkPipelineCoverageToColorStateCreateInfoNV;
+
+
+
+#define VK_NV_framebuffer_mixed_samples 1
+#define VK_NV_FRAMEBUFFER_MIXED_SAMPLES_SPEC_VERSION 1
+#define VK_NV_FRAMEBUFFER_MIXED_SAMPLES_EXTENSION_NAME "VK_NV_framebuffer_mixed_samples"
+
+
+typedef enum VkCoverageModulationModeNV {
+ VK_COVERAGE_MODULATION_MODE_NONE_NV = 0,
+ VK_COVERAGE_MODULATION_MODE_RGB_NV = 1,
+ VK_COVERAGE_MODULATION_MODE_ALPHA_NV = 2,
+ VK_COVERAGE_MODULATION_MODE_RGBA_NV = 3,
+ VK_COVERAGE_MODULATION_MODE_BEGIN_RANGE_NV = VK_COVERAGE_MODULATION_MODE_NONE_NV,
+ VK_COVERAGE_MODULATION_MODE_END_RANGE_NV = VK_COVERAGE_MODULATION_MODE_RGBA_NV,
+ VK_COVERAGE_MODULATION_MODE_RANGE_SIZE_NV = (VK_COVERAGE_MODULATION_MODE_RGBA_NV - VK_COVERAGE_MODULATION_MODE_NONE_NV + 1),
+ VK_COVERAGE_MODULATION_MODE_MAX_ENUM_NV = 0x7FFFFFFF
+} VkCoverageModulationModeNV;
+
+typedef VkFlags VkPipelineCoverageModulationStateCreateFlagsNV;
+
+typedef struct VkPipelineCoverageModulationStateCreateInfoNV {
+ VkStructureType sType;
+ const void* pNext;
+ VkPipelineCoverageModulationStateCreateFlagsNV flags;
+ VkCoverageModulationModeNV coverageModulationMode;
+ VkBool32 coverageModulationTableEnable;
+ uint32_t coverageModulationTableCount;
+ const float* pCoverageModulationTable;
+} VkPipelineCoverageModulationStateCreateInfoNV;
+
+
+
+#define VK_NV_fill_rectangle 1
+#define VK_NV_FILL_RECTANGLE_SPEC_VERSION 1
+#define VK_NV_FILL_RECTANGLE_EXTENSION_NAME "VK_NV_fill_rectangle"
+
+
+#define VK_EXT_post_depth_coverage 1
+#define VK_EXT_POST_DEPTH_COVERAGE_SPEC_VERSION 1
+#define VK_EXT_POST_DEPTH_COVERAGE_EXTENSION_NAME "VK_EXT_post_depth_coverage"
+
+
+#define VK_EXT_validation_cache 1
+VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkValidationCacheEXT)
+
+#define VK_EXT_VALIDATION_CACHE_SPEC_VERSION 1
+#define VK_EXT_VALIDATION_CACHE_EXTENSION_NAME "VK_EXT_validation_cache"
+
+
+typedef enum VkValidationCacheHeaderVersionEXT {
+ VK_VALIDATION_CACHE_HEADER_VERSION_ONE_EXT = 1,
+ VK_VALIDATION_CACHE_HEADER_VERSION_BEGIN_RANGE_EXT = VK_VALIDATION_CACHE_HEADER_VERSION_ONE_EXT,
+ VK_VALIDATION_CACHE_HEADER_VERSION_END_RANGE_EXT = VK_VALIDATION_CACHE_HEADER_VERSION_ONE_EXT,
+ VK_VALIDATION_CACHE_HEADER_VERSION_RANGE_SIZE_EXT = (VK_VALIDATION_CACHE_HEADER_VERSION_ONE_EXT - VK_VALIDATION_CACHE_HEADER_VERSION_ONE_EXT + 1),
+ VK_VALIDATION_CACHE_HEADER_VERSION_MAX_ENUM_EXT = 0x7FFFFFFF
+} VkValidationCacheHeaderVersionEXT;
+
+typedef VkFlags VkValidationCacheCreateFlagsEXT;
+
+typedef struct VkValidationCacheCreateInfoEXT {
+ VkStructureType sType;
+ const void* pNext;
+ VkValidationCacheCreateFlagsEXT flags;
+ size_t initialDataSize;
+ const void* pInitialData;
+} VkValidationCacheCreateInfoEXT;
+
+typedef struct VkShaderModuleValidationCacheCreateInfoEXT {
+ VkStructureType sType;
+ const void* pNext;
+ VkValidationCacheEXT validationCache;
+} VkShaderModuleValidationCacheCreateInfoEXT;
+
+
+typedef VkResult (VKAPI_PTR *PFN_vkCreateValidationCacheEXT)(VkDevice device, const VkValidationCacheCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkValidationCacheEXT* pValidationCache);
+typedef void (VKAPI_PTR *PFN_vkDestroyValidationCacheEXT)(VkDevice device, VkValidationCacheEXT validationCache, const VkAllocationCallbacks* pAllocator);
+typedef VkResult (VKAPI_PTR *PFN_vkMergeValidationCachesEXT)(VkDevice device, VkValidationCacheEXT dstCache, uint32_t srcCacheCount, const VkValidationCacheEXT* pSrcCaches);
+typedef VkResult (VKAPI_PTR *PFN_vkGetValidationCacheDataEXT)(VkDevice device, VkValidationCacheEXT validationCache, size_t* pDataSize, void* pData);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR VkResult VKAPI_CALL vkCreateValidationCacheEXT(
+ VkDevice device,
+ const VkValidationCacheCreateInfoEXT* pCreateInfo,
+ const VkAllocationCallbacks* pAllocator,
+ VkValidationCacheEXT* pValidationCache);
+
+VKAPI_ATTR void VKAPI_CALL vkDestroyValidationCacheEXT(
+ VkDevice device,
+ VkValidationCacheEXT validationCache,
+ const VkAllocationCallbacks* pAllocator);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkMergeValidationCachesEXT(
+ VkDevice device,
+ VkValidationCacheEXT dstCache,
+ uint32_t srcCacheCount,
+ const VkValidationCacheEXT* pSrcCaches);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkGetValidationCacheDataEXT(
+ VkDevice device,
+ VkValidationCacheEXT validationCache,
+ size_t* pDataSize,
+ void* pData);
+#endif
+
+#define VK_EXT_shader_viewport_index_layer 1
+#define VK_EXT_SHADER_VIEWPORT_INDEX_LAYER_SPEC_VERSION 1
+#define VK_EXT_SHADER_VIEWPORT_INDEX_LAYER_EXTENSION_NAME "VK_EXT_shader_viewport_index_layer"
+
+
#ifdef __cplusplus
}
#endif
diff --git a/vulkan/libvulkan/Android.bp b/vulkan/libvulkan/Android.bp
index 5f9b357..b55fa27 100644
--- a/vulkan/libvulkan/Android.bp
+++ b/vulkan/libvulkan/Android.bp
@@ -80,6 +80,7 @@
"libcutils",
"libz",
"libnativewindow",
+ "android.hardware.graphics.common@1.0",
],
static_libs: ["libgrallocusage"],
}
diff --git a/vulkan/libvulkan/api.cpp b/vulkan/libvulkan/api.cpp
index e05ca5a..d840786 100644
--- a/vulkan/libvulkan/api.cpp
+++ b/vulkan/libvulkan/api.cpp
@@ -1280,5 +1280,10 @@
physicalDevice, nullptr, pPropertyCount, pProperties);
}
+VkResult EnumerateInstanceVersion(uint32_t* pApiVersion) {
+ *pApiVersion = VK_API_VERSION_1_1;
+ return VK_SUCCESS;
+}
+
} // namespace api
} // namespace vulkan
diff --git a/vulkan/libvulkan/api.h b/vulkan/libvulkan/api.h
index ded7d17..416cba0 100644
--- a/vulkan/libvulkan/api.h
+++ b/vulkan/libvulkan/api.h
@@ -33,6 +33,7 @@
VKAPI_ATTR VkResult EnumerateInstanceExtensionProperties(const char* pLayerName, uint32_t* pPropertyCount, VkExtensionProperties* pProperties);
VKAPI_ATTR VkResult EnumerateDeviceLayerProperties(VkPhysicalDevice physicalDevice, uint32_t* pPropertyCount, VkLayerProperties* pProperties);
VKAPI_ATTR VkResult EnumerateDeviceExtensionProperties(VkPhysicalDevice physicalDevice, const char* pLayerName, uint32_t* pPropertyCount, VkExtensionProperties* pProperties);
+VKAPI_ATTR VkResult EnumerateInstanceVersion(uint32_t* pApiVersion);
// clang-format on
inline InstanceData& GetData(VkInstance instance) {
diff --git a/vulkan/libvulkan/api_gen.cpp b/vulkan/libvulkan/api_gen.cpp
index 54c77f1..2aa1d5a 100644
--- a/vulkan/libvulkan/api_gen.cpp
+++ b/vulkan/libvulkan/api_gen.cpp
@@ -103,6 +103,26 @@
return VK_SUCCESS;
}
+VKAPI_ATTR VkResult disabledGetDeviceGroupPresentCapabilitiesKHR(VkDevice device, VkDeviceGroupPresentCapabilitiesKHR*) {
+ driver::Logger(device).Err(device, "VK_KHR_swapchain not enabled. Exported vkGetDeviceGroupPresentCapabilitiesKHR not executed.");
+ return VK_SUCCESS;
+}
+
+VKAPI_ATTR VkResult disabledGetDeviceGroupSurfacePresentModesKHR(VkDevice device, VkSurfaceKHR, VkDeviceGroupPresentModeFlagsKHR*) {
+ driver::Logger(device).Err(device, "VK_KHR_swapchain not enabled. Exported vkGetDeviceGroupSurfacePresentModesKHR not executed.");
+ return VK_SUCCESS;
+}
+
+VKAPI_ATTR VkResult disabledGetPhysicalDevicePresentRectanglesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR, uint32_t*, VkRect2D*) {
+ driver::Logger(physicalDevice).Err(physicalDevice, "VK_KHR_swapchain not enabled. Exported vkGetPhysicalDevicePresentRectanglesKHR not executed.");
+ return VK_SUCCESS;
+}
+
+VKAPI_ATTR VkResult disabledAcquireNextImage2KHR(VkDevice device, const VkAcquireNextImageInfoKHR*, uint32_t*) {
+ driver::Logger(device).Err(device, "VK_KHR_swapchain not enabled. Exported vkAcquireNextImage2KHR not executed.");
+ return VK_SUCCESS;
+}
+
VKAPI_ATTR VkResult disabledCreateAndroidSurfaceKHR(VkInstance instance, const VkAndroidSurfaceCreateInfoKHR*, const VkAllocationCallbacks*, VkSurfaceKHR*) {
driver::Logger(instance).Err(instance, "VK_KHR_android_surface not enabled. Exported vkCreateAndroidSurfaceKHR not executed.");
return VK_SUCCESS;
@@ -132,11 +152,23 @@
INIT_PROC(true, instance, CreateDevice);
INIT_PROC(true, instance, EnumerateDeviceExtensionProperties);
INIT_PROC(true, instance, GetPhysicalDeviceSparseImageFormatProperties);
+ INIT_PROC(false, instance, EnumeratePhysicalDeviceGroups);
+ INIT_PROC(false, instance, GetPhysicalDeviceFeatures2);
+ INIT_PROC(false, instance, GetPhysicalDeviceProperties2);
+ INIT_PROC(false, instance, GetPhysicalDeviceFormatProperties2);
+ INIT_PROC(false, instance, GetPhysicalDeviceImageFormatProperties2);
+ INIT_PROC(false, instance, GetPhysicalDeviceQueueFamilyProperties2);
+ INIT_PROC(false, instance, GetPhysicalDeviceMemoryProperties2);
+ INIT_PROC(false, instance, GetPhysicalDeviceSparseImageFormatProperties2);
+ INIT_PROC(false, instance, GetPhysicalDeviceExternalBufferProperties);
+ INIT_PROC(false, instance, GetPhysicalDeviceExternalFenceProperties);
+ INIT_PROC(false, instance, GetPhysicalDeviceExternalSemaphoreProperties);
INIT_PROC_EXT(KHR_surface, true, instance, DestroySurfaceKHR);
INIT_PROC_EXT(KHR_surface, true, instance, GetPhysicalDeviceSurfaceSupportKHR);
INIT_PROC_EXT(KHR_surface, true, instance, GetPhysicalDeviceSurfaceCapabilitiesKHR);
INIT_PROC_EXT(KHR_surface, true, instance, GetPhysicalDeviceSurfaceFormatsKHR);
INIT_PROC_EXT(KHR_surface, true, instance, GetPhysicalDeviceSurfacePresentModesKHR);
+ INIT_PROC_EXT(KHR_swapchain, false, instance, GetPhysicalDevicePresentRectanglesKHR);
INIT_PROC_EXT(KHR_android_surface, true, instance, CreateAndroidSurfaceKHR);
// clang-format on
@@ -272,11 +304,30 @@
INIT_PROC(true, dev, CmdNextSubpass);
INIT_PROC(true, dev, CmdEndRenderPass);
INIT_PROC(true, dev, CmdExecuteCommands);
+ INIT_PROC(false, dev, BindBufferMemory2);
+ INIT_PROC(false, dev, BindImageMemory2);
+ INIT_PROC(false, dev, GetDeviceGroupPeerMemoryFeatures);
+ INIT_PROC(false, dev, CmdSetDeviceMask);
+ INIT_PROC(false, dev, CmdDispatchBase);
+ INIT_PROC(false, dev, GetImageMemoryRequirements2);
+ INIT_PROC(false, dev, GetBufferMemoryRequirements2);
+ INIT_PROC(false, dev, GetImageSparseMemoryRequirements2);
+ INIT_PROC(false, dev, TrimCommandPool);
+ INIT_PROC(false, dev, GetDeviceQueue2);
+ INIT_PROC(false, dev, CreateSamplerYcbcrConversion);
+ INIT_PROC(false, dev, DestroySamplerYcbcrConversion);
+ INIT_PROC(false, dev, CreateDescriptorUpdateTemplate);
+ INIT_PROC(false, dev, DestroyDescriptorUpdateTemplate);
+ INIT_PROC(false, dev, UpdateDescriptorSetWithTemplate);
+ INIT_PROC(false, dev, GetDescriptorSetLayoutSupport);
INIT_PROC_EXT(KHR_swapchain, true, dev, CreateSwapchainKHR);
INIT_PROC_EXT(KHR_swapchain, true, dev, DestroySwapchainKHR);
INIT_PROC_EXT(KHR_swapchain, true, dev, GetSwapchainImagesKHR);
INIT_PROC_EXT(KHR_swapchain, true, dev, AcquireNextImageKHR);
INIT_PROC_EXT(KHR_swapchain, true, dev, QueuePresentKHR);
+ INIT_PROC_EXT(KHR_swapchain, false, dev, GetDeviceGroupPresentCapabilitiesKHR);
+ INIT_PROC_EXT(KHR_swapchain, false, dev, GetDeviceGroupSurfacePresentModesKHR);
+ INIT_PROC_EXT(KHR_swapchain, false, dev, AcquireNextImage2KHR);
// clang-format on
return success;
@@ -416,6 +467,33 @@
VKAPI_ATTR void CmdNextSubpass(VkCommandBuffer commandBuffer, VkSubpassContents contents);
VKAPI_ATTR void CmdEndRenderPass(VkCommandBuffer commandBuffer);
VKAPI_ATTR void CmdExecuteCommands(VkCommandBuffer commandBuffer, uint32_t commandBufferCount, const VkCommandBuffer* pCommandBuffers);
+VKAPI_ATTR VkResult BindBufferMemory2(VkDevice device, uint32_t bindInfoCount, const VkBindBufferMemoryInfo* pBindInfos);
+VKAPI_ATTR VkResult BindImageMemory2(VkDevice device, uint32_t bindInfoCount, const VkBindImageMemoryInfo* pBindInfos);
+VKAPI_ATTR void GetDeviceGroupPeerMemoryFeatures(VkDevice device, uint32_t heapIndex, uint32_t localDeviceIndex, uint32_t remoteDeviceIndex, VkPeerMemoryFeatureFlags* pPeerMemoryFeatures);
+VKAPI_ATTR void CmdSetDeviceMask(VkCommandBuffer commandBuffer, uint32_t deviceMask);
+VKAPI_ATTR void CmdDispatchBase(VkCommandBuffer commandBuffer, uint32_t baseGroupX, uint32_t baseGroupY, uint32_t baseGroupZ, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ);
+VKAPI_ATTR VkResult EnumeratePhysicalDeviceGroups(VkInstance instance, uint32_t* pPhysicalDeviceGroupCount, VkPhysicalDeviceGroupProperties* pPhysicalDeviceGroupProperties);
+VKAPI_ATTR void GetImageMemoryRequirements2(VkDevice device, const VkImageMemoryRequirementsInfo2* pInfo, VkMemoryRequirements2* pMemoryRequirements);
+VKAPI_ATTR void GetBufferMemoryRequirements2(VkDevice device, const VkBufferMemoryRequirementsInfo2* pInfo, VkMemoryRequirements2* pMemoryRequirements);
+VKAPI_ATTR void GetImageSparseMemoryRequirements2(VkDevice device, const VkImageSparseMemoryRequirementsInfo2* pInfo, uint32_t* pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements2* pSparseMemoryRequirements);
+VKAPI_ATTR void GetPhysicalDeviceFeatures2(VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures2* pFeatures);
+VKAPI_ATTR void GetPhysicalDeviceProperties2(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties2* pProperties);
+VKAPI_ATTR void GetPhysicalDeviceFormatProperties2(VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties2* pFormatProperties);
+VKAPI_ATTR VkResult GetPhysicalDeviceImageFormatProperties2(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceImageFormatInfo2* pImageFormatInfo, VkImageFormatProperties2* pImageFormatProperties);
+VKAPI_ATTR void GetPhysicalDeviceQueueFamilyProperties2(VkPhysicalDevice physicalDevice, uint32_t* pQueueFamilyPropertyCount, VkQueueFamilyProperties2* pQueueFamilyProperties);
+VKAPI_ATTR void GetPhysicalDeviceMemoryProperties2(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties2* pMemoryProperties);
+VKAPI_ATTR void GetPhysicalDeviceSparseImageFormatProperties2(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSparseImageFormatInfo2* pFormatInfo, uint32_t* pPropertyCount, VkSparseImageFormatProperties2* pProperties);
+VKAPI_ATTR void TrimCommandPool(VkDevice device, VkCommandPool commandPool, VkCommandPoolTrimFlags flags);
+VKAPI_ATTR void GetDeviceQueue2(VkDevice device, const VkDeviceQueueInfo2* pQueueInfo, VkQueue* pQueue);
+VKAPI_ATTR VkResult CreateSamplerYcbcrConversion(VkDevice device, const VkSamplerYcbcrConversionCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSamplerYcbcrConversion* pYcbcrConversion);
+VKAPI_ATTR void DestroySamplerYcbcrConversion(VkDevice device, VkSamplerYcbcrConversion ycbcrConversion, const VkAllocationCallbacks* pAllocator);
+VKAPI_ATTR VkResult CreateDescriptorUpdateTemplate(VkDevice device, const VkDescriptorUpdateTemplateCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDescriptorUpdateTemplate* pDescriptorUpdateTemplate);
+VKAPI_ATTR void DestroyDescriptorUpdateTemplate(VkDevice device, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const VkAllocationCallbacks* pAllocator);
+VKAPI_ATTR void UpdateDescriptorSetWithTemplate(VkDevice device, VkDescriptorSet descriptorSet, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const void* pData);
+VKAPI_ATTR void GetPhysicalDeviceExternalBufferProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalBufferInfo* pExternalBufferInfo, VkExternalBufferProperties* pExternalBufferProperties);
+VKAPI_ATTR void GetPhysicalDeviceExternalFenceProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalFenceInfo* pExternalFenceInfo, VkExternalFenceProperties* pExternalFenceProperties);
+VKAPI_ATTR void GetPhysicalDeviceExternalSemaphoreProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalSemaphoreInfo* pExternalSemaphoreInfo, VkExternalSemaphoreProperties* pExternalSemaphoreProperties);
+VKAPI_ATTR void GetDescriptorSetLayoutSupport(VkDevice device, const VkDescriptorSetLayoutCreateInfo* pCreateInfo, VkDescriptorSetLayoutSupport* pSupport);
VKAPI_ATTR void DestroySurfaceKHR(VkInstance instance, VkSurfaceKHR surface, const VkAllocationCallbacks* pAllocator);
VKAPI_ATTR VkResult GetPhysicalDeviceSurfaceSupportKHR(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, VkSurfaceKHR surface, VkBool32* pSupported);
VKAPI_ATTR VkResult GetPhysicalDeviceSurfaceCapabilitiesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, VkSurfaceCapabilitiesKHR* pSurfaceCapabilities);
@@ -426,6 +504,10 @@
VKAPI_ATTR VkResult GetSwapchainImagesKHR(VkDevice device, VkSwapchainKHR swapchain, uint32_t* pSwapchainImageCount, VkImage* pSwapchainImages);
VKAPI_ATTR VkResult AcquireNextImageKHR(VkDevice device, VkSwapchainKHR swapchain, uint64_t timeout, VkSemaphore semaphore, VkFence fence, uint32_t* pImageIndex);
VKAPI_ATTR VkResult QueuePresentKHR(VkQueue queue, const VkPresentInfoKHR* pPresentInfo);
+VKAPI_ATTR VkResult GetDeviceGroupPresentCapabilitiesKHR(VkDevice device, VkDeviceGroupPresentCapabilitiesKHR* pDeviceGroupPresentCapabilities);
+VKAPI_ATTR VkResult GetDeviceGroupSurfacePresentModesKHR(VkDevice device, VkSurfaceKHR surface, VkDeviceGroupPresentModeFlagsKHR* pModes);
+VKAPI_ATTR VkResult GetPhysicalDevicePresentRectanglesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t* pRectCount, VkRect2D* pRects);
+VKAPI_ATTR VkResult AcquireNextImage2KHR(VkDevice device, const VkAcquireNextImageInfoKHR* pAcquireInfo, uint32_t* pImageIndex);
VKAPI_ATTR VkResult CreateAndroidSurfaceKHR(VkInstance instance, const VkAndroidSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface);
VKAPI_ATTR VkResult EnumeratePhysicalDevices(VkInstance instance, uint32_t* pPhysicalDeviceCount, VkPhysicalDevice* pPhysicalDevices) {
@@ -451,27 +533,41 @@
"vkEnumerateDeviceLayerProperties",
"vkEnumerateInstanceExtensionProperties",
"vkEnumerateInstanceLayerProperties",
- "vkEnumeratePhysicalDeviceGroupsKHX",
+ "vkEnumerateInstanceVersion",
+ "vkEnumeratePhysicalDeviceGroups",
+ "vkEnumeratePhysicalDeviceGroupsKHR",
"vkEnumeratePhysicalDevices",
"vkGetInstanceProcAddr",
- "vkGetPhysicalDeviceExternalBufferPropertiesKHX",
+ "vkGetPhysicalDeviceExternalBufferProperties",
+ "vkGetPhysicalDeviceExternalBufferPropertiesKHR",
+ "vkGetPhysicalDeviceExternalFenceProperties",
+ "vkGetPhysicalDeviceExternalFencePropertiesKHR",
"vkGetPhysicalDeviceExternalImageFormatPropertiesNV",
- "vkGetPhysicalDeviceExternalSemaphorePropertiesKHX",
+ "vkGetPhysicalDeviceExternalSemaphoreProperties",
+ "vkGetPhysicalDeviceExternalSemaphorePropertiesKHR",
"vkGetPhysicalDeviceFeatures",
+ "vkGetPhysicalDeviceFeatures2",
"vkGetPhysicalDeviceFeatures2KHR",
"vkGetPhysicalDeviceFormatProperties",
+ "vkGetPhysicalDeviceFormatProperties2",
"vkGetPhysicalDeviceFormatProperties2KHR",
"vkGetPhysicalDeviceGeneratedCommandsPropertiesNVX",
"vkGetPhysicalDeviceImageFormatProperties",
+ "vkGetPhysicalDeviceImageFormatProperties2",
"vkGetPhysicalDeviceImageFormatProperties2KHR",
"vkGetPhysicalDeviceMemoryProperties",
+ "vkGetPhysicalDeviceMemoryProperties2",
"vkGetPhysicalDeviceMemoryProperties2KHR",
- "vkGetPhysicalDevicePresentRectanglesKHX",
+ "vkGetPhysicalDeviceMultisamplePropertiesEXT",
+ "vkGetPhysicalDevicePresentRectanglesKHR",
"vkGetPhysicalDeviceProperties",
+ "vkGetPhysicalDeviceProperties2",
"vkGetPhysicalDeviceProperties2KHR",
"vkGetPhysicalDeviceQueueFamilyProperties",
+ "vkGetPhysicalDeviceQueueFamilyProperties2",
"vkGetPhysicalDeviceQueueFamilyProperties2KHR",
"vkGetPhysicalDeviceSparseImageFormatProperties",
+ "vkGetPhysicalDeviceSparseImageFormatProperties2",
"vkGetPhysicalDeviceSparseImageFormatProperties2KHR",
"vkGetPhysicalDeviceSurfaceCapabilities2KHR",
"vkGetPhysicalDeviceSurfaceCapabilitiesKHR",
@@ -506,6 +602,7 @@
if (strcmp(pName, "vkCreateInstance") == 0) return reinterpret_cast<PFN_vkVoidFunction>(CreateInstance);
if (strcmp(pName, "vkEnumerateInstanceLayerProperties") == 0) return reinterpret_cast<PFN_vkVoidFunction>(EnumerateInstanceLayerProperties);
if (strcmp(pName, "vkEnumerateInstanceExtensionProperties") == 0) return reinterpret_cast<PFN_vkVoidFunction>(EnumerateInstanceExtensionProperties);
+ if (strcmp(pName, "vkEnumerateInstanceVersion") == 0) return reinterpret_cast<PFN_vkVoidFunction>(EnumerateInstanceVersion);
ALOGE("invalid vkGetInstanceProcAddr(VK_NULL_HANDLE, \"%s\") call", pName);
return nullptr;
@@ -515,13 +612,16 @@
const char* name;
PFN_vkVoidFunction proc;
} hooks[] = {
+ { "vkAcquireNextImage2KHR", reinterpret_cast<PFN_vkVoidFunction>(AcquireNextImage2KHR) },
{ "vkAcquireNextImageKHR", reinterpret_cast<PFN_vkVoidFunction>(AcquireNextImageKHR) },
{ "vkAllocateCommandBuffers", reinterpret_cast<PFN_vkVoidFunction>(AllocateCommandBuffers) },
{ "vkAllocateDescriptorSets", reinterpret_cast<PFN_vkVoidFunction>(AllocateDescriptorSets) },
{ "vkAllocateMemory", reinterpret_cast<PFN_vkVoidFunction>(AllocateMemory) },
{ "vkBeginCommandBuffer", reinterpret_cast<PFN_vkVoidFunction>(BeginCommandBuffer) },
{ "vkBindBufferMemory", reinterpret_cast<PFN_vkVoidFunction>(BindBufferMemory) },
+ { "vkBindBufferMemory2", reinterpret_cast<PFN_vkVoidFunction>(BindBufferMemory2) },
{ "vkBindImageMemory", reinterpret_cast<PFN_vkVoidFunction>(BindImageMemory) },
+ { "vkBindImageMemory2", reinterpret_cast<PFN_vkVoidFunction>(BindImageMemory2) },
{ "vkCmdBeginQuery", reinterpret_cast<PFN_vkVoidFunction>(CmdBeginQuery) },
{ "vkCmdBeginRenderPass", reinterpret_cast<PFN_vkVoidFunction>(CmdBeginRenderPass) },
{ "vkCmdBindDescriptorSets", reinterpret_cast<PFN_vkVoidFunction>(CmdBindDescriptorSets) },
@@ -538,6 +638,7 @@
{ "vkCmdCopyImageToBuffer", reinterpret_cast<PFN_vkVoidFunction>(CmdCopyImageToBuffer) },
{ "vkCmdCopyQueryPoolResults", reinterpret_cast<PFN_vkVoidFunction>(CmdCopyQueryPoolResults) },
{ "vkCmdDispatch", reinterpret_cast<PFN_vkVoidFunction>(CmdDispatch) },
+ { "vkCmdDispatchBase", reinterpret_cast<PFN_vkVoidFunction>(CmdDispatchBase) },
{ "vkCmdDispatchIndirect", reinterpret_cast<PFN_vkVoidFunction>(CmdDispatchIndirect) },
{ "vkCmdDraw", reinterpret_cast<PFN_vkVoidFunction>(CmdDraw) },
{ "vkCmdDrawIndexed", reinterpret_cast<PFN_vkVoidFunction>(CmdDrawIndexed) },
@@ -556,6 +657,7 @@
{ "vkCmdSetBlendConstants", reinterpret_cast<PFN_vkVoidFunction>(CmdSetBlendConstants) },
{ "vkCmdSetDepthBias", reinterpret_cast<PFN_vkVoidFunction>(CmdSetDepthBias) },
{ "vkCmdSetDepthBounds", reinterpret_cast<PFN_vkVoidFunction>(CmdSetDepthBounds) },
+ { "vkCmdSetDeviceMask", reinterpret_cast<PFN_vkVoidFunction>(CmdSetDeviceMask) },
{ "vkCmdSetEvent", reinterpret_cast<PFN_vkVoidFunction>(CmdSetEvent) },
{ "vkCmdSetLineWidth", reinterpret_cast<PFN_vkVoidFunction>(CmdSetLineWidth) },
{ "vkCmdSetScissor", reinterpret_cast<PFN_vkVoidFunction>(CmdSetScissor) },
@@ -572,6 +674,7 @@
{ "vkCreateComputePipelines", reinterpret_cast<PFN_vkVoidFunction>(CreateComputePipelines) },
{ "vkCreateDescriptorPool", reinterpret_cast<PFN_vkVoidFunction>(CreateDescriptorPool) },
{ "vkCreateDescriptorSetLayout", reinterpret_cast<PFN_vkVoidFunction>(CreateDescriptorSetLayout) },
+ { "vkCreateDescriptorUpdateTemplate", reinterpret_cast<PFN_vkVoidFunction>(CreateDescriptorUpdateTemplate) },
{ "vkCreateDevice", reinterpret_cast<PFN_vkVoidFunction>(CreateDevice) },
{ "vkCreateEvent", reinterpret_cast<PFN_vkVoidFunction>(CreateEvent) },
{ "vkCreateFence", reinterpret_cast<PFN_vkVoidFunction>(CreateFence) },
@@ -585,6 +688,7 @@
{ "vkCreateQueryPool", reinterpret_cast<PFN_vkVoidFunction>(CreateQueryPool) },
{ "vkCreateRenderPass", reinterpret_cast<PFN_vkVoidFunction>(CreateRenderPass) },
{ "vkCreateSampler", reinterpret_cast<PFN_vkVoidFunction>(CreateSampler) },
+ { "vkCreateSamplerYcbcrConversion", reinterpret_cast<PFN_vkVoidFunction>(CreateSamplerYcbcrConversion) },
{ "vkCreateSemaphore", reinterpret_cast<PFN_vkVoidFunction>(CreateSemaphore) },
{ "vkCreateShaderModule", reinterpret_cast<PFN_vkVoidFunction>(CreateShaderModule) },
{ "vkCreateSwapchainKHR", reinterpret_cast<PFN_vkVoidFunction>(CreateSwapchainKHR) },
@@ -593,6 +697,7 @@
{ "vkDestroyCommandPool", reinterpret_cast<PFN_vkVoidFunction>(DestroyCommandPool) },
{ "vkDestroyDescriptorPool", reinterpret_cast<PFN_vkVoidFunction>(DestroyDescriptorPool) },
{ "vkDestroyDescriptorSetLayout", reinterpret_cast<PFN_vkVoidFunction>(DestroyDescriptorSetLayout) },
+ { "vkDestroyDescriptorUpdateTemplate", reinterpret_cast<PFN_vkVoidFunction>(DestroyDescriptorUpdateTemplate) },
{ "vkDestroyDevice", reinterpret_cast<PFN_vkVoidFunction>(DestroyDevice) },
{ "vkDestroyEvent", reinterpret_cast<PFN_vkVoidFunction>(DestroyEvent) },
{ "vkDestroyFence", reinterpret_cast<PFN_vkVoidFunction>(DestroyFence) },
@@ -606,6 +711,7 @@
{ "vkDestroyQueryPool", reinterpret_cast<PFN_vkVoidFunction>(DestroyQueryPool) },
{ "vkDestroyRenderPass", reinterpret_cast<PFN_vkVoidFunction>(DestroyRenderPass) },
{ "vkDestroySampler", reinterpret_cast<PFN_vkVoidFunction>(DestroySampler) },
+ { "vkDestroySamplerYcbcrConversion", reinterpret_cast<PFN_vkVoidFunction>(DestroySamplerYcbcrConversion) },
{ "vkDestroySemaphore", reinterpret_cast<PFN_vkVoidFunction>(DestroySemaphore) },
{ "vkDestroyShaderModule", reinterpret_cast<PFN_vkVoidFunction>(DestroyShaderModule) },
{ "vkDestroySwapchainKHR", reinterpret_cast<PFN_vkVoidFunction>(DestroySwapchainKHR) },
@@ -615,18 +721,27 @@
{ "vkEnumerateDeviceLayerProperties", reinterpret_cast<PFN_vkVoidFunction>(EnumerateDeviceLayerProperties) },
{ "vkEnumerateInstanceExtensionProperties", nullptr },
{ "vkEnumerateInstanceLayerProperties", nullptr },
+ { "vkEnumerateInstanceVersion", nullptr },
{ "vkFlushMappedMemoryRanges", reinterpret_cast<PFN_vkVoidFunction>(FlushMappedMemoryRanges) },
{ "vkFreeCommandBuffers", reinterpret_cast<PFN_vkVoidFunction>(FreeCommandBuffers) },
{ "vkFreeDescriptorSets", reinterpret_cast<PFN_vkVoidFunction>(FreeDescriptorSets) },
{ "vkFreeMemory", reinterpret_cast<PFN_vkVoidFunction>(FreeMemory) },
{ "vkGetBufferMemoryRequirements", reinterpret_cast<PFN_vkVoidFunction>(GetBufferMemoryRequirements) },
+ { "vkGetBufferMemoryRequirements2", reinterpret_cast<PFN_vkVoidFunction>(GetBufferMemoryRequirements2) },
+ { "vkGetDescriptorSetLayoutSupport", reinterpret_cast<PFN_vkVoidFunction>(GetDescriptorSetLayoutSupport) },
+ { "vkGetDeviceGroupPeerMemoryFeatures", reinterpret_cast<PFN_vkVoidFunction>(GetDeviceGroupPeerMemoryFeatures) },
+ { "vkGetDeviceGroupPresentCapabilitiesKHR", reinterpret_cast<PFN_vkVoidFunction>(GetDeviceGroupPresentCapabilitiesKHR) },
+ { "vkGetDeviceGroupSurfacePresentModesKHR", reinterpret_cast<PFN_vkVoidFunction>(GetDeviceGroupSurfacePresentModesKHR) },
{ "vkGetDeviceMemoryCommitment", reinterpret_cast<PFN_vkVoidFunction>(GetDeviceMemoryCommitment) },
{ "vkGetDeviceProcAddr", reinterpret_cast<PFN_vkVoidFunction>(GetDeviceProcAddr) },
{ "vkGetDeviceQueue", reinterpret_cast<PFN_vkVoidFunction>(GetDeviceQueue) },
+ { "vkGetDeviceQueue2", reinterpret_cast<PFN_vkVoidFunction>(GetDeviceQueue2) },
{ "vkGetEventStatus", reinterpret_cast<PFN_vkVoidFunction>(GetEventStatus) },
{ "vkGetFenceStatus", reinterpret_cast<PFN_vkVoidFunction>(GetFenceStatus) },
{ "vkGetImageMemoryRequirements", reinterpret_cast<PFN_vkVoidFunction>(GetImageMemoryRequirements) },
+ { "vkGetImageMemoryRequirements2", reinterpret_cast<PFN_vkVoidFunction>(GetImageMemoryRequirements2) },
{ "vkGetImageSparseMemoryRequirements", reinterpret_cast<PFN_vkVoidFunction>(GetImageSparseMemoryRequirements) },
+ { "vkGetImageSparseMemoryRequirements2", reinterpret_cast<PFN_vkVoidFunction>(GetImageSparseMemoryRequirements2) },
{ "vkGetImageSubresourceLayout", reinterpret_cast<PFN_vkVoidFunction>(GetImageSubresourceLayout) },
{ "vkGetInstanceProcAddr", reinterpret_cast<PFN_vkVoidFunction>(GetInstanceProcAddr) },
{ "vkGetPipelineCacheData", reinterpret_cast<PFN_vkVoidFunction>(GetPipelineCacheData) },
@@ -646,7 +761,9 @@
{ "vkResetEvent", reinterpret_cast<PFN_vkVoidFunction>(ResetEvent) },
{ "vkResetFences", reinterpret_cast<PFN_vkVoidFunction>(ResetFences) },
{ "vkSetEvent", reinterpret_cast<PFN_vkVoidFunction>(SetEvent) },
+ { "vkTrimCommandPool", reinterpret_cast<PFN_vkVoidFunction>(TrimCommandPool) },
{ "vkUnmapMemory", reinterpret_cast<PFN_vkVoidFunction>(UnmapMemory) },
+ { "vkUpdateDescriptorSetWithTemplate", reinterpret_cast<PFN_vkVoidFunction>(UpdateDescriptorSetWithTemplate) },
{ "vkUpdateDescriptorSets", reinterpret_cast<PFN_vkVoidFunction>(UpdateDescriptorSets) },
{ "vkWaitForFences", reinterpret_cast<PFN_vkVoidFunction>(WaitForFences) },
};
@@ -1172,6 +1289,114 @@
GetData(commandBuffer).dispatch.CmdExecuteCommands(commandBuffer, commandBufferCount, pCommandBuffers);
}
+VKAPI_ATTR VkResult BindBufferMemory2(VkDevice device, uint32_t bindInfoCount, const VkBindBufferMemoryInfo* pBindInfos) {
+ return GetData(device).dispatch.BindBufferMemory2(device, bindInfoCount, pBindInfos);
+}
+
+VKAPI_ATTR VkResult BindImageMemory2(VkDevice device, uint32_t bindInfoCount, const VkBindImageMemoryInfo* pBindInfos) {
+ return GetData(device).dispatch.BindImageMemory2(device, bindInfoCount, pBindInfos);
+}
+
+VKAPI_ATTR void GetDeviceGroupPeerMemoryFeatures(VkDevice device, uint32_t heapIndex, uint32_t localDeviceIndex, uint32_t remoteDeviceIndex, VkPeerMemoryFeatureFlags* pPeerMemoryFeatures) {
+ GetData(device).dispatch.GetDeviceGroupPeerMemoryFeatures(device, heapIndex, localDeviceIndex, remoteDeviceIndex, pPeerMemoryFeatures);
+}
+
+VKAPI_ATTR void CmdSetDeviceMask(VkCommandBuffer commandBuffer, uint32_t deviceMask) {
+ GetData(commandBuffer).dispatch.CmdSetDeviceMask(commandBuffer, deviceMask);
+}
+
+VKAPI_ATTR void CmdDispatchBase(VkCommandBuffer commandBuffer, uint32_t baseGroupX, uint32_t baseGroupY, uint32_t baseGroupZ, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ) {
+ GetData(commandBuffer).dispatch.CmdDispatchBase(commandBuffer, baseGroupX, baseGroupY, baseGroupZ, groupCountX, groupCountY, groupCountZ);
+}
+
+VKAPI_ATTR VkResult EnumeratePhysicalDeviceGroups(VkInstance instance, uint32_t* pPhysicalDeviceGroupCount, VkPhysicalDeviceGroupProperties* pPhysicalDeviceGroupProperties) {
+ return GetData(instance).dispatch.EnumeratePhysicalDeviceGroups(instance, pPhysicalDeviceGroupCount, pPhysicalDeviceGroupProperties);
+}
+
+VKAPI_ATTR void GetImageMemoryRequirements2(VkDevice device, const VkImageMemoryRequirementsInfo2* pInfo, VkMemoryRequirements2* pMemoryRequirements) {
+ GetData(device).dispatch.GetImageMemoryRequirements2(device, pInfo, pMemoryRequirements);
+}
+
+VKAPI_ATTR void GetBufferMemoryRequirements2(VkDevice device, const VkBufferMemoryRequirementsInfo2* pInfo, VkMemoryRequirements2* pMemoryRequirements) {
+ GetData(device).dispatch.GetBufferMemoryRequirements2(device, pInfo, pMemoryRequirements);
+}
+
+VKAPI_ATTR void GetImageSparseMemoryRequirements2(VkDevice device, const VkImageSparseMemoryRequirementsInfo2* pInfo, uint32_t* pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements2* pSparseMemoryRequirements) {
+ GetData(device).dispatch.GetImageSparseMemoryRequirements2(device, pInfo, pSparseMemoryRequirementCount, pSparseMemoryRequirements);
+}
+
+VKAPI_ATTR void GetPhysicalDeviceFeatures2(VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures2* pFeatures) {
+ GetData(physicalDevice).dispatch.GetPhysicalDeviceFeatures2(physicalDevice, pFeatures);
+}
+
+VKAPI_ATTR void GetPhysicalDeviceProperties2(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties2* pProperties) {
+ GetData(physicalDevice).dispatch.GetPhysicalDeviceProperties2(physicalDevice, pProperties);
+}
+
+VKAPI_ATTR void GetPhysicalDeviceFormatProperties2(VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties2* pFormatProperties) {
+ GetData(physicalDevice).dispatch.GetPhysicalDeviceFormatProperties2(physicalDevice, format, pFormatProperties);
+}
+
+VKAPI_ATTR VkResult GetPhysicalDeviceImageFormatProperties2(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceImageFormatInfo2* pImageFormatInfo, VkImageFormatProperties2* pImageFormatProperties) {
+ return GetData(physicalDevice).dispatch.GetPhysicalDeviceImageFormatProperties2(physicalDevice, pImageFormatInfo, pImageFormatProperties);
+}
+
+VKAPI_ATTR void GetPhysicalDeviceQueueFamilyProperties2(VkPhysicalDevice physicalDevice, uint32_t* pQueueFamilyPropertyCount, VkQueueFamilyProperties2* pQueueFamilyProperties) {
+ GetData(physicalDevice).dispatch.GetPhysicalDeviceQueueFamilyProperties2(physicalDevice, pQueueFamilyPropertyCount, pQueueFamilyProperties);
+}
+
+VKAPI_ATTR void GetPhysicalDeviceMemoryProperties2(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties2* pMemoryProperties) {
+ GetData(physicalDevice).dispatch.GetPhysicalDeviceMemoryProperties2(physicalDevice, pMemoryProperties);
+}
+
+VKAPI_ATTR void GetPhysicalDeviceSparseImageFormatProperties2(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSparseImageFormatInfo2* pFormatInfo, uint32_t* pPropertyCount, VkSparseImageFormatProperties2* pProperties) {
+ GetData(physicalDevice).dispatch.GetPhysicalDeviceSparseImageFormatProperties2(physicalDevice, pFormatInfo, pPropertyCount, pProperties);
+}
+
+VKAPI_ATTR void TrimCommandPool(VkDevice device, VkCommandPool commandPool, VkCommandPoolTrimFlags flags) {
+ GetData(device).dispatch.TrimCommandPool(device, commandPool, flags);
+}
+
+VKAPI_ATTR void GetDeviceQueue2(VkDevice device, const VkDeviceQueueInfo2* pQueueInfo, VkQueue* pQueue) {
+ GetData(device).dispatch.GetDeviceQueue2(device, pQueueInfo, pQueue);
+}
+
+VKAPI_ATTR VkResult CreateSamplerYcbcrConversion(VkDevice device, const VkSamplerYcbcrConversionCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSamplerYcbcrConversion* pYcbcrConversion) {
+ return GetData(device).dispatch.CreateSamplerYcbcrConversion(device, pCreateInfo, pAllocator, pYcbcrConversion);
+}
+
+VKAPI_ATTR void DestroySamplerYcbcrConversion(VkDevice device, VkSamplerYcbcrConversion ycbcrConversion, const VkAllocationCallbacks* pAllocator) {
+ GetData(device).dispatch.DestroySamplerYcbcrConversion(device, ycbcrConversion, pAllocator);
+}
+
+VKAPI_ATTR VkResult CreateDescriptorUpdateTemplate(VkDevice device, const VkDescriptorUpdateTemplateCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDescriptorUpdateTemplate* pDescriptorUpdateTemplate) {
+ return GetData(device).dispatch.CreateDescriptorUpdateTemplate(device, pCreateInfo, pAllocator, pDescriptorUpdateTemplate);
+}
+
+VKAPI_ATTR void DestroyDescriptorUpdateTemplate(VkDevice device, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const VkAllocationCallbacks* pAllocator) {
+ GetData(device).dispatch.DestroyDescriptorUpdateTemplate(device, descriptorUpdateTemplate, pAllocator);
+}
+
+VKAPI_ATTR void UpdateDescriptorSetWithTemplate(VkDevice device, VkDescriptorSet descriptorSet, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const void* pData) {
+ GetData(device).dispatch.UpdateDescriptorSetWithTemplate(device, descriptorSet, descriptorUpdateTemplate, pData);
+}
+
+VKAPI_ATTR void GetPhysicalDeviceExternalBufferProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalBufferInfo* pExternalBufferInfo, VkExternalBufferProperties* pExternalBufferProperties) {
+ GetData(physicalDevice).dispatch.GetPhysicalDeviceExternalBufferProperties(physicalDevice, pExternalBufferInfo, pExternalBufferProperties);
+}
+
+VKAPI_ATTR void GetPhysicalDeviceExternalFenceProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalFenceInfo* pExternalFenceInfo, VkExternalFenceProperties* pExternalFenceProperties) {
+ GetData(physicalDevice).dispatch.GetPhysicalDeviceExternalFenceProperties(physicalDevice, pExternalFenceInfo, pExternalFenceProperties);
+}
+
+VKAPI_ATTR void GetPhysicalDeviceExternalSemaphoreProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalSemaphoreInfo* pExternalSemaphoreInfo, VkExternalSemaphoreProperties* pExternalSemaphoreProperties) {
+ GetData(physicalDevice).dispatch.GetPhysicalDeviceExternalSemaphoreProperties(physicalDevice, pExternalSemaphoreInfo, pExternalSemaphoreProperties);
+}
+
+VKAPI_ATTR void GetDescriptorSetLayoutSupport(VkDevice device, const VkDescriptorSetLayoutCreateInfo* pCreateInfo, VkDescriptorSetLayoutSupport* pSupport) {
+ GetData(device).dispatch.GetDescriptorSetLayoutSupport(device, pCreateInfo, pSupport);
+}
+
VKAPI_ATTR void DestroySurfaceKHR(VkInstance instance, VkSurfaceKHR surface, const VkAllocationCallbacks* pAllocator) {
GetData(instance).dispatch.DestroySurfaceKHR(instance, surface, pAllocator);
}
@@ -1212,6 +1437,22 @@
return GetData(queue).dispatch.QueuePresentKHR(queue, pPresentInfo);
}
+VKAPI_ATTR VkResult GetDeviceGroupPresentCapabilitiesKHR(VkDevice device, VkDeviceGroupPresentCapabilitiesKHR* pDeviceGroupPresentCapabilities) {
+ return GetData(device).dispatch.GetDeviceGroupPresentCapabilitiesKHR(device, pDeviceGroupPresentCapabilities);
+}
+
+VKAPI_ATTR VkResult GetDeviceGroupSurfacePresentModesKHR(VkDevice device, VkSurfaceKHR surface, VkDeviceGroupPresentModeFlagsKHR* pModes) {
+ return GetData(device).dispatch.GetDeviceGroupSurfacePresentModesKHR(device, surface, pModes);
+}
+
+VKAPI_ATTR VkResult GetPhysicalDevicePresentRectanglesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t* pRectCount, VkRect2D* pRects) {
+ return GetData(physicalDevice).dispatch.GetPhysicalDevicePresentRectanglesKHR(physicalDevice, surface, pRectCount, pRects);
+}
+
+VKAPI_ATTR VkResult AcquireNextImage2KHR(VkDevice device, const VkAcquireNextImageInfoKHR* pAcquireInfo, uint32_t* pImageIndex) {
+ return GetData(device).dispatch.AcquireNextImage2KHR(device, pAcquireInfo, pImageIndex);
+}
+
VKAPI_ATTR VkResult CreateAndroidSurfaceKHR(VkInstance instance, const VkAndroidSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface) {
return GetData(instance).dispatch.CreateAndroidSurfaceKHR(instance, pCreateInfo, pAllocator, pSurface);
}
@@ -1912,6 +2153,146 @@
}
__attribute__((visibility("default")))
+VKAPI_ATTR VkResult vkEnumerateInstanceVersion(uint32_t* pApiVersion) {
+ return vulkan::api::EnumerateInstanceVersion(pApiVersion);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR VkResult vkBindBufferMemory2(VkDevice device, uint32_t bindInfoCount, const VkBindBufferMemoryInfo* pBindInfos) {
+ return vulkan::api::BindBufferMemory2(device, bindInfoCount, pBindInfos);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR VkResult vkBindImageMemory2(VkDevice device, uint32_t bindInfoCount, const VkBindImageMemoryInfo* pBindInfos) {
+ return vulkan::api::BindImageMemory2(device, bindInfoCount, pBindInfos);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR void vkGetDeviceGroupPeerMemoryFeatures(VkDevice device, uint32_t heapIndex, uint32_t localDeviceIndex, uint32_t remoteDeviceIndex, VkPeerMemoryFeatureFlags* pPeerMemoryFeatures) {
+ vulkan::api::GetDeviceGroupPeerMemoryFeatures(device, heapIndex, localDeviceIndex, remoteDeviceIndex, pPeerMemoryFeatures);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR void vkCmdSetDeviceMask(VkCommandBuffer commandBuffer, uint32_t deviceMask) {
+ vulkan::api::CmdSetDeviceMask(commandBuffer, deviceMask);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR void vkCmdDispatchBase(VkCommandBuffer commandBuffer, uint32_t baseGroupX, uint32_t baseGroupY, uint32_t baseGroupZ, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ) {
+ vulkan::api::CmdDispatchBase(commandBuffer, baseGroupX, baseGroupY, baseGroupZ, groupCountX, groupCountY, groupCountZ);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR VkResult vkEnumeratePhysicalDeviceGroups(VkInstance instance, uint32_t* pPhysicalDeviceGroupCount, VkPhysicalDeviceGroupProperties* pPhysicalDeviceGroupProperties) {
+ return vulkan::api::EnumeratePhysicalDeviceGroups(instance, pPhysicalDeviceGroupCount, pPhysicalDeviceGroupProperties);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR void vkGetImageMemoryRequirements2(VkDevice device, const VkImageMemoryRequirementsInfo2* pInfo, VkMemoryRequirements2* pMemoryRequirements) {
+ vulkan::api::GetImageMemoryRequirements2(device, pInfo, pMemoryRequirements);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR void vkGetBufferMemoryRequirements2(VkDevice device, const VkBufferMemoryRequirementsInfo2* pInfo, VkMemoryRequirements2* pMemoryRequirements) {
+ vulkan::api::GetBufferMemoryRequirements2(device, pInfo, pMemoryRequirements);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR void vkGetImageSparseMemoryRequirements2(VkDevice device, const VkImageSparseMemoryRequirementsInfo2* pInfo, uint32_t* pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements2* pSparseMemoryRequirements) {
+ vulkan::api::GetImageSparseMemoryRequirements2(device, pInfo, pSparseMemoryRequirementCount, pSparseMemoryRequirements);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR void vkGetPhysicalDeviceFeatures2(VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures2* pFeatures) {
+ vulkan::api::GetPhysicalDeviceFeatures2(physicalDevice, pFeatures);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR void vkGetPhysicalDeviceProperties2(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties2* pProperties) {
+ vulkan::api::GetPhysicalDeviceProperties2(physicalDevice, pProperties);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR void vkGetPhysicalDeviceFormatProperties2(VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties2* pFormatProperties) {
+ vulkan::api::GetPhysicalDeviceFormatProperties2(physicalDevice, format, pFormatProperties);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR VkResult vkGetPhysicalDeviceImageFormatProperties2(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceImageFormatInfo2* pImageFormatInfo, VkImageFormatProperties2* pImageFormatProperties) {
+ return vulkan::api::GetPhysicalDeviceImageFormatProperties2(physicalDevice, pImageFormatInfo, pImageFormatProperties);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR void vkGetPhysicalDeviceQueueFamilyProperties2(VkPhysicalDevice physicalDevice, uint32_t* pQueueFamilyPropertyCount, VkQueueFamilyProperties2* pQueueFamilyProperties) {
+ vulkan::api::GetPhysicalDeviceQueueFamilyProperties2(physicalDevice, pQueueFamilyPropertyCount, pQueueFamilyProperties);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR void vkGetPhysicalDeviceMemoryProperties2(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties2* pMemoryProperties) {
+ vulkan::api::GetPhysicalDeviceMemoryProperties2(physicalDevice, pMemoryProperties);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR void vkGetPhysicalDeviceSparseImageFormatProperties2(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSparseImageFormatInfo2* pFormatInfo, uint32_t* pPropertyCount, VkSparseImageFormatProperties2* pProperties) {
+ vulkan::api::GetPhysicalDeviceSparseImageFormatProperties2(physicalDevice, pFormatInfo, pPropertyCount, pProperties);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR void vkTrimCommandPool(VkDevice device, VkCommandPool commandPool, VkCommandPoolTrimFlags flags) {
+ vulkan::api::TrimCommandPool(device, commandPool, flags);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR void vkGetDeviceQueue2(VkDevice device, const VkDeviceQueueInfo2* pQueueInfo, VkQueue* pQueue) {
+ vulkan::api::GetDeviceQueue2(device, pQueueInfo, pQueue);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR VkResult vkCreateSamplerYcbcrConversion(VkDevice device, const VkSamplerYcbcrConversionCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSamplerYcbcrConversion* pYcbcrConversion) {
+ return vulkan::api::CreateSamplerYcbcrConversion(device, pCreateInfo, pAllocator, pYcbcrConversion);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR void vkDestroySamplerYcbcrConversion(VkDevice device, VkSamplerYcbcrConversion ycbcrConversion, const VkAllocationCallbacks* pAllocator) {
+ vulkan::api::DestroySamplerYcbcrConversion(device, ycbcrConversion, pAllocator);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR VkResult vkCreateDescriptorUpdateTemplate(VkDevice device, const VkDescriptorUpdateTemplateCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDescriptorUpdateTemplate* pDescriptorUpdateTemplate) {
+ return vulkan::api::CreateDescriptorUpdateTemplate(device, pCreateInfo, pAllocator, pDescriptorUpdateTemplate);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR void vkDestroyDescriptorUpdateTemplate(VkDevice device, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const VkAllocationCallbacks* pAllocator) {
+ vulkan::api::DestroyDescriptorUpdateTemplate(device, descriptorUpdateTemplate, pAllocator);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR void vkUpdateDescriptorSetWithTemplate(VkDevice device, VkDescriptorSet descriptorSet, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const void* pData) {
+ vulkan::api::UpdateDescriptorSetWithTemplate(device, descriptorSet, descriptorUpdateTemplate, pData);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR void vkGetPhysicalDeviceExternalBufferProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalBufferInfo* pExternalBufferInfo, VkExternalBufferProperties* pExternalBufferProperties) {
+ vulkan::api::GetPhysicalDeviceExternalBufferProperties(physicalDevice, pExternalBufferInfo, pExternalBufferProperties);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR void vkGetPhysicalDeviceExternalFenceProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalFenceInfo* pExternalFenceInfo, VkExternalFenceProperties* pExternalFenceProperties) {
+ vulkan::api::GetPhysicalDeviceExternalFenceProperties(physicalDevice, pExternalFenceInfo, pExternalFenceProperties);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR void vkGetPhysicalDeviceExternalSemaphoreProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalSemaphoreInfo* pExternalSemaphoreInfo, VkExternalSemaphoreProperties* pExternalSemaphoreProperties) {
+ vulkan::api::GetPhysicalDeviceExternalSemaphoreProperties(physicalDevice, pExternalSemaphoreInfo, pExternalSemaphoreProperties);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR void vkGetDescriptorSetLayoutSupport(VkDevice device, const VkDescriptorSetLayoutCreateInfo* pCreateInfo, VkDescriptorSetLayoutSupport* pSupport) {
+ vulkan::api::GetDescriptorSetLayoutSupport(device, pCreateInfo, pSupport);
+}
+
+__attribute__((visibility("default")))
VKAPI_ATTR void vkDestroySurfaceKHR(VkInstance instance, VkSurfaceKHR surface, const VkAllocationCallbacks* pAllocator) {
vulkan::api::DestroySurfaceKHR(instance, surface, pAllocator);
}
@@ -1962,6 +2343,26 @@
}
__attribute__((visibility("default")))
+VKAPI_ATTR VkResult vkGetDeviceGroupPresentCapabilitiesKHR(VkDevice device, VkDeviceGroupPresentCapabilitiesKHR* pDeviceGroupPresentCapabilities) {
+ return vulkan::api::GetDeviceGroupPresentCapabilitiesKHR(device, pDeviceGroupPresentCapabilities);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR VkResult vkGetDeviceGroupSurfacePresentModesKHR(VkDevice device, VkSurfaceKHR surface, VkDeviceGroupPresentModeFlagsKHR* pModes) {
+ return vulkan::api::GetDeviceGroupSurfacePresentModesKHR(device, surface, pModes);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR VkResult vkGetPhysicalDevicePresentRectanglesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t* pRectCount, VkRect2D* pRects) {
+ return vulkan::api::GetPhysicalDevicePresentRectanglesKHR(physicalDevice, surface, pRectCount, pRects);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR VkResult vkAcquireNextImage2KHR(VkDevice device, const VkAcquireNextImageInfoKHR* pAcquireInfo, uint32_t* pImageIndex) {
+ return vulkan::api::AcquireNextImage2KHR(device, pAcquireInfo, pImageIndex);
+}
+
+__attribute__((visibility("default")))
VKAPI_ATTR VkResult vkCreateAndroidSurfaceKHR(VkInstance instance, const VkAndroidSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface) {
return vulkan::api::CreateAndroidSurfaceKHR(instance, pCreateInfo, pAllocator, pSurface);
}
diff --git a/vulkan/libvulkan/api_gen.h b/vulkan/libvulkan/api_gen.h
index 3e50fda..939dc73 100644
--- a/vulkan/libvulkan/api_gen.h
+++ b/vulkan/libvulkan/api_gen.h
@@ -40,11 +40,23 @@
PFN_vkCreateDevice CreateDevice;
PFN_vkEnumerateDeviceExtensionProperties EnumerateDeviceExtensionProperties;
PFN_vkGetPhysicalDeviceSparseImageFormatProperties GetPhysicalDeviceSparseImageFormatProperties;
+ PFN_vkEnumeratePhysicalDeviceGroups EnumeratePhysicalDeviceGroups;
+ PFN_vkGetPhysicalDeviceFeatures2 GetPhysicalDeviceFeatures2;
+ PFN_vkGetPhysicalDeviceProperties2 GetPhysicalDeviceProperties2;
+ PFN_vkGetPhysicalDeviceFormatProperties2 GetPhysicalDeviceFormatProperties2;
+ PFN_vkGetPhysicalDeviceImageFormatProperties2 GetPhysicalDeviceImageFormatProperties2;
+ PFN_vkGetPhysicalDeviceQueueFamilyProperties2 GetPhysicalDeviceQueueFamilyProperties2;
+ PFN_vkGetPhysicalDeviceMemoryProperties2 GetPhysicalDeviceMemoryProperties2;
+ PFN_vkGetPhysicalDeviceSparseImageFormatProperties2 GetPhysicalDeviceSparseImageFormatProperties2;
+ PFN_vkGetPhysicalDeviceExternalBufferProperties GetPhysicalDeviceExternalBufferProperties;
+ PFN_vkGetPhysicalDeviceExternalFenceProperties GetPhysicalDeviceExternalFenceProperties;
+ PFN_vkGetPhysicalDeviceExternalSemaphoreProperties GetPhysicalDeviceExternalSemaphoreProperties;
PFN_vkDestroySurfaceKHR DestroySurfaceKHR;
PFN_vkGetPhysicalDeviceSurfaceSupportKHR GetPhysicalDeviceSurfaceSupportKHR;
PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR GetPhysicalDeviceSurfaceCapabilitiesKHR;
PFN_vkGetPhysicalDeviceSurfaceFormatsKHR GetPhysicalDeviceSurfaceFormatsKHR;
PFN_vkGetPhysicalDeviceSurfacePresentModesKHR GetPhysicalDeviceSurfacePresentModesKHR;
+ PFN_vkGetPhysicalDevicePresentRectanglesKHR GetPhysicalDevicePresentRectanglesKHR;
PFN_vkCreateAndroidSurfaceKHR CreateAndroidSurfaceKHR;
// clang-format on
};
@@ -172,11 +184,30 @@
PFN_vkCmdNextSubpass CmdNextSubpass;
PFN_vkCmdEndRenderPass CmdEndRenderPass;
PFN_vkCmdExecuteCommands CmdExecuteCommands;
+ PFN_vkBindBufferMemory2 BindBufferMemory2;
+ PFN_vkBindImageMemory2 BindImageMemory2;
+ PFN_vkGetDeviceGroupPeerMemoryFeatures GetDeviceGroupPeerMemoryFeatures;
+ PFN_vkCmdSetDeviceMask CmdSetDeviceMask;
+ PFN_vkCmdDispatchBase CmdDispatchBase;
+ PFN_vkGetImageMemoryRequirements2 GetImageMemoryRequirements2;
+ PFN_vkGetBufferMemoryRequirements2 GetBufferMemoryRequirements2;
+ PFN_vkGetImageSparseMemoryRequirements2 GetImageSparseMemoryRequirements2;
+ PFN_vkTrimCommandPool TrimCommandPool;
+ PFN_vkGetDeviceQueue2 GetDeviceQueue2;
+ PFN_vkCreateSamplerYcbcrConversion CreateSamplerYcbcrConversion;
+ PFN_vkDestroySamplerYcbcrConversion DestroySamplerYcbcrConversion;
+ PFN_vkCreateDescriptorUpdateTemplate CreateDescriptorUpdateTemplate;
+ PFN_vkDestroyDescriptorUpdateTemplate DestroyDescriptorUpdateTemplate;
+ PFN_vkUpdateDescriptorSetWithTemplate UpdateDescriptorSetWithTemplate;
+ PFN_vkGetDescriptorSetLayoutSupport GetDescriptorSetLayoutSupport;
PFN_vkCreateSwapchainKHR CreateSwapchainKHR;
PFN_vkDestroySwapchainKHR DestroySwapchainKHR;
PFN_vkGetSwapchainImagesKHR GetSwapchainImagesKHR;
PFN_vkAcquireNextImageKHR AcquireNextImageKHR;
PFN_vkQueuePresentKHR QueuePresentKHR;
+ PFN_vkGetDeviceGroupPresentCapabilitiesKHR GetDeviceGroupPresentCapabilitiesKHR;
+ PFN_vkGetDeviceGroupSurfacePresentModesKHR GetDeviceGroupSurfacePresentModesKHR;
+ PFN_vkAcquireNextImage2KHR AcquireNextImage2KHR;
// clang-format on
};
diff --git a/vulkan/libvulkan/code-generator.tmpl b/vulkan/libvulkan/code-generator.tmpl
index 5bbe116..3b48e08 100644
--- a/vulkan/libvulkan/code-generator.tmpl
+++ b/vulkan/libvulkan/code-generator.tmpl
@@ -419,7 +419,7 @@
INIT_PROC(§
{{end}}
- {{if GetAnnotation $ "optional"}}false{{else}}true{{end}}, §
+ {{if GetAnnotation $ "optional"}}false{{else if GetAnnotation $ "vulkan1_1"}}false{{else}}true{{end}}, §
{{if (Macro "IsInstanceDispatched" $)}}
instance, §
@@ -733,7 +733,9 @@
{{ if eq $.Name "vkCreateInstance"}}true
{{else if eq $.Name "vkCreateDevice"}}true
{{else if eq $.Name "vkEnumeratePhysicalDevices"}}true
+ {{else if eq $.Name "vkEnumeratePhysicalDeviceGroups"}}true
{{else if eq $.Name "vkGetDeviceQueue"}}true
+ {{else if eq $.Name "vkGetDeviceQueue2"}}true
{{else if eq $.Name "vkAllocateCommandBuffers"}}true
{{/* Destroy functions of dispatchable objects */}}
@@ -958,6 +960,7 @@
{{/* Create functions of dispatchable objects */}}
{{ if eq $.Name "vkCreateDevice"}}true
{{else if eq $.Name "vkGetDeviceQueue"}}true
+ {{else if eq $.Name "vkGetDeviceQueue2"}}true
{{else if eq $.Name "vkAllocateCommandBuffers"}}true
{{/* Destroy functions of dispatchable objects */}}
@@ -969,6 +972,7 @@
{{/* We cache physical devices in loader.cpp */}}
{{else if eq $.Name "vkEnumeratePhysicalDevices"}}true
+ {{else if eq $.Name "vkEnumeratePhysicalDeviceGroups"}}true
{{else if eq $.Name "vkGetInstanceProcAddr"}}true
{{else if eq $.Name "vkGetDeviceProcAddr"}}true
@@ -1135,9 +1139,10 @@
{{else if eq $ext "VK_KHR_xlib_surface"}}true
{{else if eq $ext "VK_KHR_wayland_surface"}}true
{{else if eq $ext "VK_KHR_win32_surface"}}true
- {{else if eq $ext "VK_KHX_external_memory_win32"}}true
- {{else if eq $ext "VK_KHX_win32_keyed_mutex"}}true
- {{else if eq $ext "VK_KHX_external_semaphore_win32"}}true
+ {{else if eq $ext "VK_KHR_external_memory_win32"}}true
+ {{else if eq $ext "VK_KHR_win32_keyed_mutex"}}true
+ {{else if eq $ext "VK_KHR_external_semaphore_win32"}}true
+ {{else if eq $ext "VK_KHR_external_fence_win32"}}true
{{else if eq $ext "VK_EXT_acquire_xlib_display"}}true
{{else if eq $ext "VK_EXT_direct_mode_display"}}true
{{else if eq $ext "VK_EXT_display_surface_counter"}}true
diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp
index 7b985d1..ade0bde 100644
--- a/vulkan/libvulkan/driver.cpp
+++ b/vulkan/libvulkan/driver.cpp
@@ -31,6 +31,8 @@
#include <graphicsenv/GraphicsEnv.h>
#include <utils/Vector.h>
+#include "android-base/properties.h"
+
#include "driver.h"
#include "stubhal.h"
@@ -822,9 +824,9 @@
// conditionally add VK_GOOGLE_display_timing if present timestamps are
// supported by the driver:
- char timestamp_property[PROPERTY_VALUE_MAX];
- property_get("service.sf.present_timestamp", timestamp_property, "1");
- if (strcmp(timestamp_property, "1") == 0) {
+ const std::string timestamp_property("service.sf.present_timestamp");
+ android::base::WaitForPropertyCreation(timestamp_property);
+ if (android::base::GetBoolProperty(timestamp_property, true)) {
loader_extensions.push_back({
VK_GOOGLE_DISPLAY_TIMING_EXTENSION_NAME,
VK_GOOGLE_DISPLAY_TIMING_SPEC_VERSION});
@@ -878,19 +880,6 @@
const VkAllocationCallbacks& data_allocator =
(pAllocator) ? *pAllocator : GetDefaultAllocator();
- if (pCreateInfo->pApplicationInfo &&
- pCreateInfo->pApplicationInfo->apiVersion >= VK_MAKE_VERSION(1, 1, 0)) {
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wold-style-cast"
- ALOGI(
- "Requested Vulkan instance version %d.%d is greater than max "
- "supported version (1.0)",
- VK_VERSION_MAJOR(pCreateInfo->pApplicationInfo->apiVersion),
- VK_VERSION_MINOR(pCreateInfo->pApplicationInfo->apiVersion));
-#pragma clang diagnostic pop
- return VK_ERROR_INCOMPATIBLE_DRIVER;
- }
-
CreateInfoWrapper wrapper(*pCreateInfo, data_allocator);
VkResult result = wrapper.Validate();
if (result != VK_SUCCESS)
@@ -1054,6 +1043,28 @@
return result;
}
+VkResult EnumeratePhysicalDeviceGroups(
+ VkInstance instance,
+ uint32_t* pPhysicalDeviceGroupCount,
+ VkPhysicalDeviceGroupProperties* pPhysicalDeviceGroupProperties) {
+ const auto& data = GetData(instance);
+
+ VkResult result = data.driver.EnumeratePhysicalDeviceGroups(
+ instance, pPhysicalDeviceGroupCount, pPhysicalDeviceGroupProperties);
+ if ((result == VK_SUCCESS || result == VK_INCOMPLETE) &&
+ *pPhysicalDeviceGroupCount && pPhysicalDeviceGroupProperties) {
+ for (uint32_t i = 0; i < *pPhysicalDeviceGroupCount; i++) {
+ for (uint32_t j = 0;
+ j < pPhysicalDeviceGroupProperties->physicalDeviceCount; j++) {
+ SetData(pPhysicalDeviceGroupProperties->physicalDevices[j],
+ data);
+ }
+ }
+ }
+
+ return result;
+}
+
void GetDeviceQueue(VkDevice device,
uint32_t queueFamilyIndex,
uint32_t queueIndex,
@@ -1064,6 +1075,15 @@
SetData(*pQueue, data);
}
+void GetDeviceQueue2(VkDevice device,
+ const VkDeviceQueueInfo2* pQueueInfo,
+ VkQueue* pQueue) {
+ const auto& data = GetData(device);
+
+ data.driver.GetDeviceQueue2(device, pQueueInfo, pQueue);
+ SetData(*pQueue, data);
+}
+
VKAPI_ATTR VkResult
AllocateCommandBuffers(VkDevice device,
const VkCommandBufferAllocateInfo* pAllocateInfo,
diff --git a/vulkan/libvulkan/driver.h b/vulkan/libvulkan/driver.h
index 7f8ae98..57c956d 100644
--- a/vulkan/libvulkan/driver.h
+++ b/vulkan/libvulkan/driver.h
@@ -126,7 +126,10 @@
VKAPI_ATTR void DestroyDevice(VkDevice device, const VkAllocationCallbacks* pAllocator);
VKAPI_ATTR VkResult EnumeratePhysicalDevices(VkInstance instance, uint32_t* pPhysicalDeviceCount, VkPhysicalDevice* pPhysicalDevices);
+VKAPI_ATTR VkResult EnumeratePhysicalDeviceGroups(VkInstance instance, uint32_t* pPhysicalDeviceGroupCount, VkPhysicalDeviceGroupProperties* pPhysicalDeviceGroupProperties);
+
VKAPI_ATTR void GetDeviceQueue(VkDevice device, uint32_t queueFamilyIndex, uint32_t queueIndex, VkQueue* pQueue);
+VKAPI_ATTR void GetDeviceQueue2(VkDevice device, const VkDeviceQueueInfo2* pQueueInfo, VkQueue* pQueue);
VKAPI_ATTR VkResult AllocateCommandBuffers(VkDevice device, const VkCommandBufferAllocateInfo* pAllocateInfo, VkCommandBuffer* pCommandBuffers);
// clang-format on
diff --git a/vulkan/libvulkan/driver_gen.cpp b/vulkan/libvulkan/driver_gen.cpp
index 82b464e..c6e8a7a 100644
--- a/vulkan/libvulkan/driver_gen.cpp
+++ b/vulkan/libvulkan/driver_gen.cpp
@@ -75,6 +75,33 @@
}
}
+VKAPI_ATTR VkResult checkedGetDeviceGroupPresentCapabilitiesKHR(VkDevice device, VkDeviceGroupPresentCapabilitiesKHR* pDeviceGroupPresentCapabilities) {
+ if (GetData(device).hook_extensions[ProcHook::KHR_swapchain]) {
+ return GetDeviceGroupPresentCapabilitiesKHR(device, pDeviceGroupPresentCapabilities);
+ } else {
+ Logger(device).Err(device, "VK_KHR_swapchain not enabled. vkGetDeviceGroupPresentCapabilitiesKHR not executed.");
+ return VK_SUCCESS;
+ }
+}
+
+VKAPI_ATTR VkResult checkedGetDeviceGroupSurfacePresentModesKHR(VkDevice device, VkSurfaceKHR surface, VkDeviceGroupPresentModeFlagsKHR* pModes) {
+ if (GetData(device).hook_extensions[ProcHook::KHR_swapchain]) {
+ return GetDeviceGroupSurfacePresentModesKHR(device, surface, pModes);
+ } else {
+ Logger(device).Err(device, "VK_KHR_swapchain not enabled. vkGetDeviceGroupSurfacePresentModesKHR not executed.");
+ return VK_SUCCESS;
+ }
+}
+
+VKAPI_ATTR VkResult checkedAcquireNextImage2KHR(VkDevice device, const VkAcquireNextImageInfoKHR* pAcquireInfo, uint32_t* pImageIndex) {
+ if (GetData(device).hook_extensions[ProcHook::KHR_swapchain]) {
+ return AcquireNextImage2KHR(device, pAcquireInfo, pImageIndex);
+ } else {
+ Logger(device).Err(device, "VK_KHR_swapchain not enabled. vkAcquireNextImage2KHR not executed.");
+ return VK_SUCCESS;
+ }
+}
+
VKAPI_ATTR VkResult checkedGetRefreshCycleDurationGOOGLE(VkDevice device, VkSwapchainKHR swapchain, VkRefreshCycleDurationGOOGLE* pDisplayTimingProperties) {
if (GetData(device).hook_extensions[ProcHook::GOOGLE_display_timing]) {
return GetRefreshCycleDurationGOOGLE(device, swapchain, pDisplayTimingProperties);
@@ -122,6 +149,13 @@
nullptr,
},
{
+ "vkAcquireNextImage2KHR",
+ ProcHook::DEVICE,
+ ProcHook::KHR_swapchain,
+ reinterpret_cast<PFN_vkVoidFunction>(AcquireNextImage2KHR),
+ reinterpret_cast<PFN_vkVoidFunction>(checkedAcquireNextImage2KHR),
+ },
+ {
"vkAcquireNextImageKHR",
ProcHook::DEVICE,
ProcHook::KHR_swapchain,
@@ -227,6 +261,13 @@
nullptr,
},
{
+ "vkEnumeratePhysicalDeviceGroups",
+ ProcHook::INSTANCE,
+ ProcHook::EXTENSION_CORE,
+ reinterpret_cast<PFN_vkVoidFunction>(EnumeratePhysicalDeviceGroups),
+ nullptr,
+ },
+ {
"vkEnumeratePhysicalDevices",
ProcHook::INSTANCE,
ProcHook::EXTENSION_CORE,
@@ -234,6 +275,20 @@
nullptr,
},
{
+ "vkGetDeviceGroupPresentCapabilitiesKHR",
+ ProcHook::DEVICE,
+ ProcHook::KHR_swapchain,
+ reinterpret_cast<PFN_vkVoidFunction>(GetDeviceGroupPresentCapabilitiesKHR),
+ reinterpret_cast<PFN_vkVoidFunction>(checkedGetDeviceGroupPresentCapabilitiesKHR),
+ },
+ {
+ "vkGetDeviceGroupSurfacePresentModesKHR",
+ ProcHook::DEVICE,
+ ProcHook::KHR_swapchain,
+ reinterpret_cast<PFN_vkVoidFunction>(GetDeviceGroupSurfacePresentModesKHR),
+ reinterpret_cast<PFN_vkVoidFunction>(checkedGetDeviceGroupSurfacePresentModesKHR),
+ },
+ {
"vkGetDeviceProcAddr",
ProcHook::DEVICE,
ProcHook::EXTENSION_CORE,
@@ -248,6 +303,13 @@
nullptr,
},
{
+ "vkGetDeviceQueue2",
+ ProcHook::DEVICE,
+ ProcHook::EXTENSION_CORE,
+ reinterpret_cast<PFN_vkVoidFunction>(GetDeviceQueue2),
+ nullptr,
+ },
+ {
"vkGetInstanceProcAddr",
ProcHook::INSTANCE,
ProcHook::EXTENSION_CORE,
@@ -262,6 +324,13 @@
reinterpret_cast<PFN_vkVoidFunction>(checkedGetPastPresentationTimingGOOGLE),
},
{
+ "vkGetPhysicalDevicePresentRectanglesKHR",
+ ProcHook::INSTANCE,
+ ProcHook::KHR_swapchain,
+ reinterpret_cast<PFN_vkVoidFunction>(GetPhysicalDevicePresentRectanglesKHR),
+ nullptr,
+ },
+ {
"vkGetPhysicalDeviceSurfaceCapabilities2KHR",
ProcHook::INSTANCE,
ProcHook::KHR_get_surface_capabilities2,
@@ -423,6 +492,7 @@
INIT_PROC(true, instance, GetPhysicalDeviceProperties);
INIT_PROC(true, instance, CreateDevice);
INIT_PROC(true, instance, EnumerateDeviceExtensionProperties);
+ INIT_PROC(false, instance, EnumeratePhysicalDeviceGroups);
INIT_PROC_EXT(EXT_debug_report, true, instance, CreateDebugReportCallbackEXT);
INIT_PROC_EXT(EXT_debug_report, true, instance, DestroyDebugReportCallbackEXT);
INIT_PROC_EXT(EXT_debug_report, true, instance, DebugReportMessageEXT);
@@ -445,6 +515,7 @@
INIT_PROC(true, dev, CreateImage);
INIT_PROC(true, dev, DestroyImage);
INIT_PROC(true, dev, AllocateCommandBuffers);
+ INIT_PROC(false, dev, GetDeviceQueue2);
INIT_PROC_EXT(ANDROID_native_buffer, false, dev, GetSwapchainGrallocUsageANDROID);
INIT_PROC_EXT(ANDROID_native_buffer, false, dev, GetSwapchainGrallocUsage2ANDROID);
INIT_PROC_EXT(ANDROID_native_buffer, true, dev, AcquireImageANDROID);
diff --git a/vulkan/libvulkan/driver_gen.h b/vulkan/libvulkan/driver_gen.h
index 3b26a80..646662f 100644
--- a/vulkan/libvulkan/driver_gen.h
+++ b/vulkan/libvulkan/driver_gen.h
@@ -67,6 +67,7 @@
PFN_vkGetPhysicalDeviceProperties GetPhysicalDeviceProperties;
PFN_vkCreateDevice CreateDevice;
PFN_vkEnumerateDeviceExtensionProperties EnumerateDeviceExtensionProperties;
+ PFN_vkEnumeratePhysicalDeviceGroups EnumeratePhysicalDeviceGroups;
PFN_vkCreateDebugReportCallbackEXT CreateDebugReportCallbackEXT;
PFN_vkDestroyDebugReportCallbackEXT DestroyDebugReportCallbackEXT;
PFN_vkDebugReportMessageEXT DebugReportMessageEXT;
@@ -82,6 +83,7 @@
PFN_vkCreateImage CreateImage;
PFN_vkDestroyImage DestroyImage;
PFN_vkAllocateCommandBuffers AllocateCommandBuffers;
+ PFN_vkGetDeviceQueue2 GetDeviceQueue2;
PFN_vkGetSwapchainGrallocUsageANDROID GetSwapchainGrallocUsageANDROID;
PFN_vkGetSwapchainGrallocUsage2ANDROID GetSwapchainGrallocUsage2ANDROID;
PFN_vkAcquireImageANDROID AcquireImageANDROID;
diff --git a/vulkan/libvulkan/stubhal.cpp b/vulkan/libvulkan/stubhal.cpp
index 2926268..726e854 100644
--- a/vulkan/libvulkan/stubhal.cpp
+++ b/vulkan/libvulkan/stubhal.cpp
@@ -97,7 +97,7 @@
return VK_SUCCESS;
}
-VKAPI_ATTR PFN_vkVoidFunction GetInstanceProcAddr(VkInstance /*instance*/,
+VKAPI_ATTR PFN_vkVoidFunction GetInstanceProcAddr(VkInstance instance,
const char* name) {
if (strcmp(name, "vkCreateInstance") == 0)
return reinterpret_cast<PFN_vkVoidFunction>(CreateInstance);
@@ -110,7 +110,9 @@
return reinterpret_cast<PFN_vkVoidFunction>(EnumeratePhysicalDevices);
if (strcmp(name, "vkGetInstanceProcAddr") == 0)
return reinterpret_cast<PFN_vkVoidFunction>(GetInstanceProcAddr);
-
+ // Per the spec, return NULL if instance is NULL.
+ if (!instance)
+ return nullptr;
// None of the other Vulkan functions should ever be called, as they all
// take a VkPhysicalDevice or other object obtained from a physical device.
return reinterpret_cast<PFN_vkVoidFunction>(NoOp);
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index cb893aa..03e6ee0 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -23,9 +23,12 @@
#include <utils/StrongPointer.h>
#include <utils/Vector.h>
#include <system/window.h>
+#include <android/hardware/graphics/common/1.0/types.h>
#include "driver.h"
+using android::hardware::graphics::common::V1_0::BufferUsage;
+
// TODO(jessehall): Currently we don't have a good error code for when a native
// window operation fails. Just returning INITIALIZATION_FAILED for now. Later
// versions (post SDK 0.9) of the API/extension have a better error code.
@@ -430,6 +433,8 @@
return HAL_DATASPACE_DISPLAY_P3;
case VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT:
return HAL_DATASPACE_V0_SCRGB_LINEAR;
+ case VK_COLOR_SPACE_EXTENDED_SRGB_NONLINEAR_EXT:
+ return HAL_DATASPACE_V0_SCRGB;
case VK_COLOR_SPACE_DCI_P3_LINEAR_EXT:
return HAL_DATASPACE_DCI_P3_LINEAR;
case VK_COLOR_SPACE_DCI_P3_NONLINEAR_EXT:
@@ -638,9 +643,9 @@
instance_data.hook_extensions.test(ProcHook::EXT_swapchain_colorspace);
const VkSurfaceFormatKHR kWideColorFormats[] = {
- {VK_FORMAT_R16G16B16A16_SFLOAT,
- VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT},
- {VK_FORMAT_A2R10G10B10_UNORM_PACK32,
+ {VK_FORMAT_R8G8B8A8_UNORM,
+ VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT},
+ {VK_FORMAT_R8G8B8A8_SRGB,
VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT},
};
const uint32_t kNumWideColorFormats =
@@ -769,6 +774,77 @@
}
VKAPI_ATTR
+VkResult GetDeviceGroupPresentCapabilitiesKHR(
+ VkDevice,
+ VkDeviceGroupPresentCapabilitiesKHR* pDeviceGroupPresentCapabilities) {
+ ALOGV_IF(pDeviceGroupPresentCapabilities->sType !=
+ VK_STRUCTURE_TYPE_DEVICE_GROUP_PRESENT_CAPABILITIES_KHR,
+ "vkGetDeviceGroupPresentCapabilitiesKHR: invalid "
+ "VkDeviceGroupPresentCapabilitiesKHR structure type %d",
+ pDeviceGroupPresentCapabilities->sType);
+
+ memset(pDeviceGroupPresentCapabilities->presentMask, 0,
+ sizeof(pDeviceGroupPresentCapabilities->presentMask));
+
+ // assume device group of size 1
+ pDeviceGroupPresentCapabilities->presentMask[0] = 1 << 0;
+ pDeviceGroupPresentCapabilities->modes =
+ VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_BIT_KHR;
+
+ return VK_SUCCESS;
+}
+
+VKAPI_ATTR
+VkResult GetDeviceGroupSurfacePresentModesKHR(
+ VkDevice,
+ VkSurfaceKHR,
+ VkDeviceGroupPresentModeFlagsKHR* pModes) {
+ *pModes = VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_BIT_KHR;
+ return VK_SUCCESS;
+}
+
+VKAPI_ATTR
+VkResult GetPhysicalDevicePresentRectanglesKHR(VkPhysicalDevice,
+ VkSurfaceKHR surface,
+ uint32_t* pRectCount,
+ VkRect2D* pRects) {
+ if (!pRects) {
+ *pRectCount = 1;
+ } else {
+ uint32_t count = std::min(*pRectCount, 1u);
+ bool incomplete = *pRectCount < 1;
+
+ *pRectCount = count;
+
+ if (incomplete) {
+ return VK_INCOMPLETE;
+ }
+
+ int err;
+ ANativeWindow* window = SurfaceFromHandle(surface)->window.get();
+
+ int width = 0, height = 0;
+ err = window->query(window, NATIVE_WINDOW_DEFAULT_WIDTH, &width);
+ if (err != 0) {
+ ALOGE("NATIVE_WINDOW_DEFAULT_WIDTH query failed: %s (%d)",
+ strerror(-err), err);
+ }
+ err = window->query(window, NATIVE_WINDOW_DEFAULT_HEIGHT, &height);
+ if (err != 0) {
+ ALOGE("NATIVE_WINDOW_DEFAULT_WIDTH query failed: %s (%d)",
+ strerror(-err), err);
+ }
+
+ // TODO: Return something better than "whole window"
+ pRects[0].offset.x = 0;
+ pRects[0].offset.y = 0;
+ pRects[0].extent = VkExtent2D{static_cast<uint32_t>(width),
+ static_cast<uint32_t>(height)};
+ }
+ return VK_SUCCESS;
+}
+
+VKAPI_ATTR
VkResult CreateSwapchainKHR(VkDevice device,
const VkSwapchainCreateInfoKHR* create_info,
const VkAllocationCallbacks* allocator,
@@ -994,7 +1070,7 @@
return VK_ERROR_SURFACE_LOST_KHR;
}
- int gralloc_usage = 0;
+ int32_t legacy_usage = 0;
if (dispatch.GetSwapchainGrallocUsage2ANDROID) {
uint64_t consumer_usage, producer_usage;
result = dispatch.GetSwapchainGrallocUsage2ANDROID(
@@ -1004,18 +1080,25 @@
ALOGE("vkGetSwapchainGrallocUsage2ANDROID failed: %d", result);
return VK_ERROR_SURFACE_LOST_KHR;
}
- gralloc_usage =
+ legacy_usage =
android_convertGralloc1To0Usage(producer_usage, consumer_usage);
} else if (dispatch.GetSwapchainGrallocUsageANDROID) {
result = dispatch.GetSwapchainGrallocUsageANDROID(
device, create_info->imageFormat, create_info->imageUsage,
- &gralloc_usage);
+ &legacy_usage);
if (result != VK_SUCCESS) {
ALOGE("vkGetSwapchainGrallocUsageANDROID failed: %d", result);
return VK_ERROR_SURFACE_LOST_KHR;
}
}
- err = native_window_set_usage(surface.window.get(), gralloc_usage);
+ uint64_t native_usage = static_cast<uint64_t>(legacy_usage);
+
+ bool createProtectedSwapchain = false;
+ if (create_info->flags & VK_SWAPCHAIN_CREATE_PROTECTED_BIT_KHR) {
+ createProtectedSwapchain = true;
+ native_usage |= BufferUsage::PROTECTED;
+ }
+ err = native_window_set_usage(surface.window.get(), native_usage);
if (err != 0) {
// TODO(jessehall): Improve error reporting. Can we enumerate possible
// errors and translate them to valid Vulkan result codes?
@@ -1063,7 +1146,7 @@
.samples = VK_SAMPLE_COUNT_1_BIT,
.tiling = VK_IMAGE_TILING_OPTIMAL,
.usage = create_info->imageUsage,
- .flags = 0,
+ .flags = createProtectedSwapchain ? VK_IMAGE_CREATE_PROTECTED_BIT : 0u,
.sharingMode = create_info->imageSharingMode,
.queueFamilyIndexCount = create_info->queueFamilyIndexCount,
.pQueueFamilyIndices = create_info->pQueueFamilyIndices,
@@ -1092,13 +1175,10 @@
image_native_buffer.handle = img.buffer->handle;
image_native_buffer.stride = img.buffer->stride;
image_native_buffer.format = img.buffer->format;
- image_native_buffer.usage = img.buffer->usage;
- // TODO: Adjust once ANativeWindowBuffer supports gralloc1-style usage.
- // For now, this is the same translation Gralloc1On0Adapter does.
- image_native_buffer.usage2.consumer =
- static_cast<uint64_t>(img.buffer->usage);
- image_native_buffer.usage2.producer =
- static_cast<uint64_t>(img.buffer->usage);
+ image_native_buffer.usage = int(img.buffer->usage);
+ android_convertGralloc0To1Usage(int(img.buffer->usage),
+ &image_native_buffer.usage2.producer,
+ &image_native_buffer.usage2.consumer);
result =
dispatch.CreateImage(device, &image_create, nullptr, &img.image);
@@ -1274,6 +1354,17 @@
return VK_SUCCESS;
}
+VKAPI_ATTR
+VkResult AcquireNextImage2KHR(VkDevice device,
+ const VkAcquireNextImageInfoKHR* pAcquireInfo,
+ uint32_t* pImageIndex) {
+ // TODO: this should actually be the other way around and this function
+ // should handle any additional structures that get passed in
+ return AcquireNextImageKHR(device, pAcquireInfo->swapchain,
+ pAcquireInfo->timeout, pAcquireInfo->semaphore,
+ pAcquireInfo->fence, pImageIndex);
+}
+
static VkResult WorstPresentResult(VkResult a, VkResult b) {
// See the error ranking for vkQueuePresentKHR at the end of section 29.6
// (in spec version 1.0.14).
diff --git a/vulkan/libvulkan/swapchain.h b/vulkan/libvulkan/swapchain.h
index e3cf624..ed5718c 100644
--- a/vulkan/libvulkan/swapchain.h
+++ b/vulkan/libvulkan/swapchain.h
@@ -29,11 +29,15 @@
VKAPI_ATTR VkResult GetPhysicalDeviceSurfaceCapabilitiesKHR(VkPhysicalDevice pdev, VkSurfaceKHR surface, VkSurfaceCapabilitiesKHR* capabilities);
VKAPI_ATTR VkResult GetPhysicalDeviceSurfaceFormatsKHR(VkPhysicalDevice pdev, VkSurfaceKHR surface_handle, uint32_t* count, VkSurfaceFormatKHR* formats);
VKAPI_ATTR VkResult GetPhysicalDeviceSurfacePresentModesKHR(VkPhysicalDevice pdev, VkSurfaceKHR surface, uint32_t* count, VkPresentModeKHR* modes);
+VKAPI_ATTR VkResult GetDeviceGroupPresentCapabilitiesKHR(VkDevice device, VkDeviceGroupPresentCapabilitiesKHR* pDeviceGroupPresentCapabilities);
+VKAPI_ATTR VkResult GetDeviceGroupSurfacePresentModesKHR(VkDevice device, VkSurfaceKHR surface, VkDeviceGroupPresentModeFlagsKHR* pModes);
+VKAPI_ATTR VkResult GetPhysicalDevicePresentRectanglesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t* pRectCount, VkRect2D* pRects);
VKAPI_ATTR VkResult CreateSwapchainKHR(VkDevice device, const VkSwapchainCreateInfoKHR* create_info, const VkAllocationCallbacks* allocator, VkSwapchainKHR* swapchain_handle);
VKAPI_ATTR void DestroySwapchainKHR(VkDevice device, VkSwapchainKHR swapchain_handle, const VkAllocationCallbacks* allocator);
VKAPI_ATTR VkResult GetSwapchainImagesKHR(VkDevice device, VkSwapchainKHR swapchain_handle, uint32_t* count, VkImage* images);
VKAPI_ATTR VkResult AcquireNextImageKHR(VkDevice device, VkSwapchainKHR swapchain_handle, uint64_t timeout, VkSemaphore semaphore, VkFence fence, uint32_t* image_index);
VKAPI_ATTR VkResult QueuePresentKHR(VkQueue queue, const VkPresentInfoKHR* present_info);
+VKAPI_ATTR VkResult AcquireNextImage2KHR(VkDevice device, const VkAcquireNextImageInfoKHR* pAcquireInfo, uint32_t* pImageIndex);
VKAPI_ATTR VkResult GetRefreshCycleDurationGOOGLE(VkDevice device, VkSwapchainKHR swapchain, VkRefreshCycleDurationGOOGLE* pDisplayTimingProperties);
VKAPI_ATTR VkResult GetPastPresentationTimingGOOGLE(VkDevice device, VkSwapchainKHR swapchain, uint32_t* pPresentationTimingCount, VkPastPresentationTimingGOOGLE* pPresentationTimings);
VKAPI_ATTR VkResult GetSwapchainStatusKHR(VkDevice device, VkSwapchainKHR swapchain);
diff --git a/vulkan/nulldrv/null_driver.cpp b/vulkan/nulldrv/null_driver.cpp
index 6714779..4647a80 100644
--- a/vulkan/nulldrv/null_driver.cpp
+++ b/vulkan/nulldrv/null_driver.cpp
@@ -16,15 +16,16 @@
#include <hardware/hwvulkan.h>
+#include <errno.h>
#include <inttypes.h>
#include <stdlib.h>
#include <string.h>
+#include <unistd.h>
#include <algorithm>
#include <array>
#include <log/log.h>
-#include <utils/Errors.h>
#include "null_driver_gen.h"
@@ -258,6 +259,12 @@
// Global
VKAPI_ATTR
+VkResult EnumerateInstanceVersion(uint32_t* pApiVersion) {
+ *pApiVersion = VK_API_VERSION_1_1;
+ return VK_SUCCESS;
+}
+
+VKAPI_ATTR
VkResult EnumerateInstanceExtensionProperties(
const char* layer_name,
uint32_t* count,
@@ -343,9 +350,14 @@
VkResult EnumeratePhysicalDevices(VkInstance instance,
uint32_t* physical_device_count,
VkPhysicalDevice* physical_devices) {
- if (physical_devices && *physical_device_count >= 1)
+ if (!physical_devices)
+ *physical_device_count = 1;
+ else if (*physical_device_count == 0)
+ return VK_INCOMPLETE;
+ else {
physical_devices[0] = &instance->physical_device;
- *physical_device_count = 1;
+ *physical_device_count = 1;
+ }
return VK_SUCCESS;
}
@@ -1469,6 +1481,93 @@
void DebugReportMessageEXT(VkInstance instance, VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objectType, uint64_t object, size_t location, int32_t messageCode, const char* pLayerPrefix, const char* pMessage) {
}
+VkResult BindBufferMemory2(VkDevice device, uint32_t bindInfoCount, const VkBindBufferMemoryInfo* pBindInfos) {
+ return VK_SUCCESS;
+}
+
+VkResult BindImageMemory2(VkDevice device, uint32_t bindInfoCount, const VkBindImageMemoryInfo* pBindInfos) {
+ return VK_SUCCESS;
+}
+
+void GetDeviceGroupPeerMemoryFeatures(VkDevice device, uint32_t heapIndex, uint32_t localDeviceIndex, uint32_t remoteDeviceIndex, VkPeerMemoryFeatureFlags* pPeerMemoryFeatures) {
+}
+
+void CmdSetDeviceMask(VkCommandBuffer commandBuffer, uint32_t deviceMask) {
+}
+
+void CmdDispatchBase(VkCommandBuffer commandBuffer, uint32_t baseGroupX, uint32_t baseGroupY, uint32_t baseGroupZ, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ) {
+}
+
+VkResult EnumeratePhysicalDeviceGroups(VkInstance instance, uint32_t* pPhysicalDeviceGroupCount, VkPhysicalDeviceGroupProperties* pPhysicalDeviceGroupProperties) {
+ return VK_SUCCESS;
+}
+
+void GetImageMemoryRequirements2(VkDevice device, const VkImageMemoryRequirementsInfo2* pInfo, VkMemoryRequirements2* pMemoryRequirements) {
+}
+
+void GetBufferMemoryRequirements2(VkDevice device, const VkBufferMemoryRequirementsInfo2* pInfo, VkMemoryRequirements2* pMemoryRequirements) {
+}
+
+void GetImageSparseMemoryRequirements2(VkDevice device, const VkImageSparseMemoryRequirementsInfo2* pInfo, uint32_t* pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements2* pSparseMemoryRequirements) {
+}
+
+void GetPhysicalDeviceFeatures2(VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures2* pFeatures) {
+}
+
+void GetPhysicalDeviceProperties2(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties2* pProperties) {
+}
+
+void GetPhysicalDeviceFormatProperties2(VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties2* pFormatProperties) {
+}
+
+VkResult GetPhysicalDeviceImageFormatProperties2(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceImageFormatInfo2* pImageFormatInfo, VkImageFormatProperties2* pImageFormatProperties) {
+ return VK_SUCCESS;
+}
+
+void GetPhysicalDeviceQueueFamilyProperties2(VkPhysicalDevice physicalDevice, uint32_t* pQueueFamilyPropertyCount, VkQueueFamilyProperties2* pQueueFamilyProperties) {
+}
+
+void GetPhysicalDeviceMemoryProperties2(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties2* pMemoryProperties) {
+}
+
+void GetPhysicalDeviceSparseImageFormatProperties2(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSparseImageFormatInfo2* pFormatInfo, uint32_t* pPropertyCount, VkSparseImageFormatProperties2* pProperties) {
+}
+
+void TrimCommandPool(VkDevice device, VkCommandPool commandPool, VkCommandPoolTrimFlags flags) {
+}
+
+void GetDeviceQueue2(VkDevice device, const VkDeviceQueueInfo2* pQueueInfo, VkQueue* pQueue) {
+}
+
+VkResult CreateSamplerYcbcrConversion(VkDevice device, const VkSamplerYcbcrConversionCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSamplerYcbcrConversion* pYcbcrConversion) {
+ return VK_SUCCESS;
+}
+
+void DestroySamplerYcbcrConversion(VkDevice device, VkSamplerYcbcrConversion ycbcrConversion, const VkAllocationCallbacks* pAllocator) {
+}
+
+VkResult CreateDescriptorUpdateTemplate(VkDevice device, const VkDescriptorUpdateTemplateCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDescriptorUpdateTemplate* pDescriptorUpdateTemplate) {
+ return VK_SUCCESS;
+}
+
+void DestroyDescriptorUpdateTemplate(VkDevice device, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const VkAllocationCallbacks* pAllocator) {
+}
+
+void UpdateDescriptorSetWithTemplate(VkDevice device, VkDescriptorSet descriptorSet, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const void* pData) {
+}
+
+void GetPhysicalDeviceExternalBufferProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalBufferInfo* pExternalBufferInfo, VkExternalBufferProperties* pExternalBufferProperties) {
+}
+
+void GetPhysicalDeviceExternalFenceProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalFenceInfo* pExternalFenceInfo, VkExternalFenceProperties* pExternalFenceProperties) {
+}
+
+void GetPhysicalDeviceExternalSemaphoreProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalSemaphoreInfo* pExternalSemaphoreInfo, VkExternalSemaphoreProperties* pExternalSemaphoreProperties) {
+}
+
+void GetDescriptorSetLayoutSupport(VkDevice device, const VkDescriptorSetLayoutCreateInfo* pCreateInfo, VkDescriptorSetLayoutSupport* pSupport) {
+}
+
#pragma clang diagnostic pop
// clang-format on
diff --git a/vulkan/nulldrv/null_driver_gen.cpp b/vulkan/nulldrv/null_driver_gen.cpp
index 25ee65a..92b7468 100644
--- a/vulkan/nulldrv/null_driver_gen.cpp
+++ b/vulkan/nulldrv/null_driver_gen.cpp
@@ -49,6 +49,7 @@
{"vkCreateInstance", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCreateInstance>(CreateInstance))},
{"vkEnumerateInstanceExtensionProperties", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkEnumerateInstanceExtensionProperties>(EnumerateInstanceExtensionProperties))},
{"vkEnumerateInstanceLayerProperties", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkEnumerateInstanceLayerProperties>(EnumerateInstanceLayerProperties))},
+ {"vkEnumerateInstanceVersion", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkEnumerateInstanceVersion>(EnumerateInstanceVersion))},
// clang-format on
};
@@ -60,7 +61,9 @@
{"vkAllocateMemory", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkAllocateMemory>(AllocateMemory))},
{"vkBeginCommandBuffer", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkBeginCommandBuffer>(BeginCommandBuffer))},
{"vkBindBufferMemory", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkBindBufferMemory>(BindBufferMemory))},
+ {"vkBindBufferMemory2", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkBindBufferMemory2>(BindBufferMemory2))},
{"vkBindImageMemory", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkBindImageMemory>(BindImageMemory))},
+ {"vkBindImageMemory2", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkBindImageMemory2>(BindImageMemory2))},
{"vkCmdBeginQuery", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdBeginQuery>(CmdBeginQuery))},
{"vkCmdBeginRenderPass", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdBeginRenderPass>(CmdBeginRenderPass))},
{"vkCmdBindDescriptorSets", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdBindDescriptorSets>(CmdBindDescriptorSets))},
@@ -77,6 +80,7 @@
{"vkCmdCopyImageToBuffer", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdCopyImageToBuffer>(CmdCopyImageToBuffer))},
{"vkCmdCopyQueryPoolResults", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdCopyQueryPoolResults>(CmdCopyQueryPoolResults))},
{"vkCmdDispatch", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdDispatch>(CmdDispatch))},
+ {"vkCmdDispatchBase", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdDispatchBase>(CmdDispatchBase))},
{"vkCmdDispatchIndirect", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdDispatchIndirect>(CmdDispatchIndirect))},
{"vkCmdDraw", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdDraw>(CmdDraw))},
{"vkCmdDrawIndexed", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdDrawIndexed>(CmdDrawIndexed))},
@@ -95,6 +99,7 @@
{"vkCmdSetBlendConstants", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdSetBlendConstants>(CmdSetBlendConstants))},
{"vkCmdSetDepthBias", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdSetDepthBias>(CmdSetDepthBias))},
{"vkCmdSetDepthBounds", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdSetDepthBounds>(CmdSetDepthBounds))},
+ {"vkCmdSetDeviceMask", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdSetDeviceMask>(CmdSetDeviceMask))},
{"vkCmdSetEvent", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdSetEvent>(CmdSetEvent))},
{"vkCmdSetLineWidth", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdSetLineWidth>(CmdSetLineWidth))},
{"vkCmdSetScissor", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdSetScissor>(CmdSetScissor))},
@@ -112,6 +117,7 @@
{"vkCreateDebugReportCallbackEXT", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCreateDebugReportCallbackEXT>(CreateDebugReportCallbackEXT))},
{"vkCreateDescriptorPool", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCreateDescriptorPool>(CreateDescriptorPool))},
{"vkCreateDescriptorSetLayout", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCreateDescriptorSetLayout>(CreateDescriptorSetLayout))},
+ {"vkCreateDescriptorUpdateTemplate", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCreateDescriptorUpdateTemplate>(CreateDescriptorUpdateTemplate))},
{"vkCreateDevice", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCreateDevice>(CreateDevice))},
{"vkCreateEvent", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCreateEvent>(CreateEvent))},
{"vkCreateFence", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCreateFence>(CreateFence))},
@@ -125,6 +131,7 @@
{"vkCreateQueryPool", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCreateQueryPool>(CreateQueryPool))},
{"vkCreateRenderPass", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCreateRenderPass>(CreateRenderPass))},
{"vkCreateSampler", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCreateSampler>(CreateSampler))},
+ {"vkCreateSamplerYcbcrConversion", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCreateSamplerYcbcrConversion>(CreateSamplerYcbcrConversion))},
{"vkCreateSemaphore", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCreateSemaphore>(CreateSemaphore))},
{"vkCreateShaderModule", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCreateShaderModule>(CreateShaderModule))},
{"vkDebugReportMessageEXT", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkDebugReportMessageEXT>(DebugReportMessageEXT))},
@@ -134,6 +141,7 @@
{"vkDestroyDebugReportCallbackEXT", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkDestroyDebugReportCallbackEXT>(DestroyDebugReportCallbackEXT))},
{"vkDestroyDescriptorPool", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkDestroyDescriptorPool>(DestroyDescriptorPool))},
{"vkDestroyDescriptorSetLayout", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkDestroyDescriptorSetLayout>(DestroyDescriptorSetLayout))},
+ {"vkDestroyDescriptorUpdateTemplate", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkDestroyDescriptorUpdateTemplate>(DestroyDescriptorUpdateTemplate))},
{"vkDestroyDevice", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkDestroyDevice>(DestroyDevice))},
{"vkDestroyEvent", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkDestroyEvent>(DestroyEvent))},
{"vkDestroyFence", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkDestroyFence>(DestroyFence))},
@@ -147,6 +155,7 @@
{"vkDestroyQueryPool", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkDestroyQueryPool>(DestroyQueryPool))},
{"vkDestroyRenderPass", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkDestroyRenderPass>(DestroyRenderPass))},
{"vkDestroySampler", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkDestroySampler>(DestroySampler))},
+ {"vkDestroySamplerYcbcrConversion", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkDestroySamplerYcbcrConversion>(DestroySamplerYcbcrConversion))},
{"vkDestroySemaphore", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkDestroySemaphore>(DestroySemaphore))},
{"vkDestroyShaderModule", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkDestroyShaderModule>(DestroyShaderModule))},
{"vkDeviceWaitIdle", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkDeviceWaitIdle>(DeviceWaitIdle))},
@@ -155,34 +164,52 @@
{"vkEnumerateDeviceLayerProperties", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkEnumerateDeviceLayerProperties>(EnumerateDeviceLayerProperties))},
{"vkEnumerateInstanceExtensionProperties", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkEnumerateInstanceExtensionProperties>(EnumerateInstanceExtensionProperties))},
{"vkEnumerateInstanceLayerProperties", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkEnumerateInstanceLayerProperties>(EnumerateInstanceLayerProperties))},
+ {"vkEnumerateInstanceVersion", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkEnumerateInstanceVersion>(EnumerateInstanceVersion))},
+ {"vkEnumeratePhysicalDeviceGroups", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkEnumeratePhysicalDeviceGroups>(EnumeratePhysicalDeviceGroups))},
{"vkEnumeratePhysicalDevices", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkEnumeratePhysicalDevices>(EnumeratePhysicalDevices))},
{"vkFlushMappedMemoryRanges", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkFlushMappedMemoryRanges>(FlushMappedMemoryRanges))},
{"vkFreeCommandBuffers", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkFreeCommandBuffers>(FreeCommandBuffers))},
{"vkFreeDescriptorSets", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkFreeDescriptorSets>(FreeDescriptorSets))},
{"vkFreeMemory", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkFreeMemory>(FreeMemory))},
{"vkGetBufferMemoryRequirements", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetBufferMemoryRequirements>(GetBufferMemoryRequirements))},
+ {"vkGetBufferMemoryRequirements2", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetBufferMemoryRequirements2>(GetBufferMemoryRequirements2))},
+ {"vkGetDescriptorSetLayoutSupport", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetDescriptorSetLayoutSupport>(GetDescriptorSetLayoutSupport))},
+ {"vkGetDeviceGroupPeerMemoryFeatures", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetDeviceGroupPeerMemoryFeatures>(GetDeviceGroupPeerMemoryFeatures))},
{"vkGetDeviceMemoryCommitment", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetDeviceMemoryCommitment>(GetDeviceMemoryCommitment))},
{"vkGetDeviceProcAddr", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetDeviceProcAddr>(GetDeviceProcAddr))},
{"vkGetDeviceQueue", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetDeviceQueue>(GetDeviceQueue))},
+ {"vkGetDeviceQueue2", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetDeviceQueue2>(GetDeviceQueue2))},
{"vkGetEventStatus", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetEventStatus>(GetEventStatus))},
{"vkGetFenceStatus", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetFenceStatus>(GetFenceStatus))},
{"vkGetImageMemoryRequirements", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetImageMemoryRequirements>(GetImageMemoryRequirements))},
+ {"vkGetImageMemoryRequirements2", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetImageMemoryRequirements2>(GetImageMemoryRequirements2))},
{"vkGetImageSparseMemoryRequirements", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetImageSparseMemoryRequirements>(GetImageSparseMemoryRequirements))},
+ {"vkGetImageSparseMemoryRequirements2", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetImageSparseMemoryRequirements2>(GetImageSparseMemoryRequirements2))},
{"vkGetImageSubresourceLayout", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetImageSubresourceLayout>(GetImageSubresourceLayout))},
{"vkGetInstanceProcAddr", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetInstanceProcAddr>(GetInstanceProcAddr))},
+ {"vkGetPhysicalDeviceExternalBufferProperties", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetPhysicalDeviceExternalBufferProperties>(GetPhysicalDeviceExternalBufferProperties))},
+ {"vkGetPhysicalDeviceExternalFenceProperties", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetPhysicalDeviceExternalFenceProperties>(GetPhysicalDeviceExternalFenceProperties))},
+ {"vkGetPhysicalDeviceExternalSemaphoreProperties", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetPhysicalDeviceExternalSemaphoreProperties>(GetPhysicalDeviceExternalSemaphoreProperties))},
{"vkGetPhysicalDeviceFeatures", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetPhysicalDeviceFeatures>(GetPhysicalDeviceFeatures))},
+ {"vkGetPhysicalDeviceFeatures2", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetPhysicalDeviceFeatures2>(GetPhysicalDeviceFeatures2))},
{"vkGetPhysicalDeviceFeatures2KHR", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetPhysicalDeviceFeatures2KHR>(GetPhysicalDeviceFeatures2KHR))},
{"vkGetPhysicalDeviceFormatProperties", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetPhysicalDeviceFormatProperties>(GetPhysicalDeviceFormatProperties))},
+ {"vkGetPhysicalDeviceFormatProperties2", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetPhysicalDeviceFormatProperties2>(GetPhysicalDeviceFormatProperties2))},
{"vkGetPhysicalDeviceFormatProperties2KHR", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetPhysicalDeviceFormatProperties2KHR>(GetPhysicalDeviceFormatProperties2KHR))},
{"vkGetPhysicalDeviceImageFormatProperties", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetPhysicalDeviceImageFormatProperties>(GetPhysicalDeviceImageFormatProperties))},
+ {"vkGetPhysicalDeviceImageFormatProperties2", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetPhysicalDeviceImageFormatProperties2>(GetPhysicalDeviceImageFormatProperties2))},
{"vkGetPhysicalDeviceImageFormatProperties2KHR", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetPhysicalDeviceImageFormatProperties2KHR>(GetPhysicalDeviceImageFormatProperties2KHR))},
{"vkGetPhysicalDeviceMemoryProperties", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetPhysicalDeviceMemoryProperties>(GetPhysicalDeviceMemoryProperties))},
+ {"vkGetPhysicalDeviceMemoryProperties2", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetPhysicalDeviceMemoryProperties2>(GetPhysicalDeviceMemoryProperties2))},
{"vkGetPhysicalDeviceMemoryProperties2KHR", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetPhysicalDeviceMemoryProperties2KHR>(GetPhysicalDeviceMemoryProperties2KHR))},
{"vkGetPhysicalDeviceProperties", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetPhysicalDeviceProperties>(GetPhysicalDeviceProperties))},
+ {"vkGetPhysicalDeviceProperties2", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetPhysicalDeviceProperties2>(GetPhysicalDeviceProperties2))},
{"vkGetPhysicalDeviceProperties2KHR", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetPhysicalDeviceProperties2KHR>(GetPhysicalDeviceProperties2KHR))},
{"vkGetPhysicalDeviceQueueFamilyProperties", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetPhysicalDeviceQueueFamilyProperties>(GetPhysicalDeviceQueueFamilyProperties))},
+ {"vkGetPhysicalDeviceQueueFamilyProperties2", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetPhysicalDeviceQueueFamilyProperties2>(GetPhysicalDeviceQueueFamilyProperties2))},
{"vkGetPhysicalDeviceQueueFamilyProperties2KHR", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetPhysicalDeviceQueueFamilyProperties2KHR>(GetPhysicalDeviceQueueFamilyProperties2KHR))},
{"vkGetPhysicalDeviceSparseImageFormatProperties", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetPhysicalDeviceSparseImageFormatProperties>(GetPhysicalDeviceSparseImageFormatProperties))},
+ {"vkGetPhysicalDeviceSparseImageFormatProperties2", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetPhysicalDeviceSparseImageFormatProperties2>(GetPhysicalDeviceSparseImageFormatProperties2))},
{"vkGetPhysicalDeviceSparseImageFormatProperties2KHR", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetPhysicalDeviceSparseImageFormatProperties2KHR>(GetPhysicalDeviceSparseImageFormatProperties2KHR))},
{"vkGetPipelineCacheData", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetPipelineCacheData>(GetPipelineCacheData))},
{"vkGetQueryPoolResults", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetQueryPoolResults>(GetQueryPoolResults))},
@@ -202,7 +229,9 @@
{"vkResetEvent", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkResetEvent>(ResetEvent))},
{"vkResetFences", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkResetFences>(ResetFences))},
{"vkSetEvent", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkSetEvent>(SetEvent))},
+ {"vkTrimCommandPool", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkTrimCommandPool>(TrimCommandPool))},
{"vkUnmapMemory", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkUnmapMemory>(UnmapMemory))},
+ {"vkUpdateDescriptorSetWithTemplate", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkUpdateDescriptorSetWithTemplate>(UpdateDescriptorSetWithTemplate))},
{"vkUpdateDescriptorSets", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkUpdateDescriptorSets>(UpdateDescriptorSets))},
{"vkWaitForFences", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkWaitForFences>(WaitForFences))},
// clang-format on
diff --git a/vulkan/nulldrv/null_driver_gen.h b/vulkan/nulldrv/null_driver_gen.h
index 8a9a963..c6ad537 100644
--- a/vulkan/nulldrv/null_driver_gen.h
+++ b/vulkan/nulldrv/null_driver_gen.h
@@ -165,6 +165,34 @@
VKAPI_ATTR void CmdNextSubpass(VkCommandBuffer commandBuffer, VkSubpassContents contents);
VKAPI_ATTR void CmdEndRenderPass(VkCommandBuffer commandBuffer);
VKAPI_ATTR void CmdExecuteCommands(VkCommandBuffer commandBuffer, uint32_t commandBufferCount, const VkCommandBuffer* pCommandBuffers);
+VKAPI_ATTR VkResult EnumerateInstanceVersion(uint32_t* pApiVersion);
+VKAPI_ATTR VkResult BindBufferMemory2(VkDevice device, uint32_t bindInfoCount, const VkBindBufferMemoryInfo* pBindInfos);
+VKAPI_ATTR VkResult BindImageMemory2(VkDevice device, uint32_t bindInfoCount, const VkBindImageMemoryInfo* pBindInfos);
+VKAPI_ATTR void GetDeviceGroupPeerMemoryFeatures(VkDevice device, uint32_t heapIndex, uint32_t localDeviceIndex, uint32_t remoteDeviceIndex, VkPeerMemoryFeatureFlags* pPeerMemoryFeatures);
+VKAPI_ATTR void CmdSetDeviceMask(VkCommandBuffer commandBuffer, uint32_t deviceMask);
+VKAPI_ATTR void CmdDispatchBase(VkCommandBuffer commandBuffer, uint32_t baseGroupX, uint32_t baseGroupY, uint32_t baseGroupZ, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ);
+VKAPI_ATTR VkResult EnumeratePhysicalDeviceGroups(VkInstance instance, uint32_t* pPhysicalDeviceGroupCount, VkPhysicalDeviceGroupProperties* pPhysicalDeviceGroupProperties);
+VKAPI_ATTR void GetImageMemoryRequirements2(VkDevice device, const VkImageMemoryRequirementsInfo2* pInfo, VkMemoryRequirements2* pMemoryRequirements);
+VKAPI_ATTR void GetBufferMemoryRequirements2(VkDevice device, const VkBufferMemoryRequirementsInfo2* pInfo, VkMemoryRequirements2* pMemoryRequirements);
+VKAPI_ATTR void GetImageSparseMemoryRequirements2(VkDevice device, const VkImageSparseMemoryRequirementsInfo2* pInfo, uint32_t* pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements2* pSparseMemoryRequirements);
+VKAPI_ATTR void GetPhysicalDeviceFeatures2(VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures2* pFeatures);
+VKAPI_ATTR void GetPhysicalDeviceProperties2(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties2* pProperties);
+VKAPI_ATTR void GetPhysicalDeviceFormatProperties2(VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties2* pFormatProperties);
+VKAPI_ATTR VkResult GetPhysicalDeviceImageFormatProperties2(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceImageFormatInfo2* pImageFormatInfo, VkImageFormatProperties2* pImageFormatProperties);
+VKAPI_ATTR void GetPhysicalDeviceQueueFamilyProperties2(VkPhysicalDevice physicalDevice, uint32_t* pQueueFamilyPropertyCount, VkQueueFamilyProperties2* pQueueFamilyProperties);
+VKAPI_ATTR void GetPhysicalDeviceMemoryProperties2(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties2* pMemoryProperties);
+VKAPI_ATTR void GetPhysicalDeviceSparseImageFormatProperties2(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSparseImageFormatInfo2* pFormatInfo, uint32_t* pPropertyCount, VkSparseImageFormatProperties2* pProperties);
+VKAPI_ATTR void TrimCommandPool(VkDevice device, VkCommandPool commandPool, VkCommandPoolTrimFlags flags);
+VKAPI_ATTR void GetDeviceQueue2(VkDevice device, const VkDeviceQueueInfo2* pQueueInfo, VkQueue* pQueue);
+VKAPI_ATTR VkResult CreateSamplerYcbcrConversion(VkDevice device, const VkSamplerYcbcrConversionCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSamplerYcbcrConversion* pYcbcrConversion);
+VKAPI_ATTR void DestroySamplerYcbcrConversion(VkDevice device, VkSamplerYcbcrConversion ycbcrConversion, const VkAllocationCallbacks* pAllocator);
+VKAPI_ATTR VkResult CreateDescriptorUpdateTemplate(VkDevice device, const VkDescriptorUpdateTemplateCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDescriptorUpdateTemplate* pDescriptorUpdateTemplate);
+VKAPI_ATTR void DestroyDescriptorUpdateTemplate(VkDevice device, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const VkAllocationCallbacks* pAllocator);
+VKAPI_ATTR void UpdateDescriptorSetWithTemplate(VkDevice device, VkDescriptorSet descriptorSet, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const void* pData);
+VKAPI_ATTR void GetPhysicalDeviceExternalBufferProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalBufferInfo* pExternalBufferInfo, VkExternalBufferProperties* pExternalBufferProperties);
+VKAPI_ATTR void GetPhysicalDeviceExternalFenceProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalFenceInfo* pExternalFenceInfo, VkExternalFenceProperties* pExternalFenceProperties);
+VKAPI_ATTR void GetPhysicalDeviceExternalSemaphoreProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalSemaphoreInfo* pExternalSemaphoreInfo, VkExternalSemaphoreProperties* pExternalSemaphoreProperties);
+VKAPI_ATTR void GetDescriptorSetLayoutSupport(VkDevice device, const VkDescriptorSetLayoutCreateInfo* pCreateInfo, VkDescriptorSetLayoutSupport* pSupport);
VKAPI_ATTR VkResult GetSwapchainGrallocUsageANDROID(VkDevice device, VkFormat format, VkImageUsageFlags imageUsage, int32_t* grallocUsage);
VKAPI_ATTR VkResult GetSwapchainGrallocUsage2ANDROID(VkDevice device, VkFormat format, VkImageUsageFlags imageUsage, VkSwapchainImageUsageFlagsANDROID swapchainImageUsage, uint64_t* grallocConsumerUsage, uint64_t* grallocProducerUsage);
VKAPI_ATTR VkResult AcquireImageANDROID(VkDevice device, VkImage image, int nativeFenceFd, VkSemaphore semaphore, VkFence fence);