Merge "binder_parcel_fuzzer: remove setData usage" into main
diff --git a/cmds/servicemanager/Access.cpp b/cmds/servicemanager/Access.cpp
index 711038c..8098724 100644
--- a/cmds/servicemanager/Access.cpp
+++ b/cmds/servicemanager/Access.cpp
@@ -22,6 +22,8 @@
#include <selinux/android.h>
#include <selinux/avc.h>
+#include <sstream>
+
namespace android {
#ifdef VENDORSERVICEMANAGER
@@ -80,6 +82,12 @@
}
#endif
+std::string Access::CallingContext::toDebugString() const {
+ std::stringstream ss;
+ ss << "Caller(pid=" << debugPid << ",uid=" << uid << ",sid=" << sid << ")";
+ return ss.str();
+}
+
Access::Access() {
#ifdef __ANDROID__
union selinux_callback cb;
diff --git a/cmds/servicemanager/Access.h b/cmds/servicemanager/Access.h
index 77c2cd4..4ee9b90 100644
--- a/cmds/servicemanager/Access.h
+++ b/cmds/servicemanager/Access.h
@@ -36,6 +36,8 @@
pid_t debugPid;
uid_t uid;
std::string sid;
+
+ std::string toDebugString() const;
};
virtual CallingContext getCallingContext();
diff --git a/cmds/servicemanager/ServiceManager.cpp b/cmds/servicemanager/ServiceManager.cpp
index a828b52..a5c0c60 100644
--- a/cmds/servicemanager/ServiceManager.cpp
+++ b/cmds/servicemanager/ServiceManager.cpp
@@ -115,18 +115,20 @@
return instance.package() + "." + instance.interface() + "/" + instance.instance();
}
-static bool isVintfDeclared(const std::string& name) {
+static bool isVintfDeclared(const Access::CallingContext& ctx, const std::string& name) {
NativeName nname;
if (NativeName::fill(name, &nname)) {
bool found = forEachManifest([&](const ManifestWithDescription& mwd) {
if (mwd.manifest->hasNativeInstance(nname.package, nname.instance)) {
- ALOGI("Found %s in %s VINTF manifest.", name.c_str(), mwd.description);
+ ALOGI("%s Found %s in %s VINTF manifest.", ctx.toDebugString().c_str(),
+ name.c_str(), mwd.description);
return true; // break
}
return false; // continue
});
if (!found) {
- ALOGI("Could not find %s in the VINTF manifest.", name.c_str());
+ ALOGI("%s Could not find %s in the VINTF manifest.", ctx.toDebugString().c_str(),
+ name.c_str());
}
return found;
}
@@ -136,7 +138,8 @@
bool found = forEachManifest([&](const ManifestWithDescription& mwd) {
if (mwd.manifest->hasAidlInstance(aname.package, aname.iface, aname.instance)) {
- ALOGI("Found %s in %s VINTF manifest.", name.c_str(), mwd.description);
+ ALOGI("%s Found %s in %s VINTF manifest.", ctx.toDebugString().c_str(), name.c_str(),
+ mwd.description);
return true; // break
}
return false; // continue
@@ -161,8 +164,9 @@
}
// Although it is tested, explicitly rebuilding qualified name, in case it
// becomes something unexpected.
- ALOGI("Could not find %s.%s/%s in the VINTF manifest. %s.", aname.package.c_str(),
- aname.iface.c_str(), aname.instance.c_str(), available.c_str());
+ ALOGI("%s Could not find %s.%s/%s in the VINTF manifest. %s.", ctx.toDebugString().c_str(),
+ aname.package.c_str(), aname.iface.c_str(), aname.instance.c_str(),
+ available.c_str());
}
return found;
@@ -290,12 +294,13 @@
return ret;
}
-static bool meetsDeclarationRequirements(const sp<IBinder>& binder, const std::string& name) {
+static bool meetsDeclarationRequirements(const Access::CallingContext& ctx,
+ const sp<IBinder>& binder, const std::string& name) {
if (!Stability::requiresVintfDeclaration(binder)) {
return true;
}
- return isVintfDeclared(name);
+ return isVintfDeclared(ctx, name);
}
#endif // !VENDORSERVICEMANAGER
@@ -307,7 +312,7 @@
// clear this bit so that we can abort in other cases, where it would
// mean inconsistent logic in servicemanager (unexpected and tested, but
// the original lazy service impl here had that bug).
- LOG(WARNING) << "a service was removed when there are clients";
+ ALOGW("A service was removed when there are clients");
}
}
@@ -423,25 +428,26 @@
}
if (!isValidServiceName(name)) {
- ALOGE("Invalid service name: %s", name.c_str());
+ ALOGE("%s Invalid service name: %s", ctx.toDebugString().c_str(), name.c_str());
return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT, "Invalid service name.");
}
#ifndef VENDORSERVICEMANAGER
- if (!meetsDeclarationRequirements(binder, name)) {
+ if (!meetsDeclarationRequirements(ctx, binder, name)) {
// already logged
return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT, "VINTF declaration error.");
}
#endif // !VENDORSERVICEMANAGER
if ((dumpPriority & DUMP_FLAG_PRIORITY_ALL) == 0) {
- ALOGW("Dump flag priority is not set when adding %s", name.c_str());
+ ALOGW("%s Dump flag priority is not set when adding %s", ctx.toDebugString().c_str(),
+ name.c_str());
}
// implicitly unlinked when the binder is removed
if (binder->remoteBinder() != nullptr &&
binder->linkToDeath(sp<ServiceManager>::fromExisting(this)) != OK) {
- ALOGE("Could not linkToDeath when adding %s", name.c_str());
+ ALOGE("%s Could not linkToDeath when adding %s", ctx.toDebugString().c_str(), name.c_str());
return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE, "Couldn't linkToDeath.");
}
@@ -543,7 +549,7 @@
}
if (!isValidServiceName(name)) {
- ALOGE("Invalid service name: %s", name.c_str());
+ ALOGE("%s Invalid service name: %s", ctx.toDebugString().c_str(), name.c_str());
return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT, "Invalid service name.");
}
@@ -554,7 +560,7 @@
if (OK !=
IInterface::asBinder(callback)->linkToDeath(
sp<ServiceManager>::fromExisting(this))) {
- ALOGE("Could not linkToDeath when adding %s", name.c_str());
+ ALOGE("%s Could not linkToDeath when adding %s", ctx.toDebugString().c_str(), name.c_str());
return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE, "Couldn't link to death.");
}
@@ -586,7 +592,8 @@
}
if (!found) {
- ALOGE("Trying to unregister callback, but none exists %s", name.c_str());
+ ALOGE("%s Trying to unregister callback, but none exists %s", ctx.toDebugString().c_str(),
+ name.c_str());
return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE, "Nothing to unregister.");
}
@@ -603,7 +610,7 @@
*outReturn = false;
#ifndef VENDORSERVICEMANAGER
- *outReturn = isVintfDeclared(name);
+ *outReturn = isVintfDeclared(ctx, name);
#endif
return Status::ok();
}
@@ -735,18 +742,16 @@
}
void ServiceManager::tryStartService(const Access::CallingContext& ctx, const std::string& name) {
- ALOGI("Since '%s' could not be found (requested by debug pid %d), trying to start it as a lazy "
- "AIDL service. (if it's not configured to be a lazy service, it may be stuck starting or "
- "still starting).",
- name.c_str(), ctx.debugPid);
+ ALOGI("%s Since '%s' could not be found trying to start it as a lazy AIDL service. (if it's "
+ "not configured to be a lazy service, it may be stuck starting or still starting).",
+ ctx.toDebugString().c_str(), name.c_str());
std::thread([=] {
if (!base::SetProperty("ctl.interface_start", "aidl/" + name)) {
- ALOGI("Tried to start aidl service %s as a lazy service, but was unable to. Usually "
- "this happens when a "
- "service is not installed, but if the service is intended to be used as a "
- "lazy service, then it may be configured incorrectly.",
- name.c_str());
+ ALOGI("%s Tried to start aidl service %s as a lazy service, but was unable to. Usually "
+ "this happens when a service is not installed, but if the service is intended to "
+ "be used as a lazy service, then it may be configured incorrectly.",
+ ctx.toDebugString().c_str(), name.c_str());
}
}).detach();
}
@@ -764,26 +769,28 @@
auto serviceIt = mNameToService.find(name);
if (serviceIt == mNameToService.end()) {
- ALOGE("Could not add callback for nonexistent service: %s", name.c_str());
+ ALOGE("%s Could not add callback for nonexistent service: %s", ctx.toDebugString().c_str(),
+ name.c_str());
return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT, "Service doesn't exist.");
}
if (serviceIt->second.ctx.debugPid != IPCThreadState::self()->getCallingPid()) {
- ALOGW("Only a server can register for client callbacks (for %s)", name.c_str());
+ ALOGW("%s Only a server can register for client callbacks (for %s)",
+ ctx.toDebugString().c_str(), name.c_str());
return Status::fromExceptionCode(Status::EX_UNSUPPORTED_OPERATION,
"Only service can register client callback for itself.");
}
if (serviceIt->second.binder != service) {
- ALOGW("Tried to register client callback for %s but a different service is registered "
+ ALOGW("%s Tried to register client callback for %s but a different service is registered "
"under this name.",
- name.c_str());
+ ctx.toDebugString().c_str(), name.c_str());
return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT, "Service mismatch.");
}
if (OK !=
IInterface::asBinder(cb)->linkToDeath(sp<ServiceManager>::fromExisting(this))) {
- ALOGE("Could not linkToDeath when adding client callback for %s", name.c_str());
+ ALOGE("%s Could not linkToDeath when adding client callback for %s", name.c_str());
return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE, "Couldn't linkToDeath.");
}
@@ -921,13 +928,14 @@
auto serviceIt = mNameToService.find(name);
if (serviceIt == mNameToService.end()) {
- ALOGW("Tried to unregister %s, but that service wasn't registered to begin with.",
- name.c_str());
+ ALOGW("%s Tried to unregister %s, but that service wasn't registered to begin with.",
+ ctx.toDebugString().c_str(), name.c_str());
return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE, "Service not registered.");
}
if (serviceIt->second.ctx.debugPid != IPCThreadState::self()->getCallingPid()) {
- ALOGW("Only a server can unregister itself (for %s)", name.c_str());
+ ALOGW("%s Only a server can unregister itself (for %s)", ctx.toDebugString().c_str(),
+ name.c_str());
return Status::fromExceptionCode(Status::EX_UNSUPPORTED_OPERATION,
"Service can only unregister itself.");
}
@@ -935,8 +943,8 @@
sp<IBinder> storedBinder = serviceIt->second.binder;
if (binder != storedBinder) {
- ALOGW("Tried to unregister %s, but a different service is registered under this name.",
- name.c_str());
+ ALOGW("%s Tried to unregister %s, but a different service is registered under this name.",
+ ctx.toDebugString().c_str(), name.c_str());
return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE,
"Different service registered under this name.");
}
@@ -944,7 +952,8 @@
// important because we don't have timer-based guarantees, we don't want to clear
// this
if (serviceIt->second.guaranteeClient) {
- ALOGI("Tried to unregister %s, but there is about to be a client.", name.c_str());
+ ALOGI("%s Tried to unregister %s, but there is about to be a client.",
+ ctx.toDebugString().c_str(), name.c_str());
return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE,
"Can't unregister, pending client.");
}
@@ -954,7 +963,8 @@
constexpr size_t kKnownClients = 2;
if (handleServiceClientCallback(kKnownClients, name, false)) {
- ALOGI("Tried to unregister %s, but there are clients.", name.c_str());
+ ALOGI("%s Tried to unregister %s, but there are clients.", ctx.toDebugString().c_str(),
+ name.c_str());
// Since we had a failed registration attempt, and the HIDL implementation of
// delaying service shutdown for multiple periods wasn't ported here... this may
@@ -965,7 +975,7 @@
"Can't unregister, known client.");
}
- ALOGI("Unregistering %s", name.c_str());
+ ALOGI("%s Unregistering %s", ctx.toDebugString().c_str(), name.c_str());
mNameToService.erase(name);
return Status::ok();
diff --git a/include/input/MotionPredictor.h b/include/input/MotionPredictor.h
index 3b6e401..f715039 100644
--- a/include/input/MotionPredictor.h
+++ b/include/input/MotionPredictor.h
@@ -16,6 +16,7 @@
#pragma once
+#include <array>
#include <cstdint>
#include <memory>
#include <mutex>
@@ -28,6 +29,7 @@
#include <android/sysprop/InputProperties.sysprop.h>
#include <input/Input.h>
#include <input/MotionPredictorMetricsManager.h>
+#include <input/RingBuffer.h>
#include <input/TfLiteMotionPredictor.h>
#include <utils/Timers.h> // for nsecs_t
@@ -37,6 +39,31 @@
return sysprop::InputProperties::enable_motion_prediction().value_or(true);
}
+// Tracker to calculate jerk from motion position samples.
+class JerkTracker {
+public:
+ // Initialize the tracker. If normalizedDt is true, assume that each sample pushed has dt=1.
+ JerkTracker(bool normalizedDt);
+
+ // Add a position to the tracker and update derivative estimates.
+ void pushSample(int64_t timestamp, float xPos, float yPos);
+
+ // Reset JerkTracker for a new motion input.
+ void reset();
+
+ // Return last jerk calculation, if enough samples have been collected.
+ // Jerk is defined as the 3rd derivative of position (change in
+ // acceleration) and has the units of d^3p/dt^3.
+ std::optional<float> jerkMagnitude() const;
+
+private:
+ const bool mNormalizedDt;
+
+ RingBuffer<int64_t> mTimestamps{4};
+ std::array<float, 4> mXDerivatives{}; // [x, x', x'', x''']
+ std::array<float, 4> mYDerivatives{}; // [y, y', y'', y''']
+};
+
/**
* Given a set of MotionEvents for the current gesture, predict the motion. The returned MotionEvent
* contains a set of samples in the future.
@@ -97,6 +124,11 @@
std::unique_ptr<TfLiteMotionPredictorBuffers> mBuffers;
std::optional<MotionEvent> mLastEvent;
+ // mJerkTracker assumes normalized dt = 1 between recorded samples because
+ // the underlying mModel input also assumes fixed-interval samples.
+ // Normalized dt as 1 is also used to correspond with the similar Jank
+ // implementation from the JetPack MotionPredictor implementation.
+ JerkTracker mJerkTracker{true};
std::optional<MotionPredictorMetricsManager> mMetricsManager;
diff --git a/libs/binder/ndk/include_platform/android/binder_manager.h b/libs/binder/ndk/include_platform/android/binder_manager.h
index 52edae4..c665ad8 100644
--- a/libs/binder/ndk/include_platform/android/binder_manager.h
+++ b/libs/binder/ndk/include_platform/android/binder_manager.h
@@ -18,9 +18,12 @@
#include <android/binder_ibinder.h>
#include <android/binder_status.h>
-#include <android/llndk-versioning.h>
#include <sys/cdefs.h>
+#ifndef __TRUSTY__
+#include <android/llndk-versioning.h>
+#endif
+
__BEGIN_DECLS
enum AServiceManager_AddServiceFlag : uint32_t {
diff --git a/libs/binder/ndk/stability.cpp b/libs/binder/ndk/stability.cpp
index ca3d5e6..39cf1c4 100644
--- a/libs/binder/ndk/stability.cpp
+++ b/libs/binder/ndk/stability.cpp
@@ -23,7 +23,7 @@
using ::android::internal::Stability;
-#ifdef __ANDROID_VNDK__
+#if defined(__ANDROID_VNDK__) && !defined(__TRUSTY__)
#error libbinder_ndk should only be built in a system context
#endif
diff --git a/libs/binder/trusty/ndk/include/sys/cdefs.h b/libs/binder/trusty/ndk/include/sys/cdefs.h
index 6a48d2b..eabfe60 100644
--- a/libs/binder/trusty/ndk/include/sys/cdefs.h
+++ b/libs/binder/trusty/ndk/include/sys/cdefs.h
@@ -22,3 +22,4 @@
#define __END_DECLS __END_CDECLS
#define __INTRODUCED_IN(x) /* nothing on Trusty */
+#define __INTRODUCED_IN_LLNDK(x) /* nothing on Trusty */
diff --git a/libs/binder/trusty/ndk/rules.mk b/libs/binder/trusty/ndk/rules.mk
index 03fd006..7a275c2 100644
--- a/libs/binder/trusty/ndk/rules.mk
+++ b/libs/binder/trusty/ndk/rules.mk
@@ -23,6 +23,7 @@
$(LIBBINDER_NDK_DIR)/ibinder.cpp \
$(LIBBINDER_NDK_DIR)/libbinder.cpp \
$(LIBBINDER_NDK_DIR)/parcel.cpp \
+ $(LIBBINDER_NDK_DIR)/stability.cpp \
$(LIBBINDER_NDK_DIR)/status.cpp \
MODULE_EXPORT_INCLUDES += \
diff --git a/libs/input/InputConsumer.cpp b/libs/input/InputConsumer.cpp
index e0d874e..41ecfe3 100644
--- a/libs/input/InputConsumer.cpp
+++ b/libs/input/InputConsumer.cpp
@@ -325,9 +325,10 @@
case InputMessage::Type::FINISHED:
case InputMessage::Type::TIMELINE: {
- LOG_ALWAYS_FATAL("Consumed a %s message, which should never be seen by "
- "InputConsumer!",
- ftl::enum_string(mMsg.header.type).c_str());
+ LOG(FATAL) << "Consumed a " << ftl::enum_string(mMsg.header.type)
+ << " message, which should never be seen by "
+ "InputConsumer on "
+ << mChannel->getName();
break;
}
diff --git a/libs/input/InputConsumerNoResampling.cpp b/libs/input/InputConsumerNoResampling.cpp
index 52acb51..76f2b4a 100644
--- a/libs/input/InputConsumerNoResampling.cpp
+++ b/libs/input/InputConsumerNoResampling.cpp
@@ -413,10 +413,9 @@
case InputMessage::Type::FINISHED:
case InputMessage::Type::TIMELINE: {
- LOG_ALWAYS_FATAL("Consumed a %s message, which should never be seen by "
- "InputConsumer on %s",
- ftl::enum_string(msg.header.type).c_str(),
- mChannel->getName().c_str());
+ LOG(FATAL) << "Consumed a " << ftl::enum_string(msg.header.type)
+ << " message, which should never be seen by InputConsumer on "
+ << mChannel->getName();
break;
}
diff --git a/libs/input/MotionPredictor.cpp b/libs/input/MotionPredictor.cpp
index 1df88dd..77292d4 100644
--- a/libs/input/MotionPredictor.cpp
+++ b/libs/input/MotionPredictor.cpp
@@ -18,12 +18,15 @@
#include <input/MotionPredictor.h>
+#include <array>
#include <cinttypes>
#include <cmath>
#include <cstddef>
#include <cstdint>
#include <limits>
+#include <optional>
#include <string>
+#include <utility>
#include <vector>
#include <android-base/logging.h>
@@ -61,6 +64,66 @@
} // namespace
+// --- JerkTracker ---
+
+JerkTracker::JerkTracker(bool normalizedDt) : mNormalizedDt(normalizedDt) {}
+
+void JerkTracker::pushSample(int64_t timestamp, float xPos, float yPos) {
+ mTimestamps.pushBack(timestamp);
+ const int numSamples = mTimestamps.size();
+
+ std::array<float, 4> newXDerivatives;
+ std::array<float, 4> newYDerivatives;
+
+ /**
+ * Diagram showing the calculation of higher order derivatives of sample x3
+ * collected at time=t3.
+ * Terms in parentheses are not stored (and not needed for calculations)
+ * t0 ----- t1 ----- t2 ----- t3
+ * (x0)-----(x1) ----- x2 ----- x3
+ * (x'0) --- x'1 --- x'2
+ * x''0 - x''1
+ * x'''0
+ *
+ * In this example:
+ * x'2 = (x3 - x2) / (t3 - t2)
+ * x''1 = (x'2 - x'1) / (t2 - t1)
+ * x'''0 = (x''1 - x''0) / (t1 - t0)
+ * Therefore, timestamp history is needed to calculate higher order derivatives,
+ * compared to just the last calculated derivative sample.
+ *
+ * If mNormalizedDt = true, then dt = 1 and the division is moot.
+ */
+ for (int i = 0; i < numSamples; ++i) {
+ if (i == 0) {
+ newXDerivatives[i] = xPos;
+ newYDerivatives[i] = yPos;
+ } else {
+ newXDerivatives[i] = newXDerivatives[i - 1] - mXDerivatives[i - 1];
+ newYDerivatives[i] = newYDerivatives[i - 1] - mYDerivatives[i - 1];
+ if (!mNormalizedDt) {
+ const float dt = mTimestamps[numSamples - i] - mTimestamps[numSamples - i - 1];
+ newXDerivatives[i] = newXDerivatives[i] / dt;
+ newYDerivatives[i] = newYDerivatives[i] / dt;
+ }
+ }
+ }
+
+ std::swap(newXDerivatives, mXDerivatives);
+ std::swap(newYDerivatives, mYDerivatives);
+}
+
+void JerkTracker::reset() {
+ mTimestamps.clear();
+}
+
+std::optional<float> JerkTracker::jerkMagnitude() const {
+ if (mTimestamps.size() == mTimestamps.capacity()) {
+ return std::hypot(mXDerivatives[3], mYDerivatives[3]);
+ }
+ return std::nullopt;
+}
+
// --- MotionPredictor ---
MotionPredictor::MotionPredictor(nsecs_t predictionTimestampOffsetNanos,
@@ -107,6 +170,7 @@
if (action == AMOTION_EVENT_ACTION_UP || action == AMOTION_EVENT_ACTION_CANCEL) {
ALOGD_IF(isDebug(), "End of event stream");
mBuffers->reset();
+ mJerkTracker.reset();
mLastEvent.reset();
return {};
} else if (action != AMOTION_EVENT_ACTION_DOWN && action != AMOTION_EVENT_ACTION_MOVE) {
@@ -141,6 +205,9 @@
0, i),
.orientation = event.getHistoricalOrientation(0, i),
});
+ mJerkTracker.pushSample(event.getHistoricalEventTime(i),
+ coords->getAxisValue(AMOTION_EVENT_AXIS_X),
+ coords->getAxisValue(AMOTION_EVENT_AXIS_Y));
}
if (!mLastEvent) {
diff --git a/libs/input/tests/MotionPredictor_test.cpp b/libs/input/tests/MotionPredictor_test.cpp
index 3343114..f74874c 100644
--- a/libs/input/tests/MotionPredictor_test.cpp
+++ b/libs/input/tests/MotionPredictor_test.cpp
@@ -15,6 +15,7 @@
*/
#include <chrono>
+#include <cmath>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
@@ -65,6 +66,108 @@
return event;
}
+TEST(JerkTrackerTest, JerkReadiness) {
+ JerkTracker jerkTracker(true);
+ EXPECT_FALSE(jerkTracker.jerkMagnitude());
+ jerkTracker.pushSample(/*timestamp=*/0, 20, 50);
+ EXPECT_FALSE(jerkTracker.jerkMagnitude());
+ jerkTracker.pushSample(/*timestamp=*/1, 25, 53);
+ EXPECT_FALSE(jerkTracker.jerkMagnitude());
+ jerkTracker.pushSample(/*timestamp=*/2, 30, 60);
+ EXPECT_FALSE(jerkTracker.jerkMagnitude());
+ jerkTracker.pushSample(/*timestamp=*/3, 35, 70);
+ EXPECT_TRUE(jerkTracker.jerkMagnitude());
+ jerkTracker.reset();
+ EXPECT_FALSE(jerkTracker.jerkMagnitude());
+ jerkTracker.pushSample(/*timestamp=*/4, 30, 60);
+ EXPECT_FALSE(jerkTracker.jerkMagnitude());
+}
+
+TEST(JerkTrackerTest, JerkCalculationNormalizedDtTrue) {
+ JerkTracker jerkTracker(true);
+ jerkTracker.pushSample(/*timestamp=*/0, 20, 50);
+ jerkTracker.pushSample(/*timestamp=*/1, 25, 53);
+ jerkTracker.pushSample(/*timestamp=*/2, 30, 60);
+ jerkTracker.pushSample(/*timestamp=*/3, 45, 70);
+ /**
+ * Jerk derivative table
+ * x: 20 25 30 45
+ * x': 5 5 15
+ * x'': 0 10
+ * x''': 10
+ *
+ * y: 50 53 60 70
+ * y': 3 7 10
+ * y'': 4 3
+ * y''': -1
+ */
+ EXPECT_FLOAT_EQ(jerkTracker.jerkMagnitude().value(), std::hypot(10, -1));
+ jerkTracker.pushSample(/*timestamp=*/4, 20, 65);
+ /**
+ * (continuing from above table)
+ * x: 45 -> 20
+ * x': 15 -> -25
+ * x'': 10 -> -40
+ * x''': -50
+ *
+ * y: 70 -> 65
+ * y': 10 -> -5
+ * y'': 3 -> -15
+ * y''': -18
+ */
+ EXPECT_FLOAT_EQ(jerkTracker.jerkMagnitude().value(), std::hypot(-50, -18));
+}
+
+TEST(JerkTrackerTest, JerkCalculationNormalizedDtFalse) {
+ JerkTracker jerkTracker(false);
+ jerkTracker.pushSample(/*timestamp=*/0, 20, 50);
+ jerkTracker.pushSample(/*timestamp=*/10, 25, 53);
+ jerkTracker.pushSample(/*timestamp=*/20, 30, 60);
+ jerkTracker.pushSample(/*timestamp=*/30, 45, 70);
+ /**
+ * Jerk derivative table
+ * x: 20 25 30 45
+ * x': .5 .5 1.5
+ * x'': 0 .1
+ * x''': .01
+ *
+ * y: 50 53 60 70
+ * y': .3 .7 1
+ * y'': .04 .03
+ * y''': -.001
+ */
+ EXPECT_FLOAT_EQ(jerkTracker.jerkMagnitude().value(), std::hypot(.01, -.001));
+ jerkTracker.pushSample(/*timestamp=*/50, 20, 65);
+ /**
+ * (continuing from above table)
+ * x: 45 -> 20
+ * x': 1.5 -> -1.25 (delta above, divide by 20)
+ * x'': .1 -> -.275 (delta above, divide by 10)
+ * x''': -.0375 (delta above, divide by 10)
+ *
+ * y: 70 -> 65
+ * y': 1 -> -.25 (delta above, divide by 20)
+ * y'': .03 -> -.125 (delta above, divide by 10)
+ * y''': -.0155 (delta above, divide by 10)
+ */
+ EXPECT_FLOAT_EQ(jerkTracker.jerkMagnitude().value(), std::hypot(-.0375, -.0155));
+}
+
+TEST(JerkTrackerTest, JerkCalculationAfterReset) {
+ JerkTracker jerkTracker(true);
+ jerkTracker.pushSample(/*timestamp=*/0, 20, 50);
+ jerkTracker.pushSample(/*timestamp=*/1, 25, 53);
+ jerkTracker.pushSample(/*timestamp=*/2, 30, 60);
+ jerkTracker.pushSample(/*timestamp=*/3, 45, 70);
+ jerkTracker.pushSample(/*timestamp=*/4, 20, 65);
+ jerkTracker.reset();
+ jerkTracker.pushSample(/*timestamp=*/5, 20, 50);
+ jerkTracker.pushSample(/*timestamp=*/6, 25, 53);
+ jerkTracker.pushSample(/*timestamp=*/7, 30, 60);
+ jerkTracker.pushSample(/*timestamp=*/8, 45, 70);
+ EXPECT_FLOAT_EQ(jerkTracker.jerkMagnitude().value(), std::hypot(10, -1));
+}
+
TEST(MotionPredictorTest, IsPredictionAvailable) {
MotionPredictor predictor(/*predictionTimestampOffsetNanos=*/0,
[]() { return true /*enable prediction*/; });
diff --git a/libs/renderengine/Android.bp b/libs/renderengine/Android.bp
index 0defc7e..c003111 100644
--- a/libs/renderengine/Android.bp
+++ b/libs/renderengine/Android.bp
@@ -84,6 +84,7 @@
"skia/Cache.cpp",
"skia/ColorSpaces.cpp",
"skia/GaneshVkRenderEngine.cpp",
+ "skia/GraphiteVkRenderEngine.cpp",
"skia/GLExtensions.cpp",
"skia/SkiaRenderEngine.cpp",
"skia/SkiaGLRenderEngine.cpp",
@@ -91,6 +92,8 @@
"skia/VulkanInterface.cpp",
"skia/compat/GaneshBackendTexture.cpp",
"skia/compat/GaneshGpuContext.cpp",
+ "skia/compat/GraphiteBackendTexture.cpp",
+ "skia/compat/GraphiteGpuContext.cpp",
"skia/debug/CaptureTimer.cpp",
"skia/debug/CommonPool.cpp",
"skia/debug/SkiaCapture.cpp",
diff --git a/libs/renderengine/RenderEngine.cpp b/libs/renderengine/RenderEngine.cpp
index 233134d..1c60563 100644
--- a/libs/renderengine/RenderEngine.cpp
+++ b/libs/renderengine/RenderEngine.cpp
@@ -16,40 +16,45 @@
#include <renderengine/RenderEngine.h>
-#include <cutils/properties.h>
-#include <log/log.h>
#include "renderengine/ExternalTexture.h"
+#include "skia/GaneshVkRenderEngine.h"
+#include "skia/GraphiteVkRenderEngine.h"
+#include "skia/SkiaGLRenderEngine.h"
#include "threaded/RenderEngineThreaded.h"
-#include "skia/SkiaGLRenderEngine.h"
-#include "skia/SkiaVkRenderEngine.h"
+#include <cutils/properties.h>
+#include <log/log.h>
namespace android {
namespace renderengine {
std::unique_ptr<RenderEngine> RenderEngine::create(const RenderEngineCreationArgs& args) {
- if (args.threaded == Threaded::YES) {
- switch (args.graphicsApi) {
- case GraphicsApi::GL:
- ALOGD("Threaded RenderEngine with SkiaGL Backend");
- return renderengine::threaded::RenderEngineThreaded::create([args]() {
- return android::renderengine::skia::SkiaGLRenderEngine::create(args);
- });
- case GraphicsApi::VK:
- ALOGD("Threaded RenderEngine with SkiaVK Backend");
- return renderengine::threaded::RenderEngineThreaded::create([args]() {
- return android::renderengine::skia::SkiaVkRenderEngine::create(args);
- });
+ threaded::CreateInstanceFactory createInstanceFactory;
+
+ ALOGD("%sRenderEngine with %s Backend (%s)", args.threaded == Threaded::YES ? "Threaded " : "",
+ args.graphicsApi == GraphicsApi::GL ? "SkiaGL" : "SkiaVK",
+ args.skiaBackend == SkiaBackend::GANESH ? "Ganesh" : "Graphite");
+
+ if (args.skiaBackend == SkiaBackend::GRAPHITE) {
+ createInstanceFactory = [args]() {
+ return android::renderengine::skia::GraphiteVkRenderEngine::create(args);
+ };
+ } else { // GANESH
+ if (args.graphicsApi == GraphicsApi::VK) {
+ createInstanceFactory = [args]() {
+ return android::renderengine::skia::GaneshVkRenderEngine::create(args);
+ };
+ } else { // GL
+ createInstanceFactory = [args]() {
+ return android::renderengine::skia::SkiaGLRenderEngine::create(args);
+ };
}
}
- switch (args.graphicsApi) {
- case GraphicsApi::GL:
- ALOGD("RenderEngine with SkiaGL Backend");
- return renderengine::skia::SkiaGLRenderEngine::create(args);
- case GraphicsApi::VK:
- ALOGD("RenderEngine with SkiaVK Backend");
- return renderengine::skia::SkiaVkRenderEngine::create(args);
+ if (args.threaded == Threaded::YES) {
+ return renderengine::threaded::RenderEngineThreaded::create(createInstanceFactory);
+ } else {
+ return createInstanceFactory();
}
}
diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h
index de05268..00a6213 100644
--- a/libs/renderengine/include/renderengine/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/RenderEngine.h
@@ -102,6 +102,11 @@
VK,
};
+ enum class SkiaBackend {
+ GANESH,
+ GRAPHITE,
+ };
+
static std::unique_ptr<RenderEngine> create(const RenderEngineCreationArgs& args);
static bool canSupport(GraphicsApi);
@@ -257,6 +262,7 @@
RenderEngine::ContextPriority contextPriority;
RenderEngine::Threaded threaded;
RenderEngine::GraphicsApi graphicsApi;
+ RenderEngine::SkiaBackend skiaBackend;
struct Builder;
@@ -267,7 +273,8 @@
bool _supportsBackgroundBlur,
RenderEngine::ContextPriority _contextPriority,
RenderEngine::Threaded _threaded,
- RenderEngine::GraphicsApi _graphicsApi)
+ RenderEngine::GraphicsApi _graphicsApi,
+ RenderEngine::SkiaBackend _skiaBackend)
: pixelFormat(_pixelFormat),
imageCacheSize(_imageCacheSize),
enableProtectedContext(_enableProtectedContext),
@@ -275,7 +282,8 @@
supportsBackgroundBlur(_supportsBackgroundBlur),
contextPriority(_contextPriority),
threaded(_threaded),
- graphicsApi(_graphicsApi) {}
+ graphicsApi(_graphicsApi),
+ skiaBackend(_skiaBackend) {}
RenderEngineCreationArgs() = delete;
};
@@ -314,10 +322,14 @@
this->graphicsApi = graphicsApi;
return *this;
}
+ Builder& setSkiaBackend(RenderEngine::SkiaBackend skiaBackend) {
+ this->skiaBackend = skiaBackend;
+ return *this;
+ }
RenderEngineCreationArgs build() const {
return RenderEngineCreationArgs(pixelFormat, imageCacheSize, enableProtectedContext,
precacheToneMapperShaderOnly, supportsBackgroundBlur,
- contextPriority, threaded, graphicsApi);
+ contextPriority, threaded, graphicsApi, skiaBackend);
}
private:
@@ -330,6 +342,7 @@
RenderEngine::ContextPriority contextPriority = RenderEngine::ContextPriority::MEDIUM;
RenderEngine::Threaded threaded = RenderEngine::Threaded::YES;
RenderEngine::GraphicsApi graphicsApi = RenderEngine::GraphicsApi::GL;
+ RenderEngine::SkiaBackend skiaBackend = RenderEngine::SkiaBackend::GANESH;
};
} // namespace renderengine
diff --git a/libs/renderengine/skia/GaneshVkRenderEngine.cpp b/libs/renderengine/skia/GaneshVkRenderEngine.cpp
index aa18713..68798bf 100644
--- a/libs/renderengine/skia/GaneshVkRenderEngine.cpp
+++ b/libs/renderengine/skia/GaneshVkRenderEngine.cpp
@@ -27,6 +27,22 @@
namespace android::renderengine::skia {
+std::unique_ptr<GaneshVkRenderEngine> GaneshVkRenderEngine::create(
+ const RenderEngineCreationArgs& args) {
+ std::unique_ptr<GaneshVkRenderEngine> engine(new GaneshVkRenderEngine(args));
+ engine->ensureContextsCreated();
+
+ if (getVulkanInterface(false).isInitialized()) {
+ ALOGD("GaneshVkRenderEngine::%s: successfully initialized GaneshVkRenderEngine", __func__);
+ return engine;
+ } else {
+ ALOGE("GaneshVkRenderEngine::%s: could not create GaneshVkRenderEngine. "
+ "Likely insufficient Vulkan support",
+ __func__);
+ return {};
+ }
+}
+
// Ganesh-specific function signature for fFinishedProc callback.
static void unref_semaphore(void* semaphore) {
SkiaVkRenderEngine::DestroySemaphoreInfo* info =
diff --git a/libs/renderengine/skia/GaneshVkRenderEngine.h b/libs/renderengine/skia/GaneshVkRenderEngine.h
index 5940d04..e6123c2 100644
--- a/libs/renderengine/skia/GaneshVkRenderEngine.h
+++ b/libs/renderengine/skia/GaneshVkRenderEngine.h
@@ -21,15 +21,16 @@
namespace android::renderengine::skia {
class GaneshVkRenderEngine : public SkiaVkRenderEngine {
- friend std::unique_ptr<SkiaVkRenderEngine> SkiaVkRenderEngine::create(
- const RenderEngineCreationArgs& args);
+public:
+ static std::unique_ptr<GaneshVkRenderEngine> create(const RenderEngineCreationArgs& args);
protected:
- GaneshVkRenderEngine(const RenderEngineCreationArgs& args) : SkiaVkRenderEngine(args) {}
-
std::unique_ptr<SkiaGpuContext> createContext(VulkanInterface& vulkanInterface) override;
void waitFence(SkiaGpuContext* context, base::borrowed_fd fenceFd) override;
base::unique_fd flushAndSubmit(SkiaGpuContext* context, sk_sp<SkSurface> dstSurface) override;
+
+private:
+ GaneshVkRenderEngine(const RenderEngineCreationArgs& args) : SkiaVkRenderEngine(args) {}
};
} // namespace android::renderengine::skia
diff --git a/libs/renderengine/skia/GraphiteVkRenderEngine.cpp b/libs/renderengine/skia/GraphiteVkRenderEngine.cpp
new file mode 100644
index 0000000..b5cb21b
--- /dev/null
+++ b/libs/renderengine/skia/GraphiteVkRenderEngine.cpp
@@ -0,0 +1,140 @@
+/*
+ * Copyright 2024 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 "GraphiteVkRenderEngine.h"
+
+#undef LOG_TAG
+#define LOG_TAG "RenderEngine"
+
+#include <include/gpu/GpuTypes.h>
+#include <include/gpu/graphite/BackendSemaphore.h>
+#include <include/gpu/graphite/Context.h>
+#include <include/gpu/graphite/Recording.h>
+
+#include <log/log_main.h>
+#include <sync/sync.h>
+
+#include <memory>
+#include <vector>
+
+namespace android::renderengine::skia {
+
+std::unique_ptr<GraphiteVkRenderEngine> GraphiteVkRenderEngine::create(
+ const RenderEngineCreationArgs& args) {
+ std::unique_ptr<GraphiteVkRenderEngine> engine(new GraphiteVkRenderEngine(args));
+ engine->ensureContextsCreated();
+
+ if (getVulkanInterface(false).isInitialized()) {
+ ALOGD("GraphiteVkRenderEngine::%s: successfully initialized GraphiteVkRenderEngine",
+ __func__);
+ return engine;
+ } else {
+ ALOGE("GraphiteVkRenderEngine::%s: could not create GraphiteVkRenderEngine. "
+ "Likely insufficient Vulkan support",
+ __func__);
+ return {};
+ }
+}
+
+// Graphite-specific function signature for fFinishedProc callback.
+static void unref_semaphore(void* semaphore, skgpu::CallbackResult result) {
+ if (result != skgpu::CallbackResult::kSuccess) {
+ ALOGE("Graphite submission of work to GPU failed, check for Skia errors");
+ }
+ SkiaVkRenderEngine::DestroySemaphoreInfo* info =
+ reinterpret_cast<SkiaVkRenderEngine::DestroySemaphoreInfo*>(semaphore);
+ info->unref();
+}
+
+std::unique_ptr<SkiaGpuContext> GraphiteVkRenderEngine::createContext(
+ VulkanInterface& vulkanInterface) {
+ return SkiaGpuContext::MakeVulkan_Graphite(vulkanInterface.getGraphiteBackendContext());
+}
+
+void GraphiteVkRenderEngine::waitFence(SkiaGpuContext*, base::borrowed_fd fenceFd) {
+ if (fenceFd.get() < 0) return;
+
+ int dupedFd = dup(fenceFd.get());
+ if (dupedFd < 0) {
+ ALOGE("failed to create duplicate fence fd: %d", dupedFd);
+ sync_wait(fenceFd.get(), -1);
+ return;
+ }
+
+ base::unique_fd fenceDup(dupedFd);
+ VkSemaphore waitSemaphore =
+ getVulkanInterface(isProtected()).importSemaphoreFromSyncFd(fenceDup.release());
+ graphite::BackendSemaphore beSemaphore(waitSemaphore);
+ mStagedWaitSemaphores.push_back(beSemaphore);
+}
+
+base::unique_fd GraphiteVkRenderEngine::flushAndSubmit(SkiaGpuContext* context, sk_sp<SkSurface>) {
+ // Minimal Recording setup. Required even if there are no incoming semaphores to wait on, and if
+ // creating the outgoing signaling semaphore fails.
+ std::unique_ptr<graphite::Recording> recording = context->graphiteRecorder()->snap();
+ graphite::InsertRecordingInfo insertInfo;
+ insertInfo.fRecording = recording.get();
+
+ VulkanInterface& vulkanInterface = getVulkanInterface(isProtected());
+ // This "signal" semaphore is called after rendering, but it is cleaned up in the same mechanism
+ // as "wait" semaphores from waitFence.
+ VkSemaphore vkSignalSemaphore = vulkanInterface.createExportableSemaphore();
+ graphite::BackendSemaphore backendSignalSemaphore(vkSignalSemaphore);
+
+ // Collect all Vk semaphores that DestroySemaphoreInfo needs to own and delete after GPU work.
+ std::vector<VkSemaphore> vkSemaphoresToCleanUp;
+ if (vkSignalSemaphore != VK_NULL_HANDLE) {
+ vkSemaphoresToCleanUp.push_back(vkSignalSemaphore);
+ }
+ for (auto backendWaitSemaphore : mStagedWaitSemaphores) {
+ vkSemaphoresToCleanUp.push_back(backendWaitSemaphore.getVkSemaphore());
+ }
+
+ DestroySemaphoreInfo* destroySemaphoreInfo = nullptr;
+ if (vkSemaphoresToCleanUp.size() > 0) {
+ destroySemaphoreInfo =
+ new DestroySemaphoreInfo(vulkanInterface, std::move(vkSemaphoresToCleanUp));
+
+ insertInfo.fNumWaitSemaphores = mStagedWaitSemaphores.size();
+ insertInfo.fWaitSemaphores = mStagedWaitSemaphores.data();
+ insertInfo.fNumSignalSemaphores = 1;
+ insertInfo.fSignalSemaphores = &backendSignalSemaphore;
+ insertInfo.fFinishedProc = unref_semaphore;
+ insertInfo.fFinishedContext = destroySemaphoreInfo;
+ }
+
+ const bool inserted = context->graphiteContext()->insertRecording(insertInfo);
+ LOG_ALWAYS_FATAL_IF(!inserted,
+ "graphite::Context::insertRecording(...) failed, check for Skia errors");
+ const bool submitted = context->graphiteContext()->submit(graphite::SyncToCpu::kNo);
+ LOG_ALWAYS_FATAL_IF(!submitted, "graphite::Context::submit(...) failed, check for Skia errors");
+ // Skia's "backend" semaphores can be deleted immediately after inserting the recording; only
+ // the underlying VK semaphores need to be kept until GPU work is complete.
+ mStagedWaitSemaphores.clear();
+
+ base::unique_fd drawFenceFd(-1);
+ if (vkSignalSemaphore != VK_NULL_HANDLE) {
+ drawFenceFd.reset(vulkanInterface.exportSemaphoreSyncFd(vkSignalSemaphore));
+ }
+ // Now that drawFenceFd has been created, we can delete RE's reference to this semaphore, as
+ // another reference is still held until fFinishedProc is called after completion of GPU work.
+ if (destroySemaphoreInfo) {
+ destroySemaphoreInfo->unref();
+ }
+ return drawFenceFd;
+}
+
+} // namespace android::renderengine::skia
diff --git a/libs/renderengine/skia/GraphiteVkRenderEngine.h b/libs/renderengine/skia/GraphiteVkRenderEngine.h
new file mode 100644
index 0000000..cf24a3b
--- /dev/null
+++ b/libs/renderengine/skia/GraphiteVkRenderEngine.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2024 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 "SkiaVkRenderEngine.h"
+
+#include <include/gpu/graphite/BackendSemaphore.h>
+
+namespace android::renderengine::skia {
+
+class GraphiteVkRenderEngine : public SkiaVkRenderEngine {
+public:
+ static std::unique_ptr<GraphiteVkRenderEngine> create(const RenderEngineCreationArgs& args);
+
+protected:
+ std::unique_ptr<SkiaGpuContext> createContext(VulkanInterface& vulkanInterface) override;
+ void waitFence(SkiaGpuContext* context, base::borrowed_fd fenceFd) override;
+ base::unique_fd flushAndSubmit(SkiaGpuContext* context, sk_sp<SkSurface> dstSurface) override;
+
+private:
+ GraphiteVkRenderEngine(const RenderEngineCreationArgs& args) : SkiaVkRenderEngine(args) {}
+
+ std::vector<graphite::BackendSemaphore> mStagedWaitSemaphores;
+};
+
+} // namespace android::renderengine::skia
diff --git a/libs/renderengine/skia/SkiaVkRenderEngine.cpp b/libs/renderengine/skia/SkiaVkRenderEngine.cpp
index 3715859..fd71332 100644
--- a/libs/renderengine/skia/SkiaVkRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaVkRenderEngine.cpp
@@ -83,23 +83,6 @@
using base::StringAppendF;
-std::unique_ptr<SkiaVkRenderEngine> SkiaVkRenderEngine::create(
- const RenderEngineCreationArgs& args) {
- // TODO: b/293371537 - Ganesh vs. Graphite subclass based on flag in RenderEngineCreationArgs
- std::unique_ptr<SkiaVkRenderEngine> engine(new GaneshVkRenderEngine(args));
- engine->ensureContextsCreated();
-
- if (sVulkanInterface.isInitialized()) {
- ALOGD("SkiaVkRenderEngine::%s: successfully initialized SkiaVkRenderEngine", __func__);
- return engine;
- } else {
- ALOGD("SkiaVkRenderEngine::%s: could not create SkiaVkRenderEngine. "
- "Likely insufficient Vulkan support",
- __func__);
- return {};
- }
-}
-
SkiaVkRenderEngine::SkiaVkRenderEngine(const RenderEngineCreationArgs& args)
: SkiaRenderEngine(args.threaded, static_cast<PixelFormat>(args.pixelFormat),
args.supportsBackgroundBlur) {}
diff --git a/libs/renderengine/skia/SkiaVkRenderEngine.h b/libs/renderengine/skia/SkiaVkRenderEngine.h
index 371b812..0a2f9b2 100644
--- a/libs/renderengine/skia/SkiaVkRenderEngine.h
+++ b/libs/renderengine/skia/SkiaVkRenderEngine.h
@@ -29,7 +29,6 @@
class SkiaVkRenderEngine : public SkiaRenderEngine {
public:
- static std::unique_ptr<SkiaVkRenderEngine> create(const RenderEngineCreationArgs& args);
~SkiaVkRenderEngine() override;
int getContextPriority() override;
diff --git a/libs/renderengine/skia/VulkanInterface.cpp b/libs/renderengine/skia/VulkanInterface.cpp
index 2f09a38..49b9f1e 100644
--- a/libs/renderengine/skia/VulkanInterface.cpp
+++ b/libs/renderengine/skia/VulkanInterface.cpp
@@ -20,6 +20,8 @@
#include "VulkanInterface.h"
#include <include/gpu/GpuTypes.h>
+#include <include/gpu/vk/VulkanBackendContext.h>
+
#include <log/log_main.h>
#include <utils/Timers.h>
@@ -47,6 +49,23 @@
return backendContext;
};
+VulkanBackendContext VulkanInterface::getGraphiteBackendContext() {
+ VulkanBackendContext backendContext;
+ backendContext.fInstance = mInstance;
+ backendContext.fPhysicalDevice = mPhysicalDevice;
+ backendContext.fDevice = mDevice;
+ backendContext.fQueue = mQueue;
+ backendContext.fGraphicsQueueIndex = mQueueIndex;
+ backendContext.fMaxAPIVersion = mApiVersion;
+ backendContext.fVkExtensions = &mGrExtensions;
+ backendContext.fDeviceFeatures2 = mPhysicalDeviceFeatures2;
+ backendContext.fGetProc = mGrGetProc;
+ backendContext.fProtectedContext = mIsProtected ? Protected::kYes : Protected::kNo;
+ backendContext.fDeviceLostContext = this; // VulkanInterface is long-lived
+ backendContext.fDeviceLostProc = onVkDeviceFault;
+ return backendContext;
+};
+
VkSemaphore VulkanInterface::createExportableSemaphore() {
VkExportSemaphoreCreateInfo exportInfo;
exportInfo.sType = VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO;
diff --git a/libs/renderengine/skia/VulkanInterface.h b/libs/renderengine/skia/VulkanInterface.h
index 512e62c..2824fcb 100644
--- a/libs/renderengine/skia/VulkanInterface.h
+++ b/libs/renderengine/skia/VulkanInterface.h
@@ -23,6 +23,10 @@
using namespace skgpu;
+namespace skgpu {
+struct VulkanBackendContext;
+} // namespace skgpu
+
namespace android {
namespace renderengine {
namespace skia {
@@ -39,8 +43,8 @@
void init(bool protectedContent = false);
void teardown();
- // TODO: b/293371537 - Graphite variant (external/skia/include/gpu/vk/VulkanBackendContext.h)
GrVkBackendContext getGaneshBackendContext();
+ VulkanBackendContext getGraphiteBackendContext();
VkSemaphore createExportableSemaphore();
VkSemaphore importSemaphoreFromSyncFd(int syncFd);
int exportSemaphoreSyncFd(VkSemaphore semaphore);
diff --git a/libs/renderengine/skia/compat/GraphiteBackendTexture.cpp b/libs/renderengine/skia/compat/GraphiteBackendTexture.cpp
new file mode 100644
index 0000000..3dd9ed2
--- /dev/null
+++ b/libs/renderengine/skia/compat/GraphiteBackendTexture.cpp
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2024 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 "GraphiteBackendTexture.h"
+
+#undef LOG_TAG
+#define LOG_TAG "RenderEngine"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+#include <include/core/SkSurfaceProps.h>
+#include <include/gpu/graphite/Image.h>
+#include <include/gpu/graphite/Surface.h>
+#include <include/gpu/graphite/TextureInfo.h>
+
+#include "skia/ColorSpaces.h"
+
+#include <android/hardware_buffer.h>
+#include <inttypes.h>
+#include <log/log_main.h>
+#include <utils/Trace.h>
+
+namespace android::renderengine::skia {
+
+GraphiteBackendTexture::GraphiteBackendTexture(std::shared_ptr<skgpu::graphite::Recorder> recorder,
+ AHardwareBuffer* buffer, bool isOutputBuffer)
+ : SkiaBackendTexture(buffer, isOutputBuffer), mRecorder(std::move(recorder)) {
+ ATRACE_CALL();
+ AHardwareBuffer_Desc desc;
+ AHardwareBuffer_describe(buffer, &desc);
+ const bool createProtectedImage = 0 != (desc.usage & AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT);
+
+ const SkISize dimensions = {static_cast<int32_t>(desc.width),
+ static_cast<int32_t>(desc.height)};
+ LOG_ALWAYS_FATAL_IF(static_cast<uint32_t>(dimensions.width()) != desc.width ||
+ static_cast<uint32_t>(dimensions.height()) != desc.height,
+ "Failed to create a valid texture, casting unsigned dimensions [%" PRIu32
+ ",%" PRIu32 "] to signed [%" PRIo32 ",%" PRIo32 "] "
+ "is invalid",
+ desc.width, desc.height, dimensions.width(), dimensions.height());
+
+ mBackendTexture = mRecorder->createBackendTexture(buffer, isOutputBuffer, createProtectedImage,
+ dimensions, false);
+ if (!mBackendTexture.isValid() || !dimensions.width() || !dimensions.height()) {
+ LOG_ALWAYS_FATAL("Failed to create a valid texture. [%p]:[%d,%d] isProtected:%d "
+ "isWriteable:%d format:%d",
+ this, dimensions.width(), dimensions.height(), createProtectedImage,
+ isOutputBuffer, desc.format);
+ }
+}
+
+GraphiteBackendTexture::~GraphiteBackendTexture() {
+ if (mBackendTexture.isValid()) {
+ mRecorder->deleteBackendTexture(mBackendTexture);
+ mBackendTexture = {};
+ }
+}
+
+sk_sp<SkImage> GraphiteBackendTexture::makeImage(SkAlphaType alphaType, ui::Dataspace dataspace,
+ TextureReleaseProc releaseImageProc,
+ ReleaseContext releaseContext) {
+ const SkColorType colorType = colorTypeForImage(alphaType);
+ sk_sp<SkImage> image =
+ SkImages::WrapTexture(mRecorder.get(), mBackendTexture, colorType, alphaType,
+ toSkColorSpace(dataspace), releaseImageProc, releaseContext);
+ if (!image) {
+ logFatalTexture("Unable to generate SkImage.", dataspace, colorType);
+ }
+ return image;
+}
+
+sk_sp<SkSurface> GraphiteBackendTexture::makeSurface(ui::Dataspace dataspace,
+ TextureReleaseProc releaseSurfaceProc,
+ ReleaseContext releaseContext) {
+ const SkColorType colorType = internalColorType();
+ SkSurfaceProps props;
+ sk_sp<SkSurface> surface =
+ SkSurfaces::WrapBackendTexture(mRecorder.get(), mBackendTexture, colorType,
+ toSkColorSpace(dataspace), &props, releaseSurfaceProc,
+ releaseContext);
+ if (!surface) {
+ logFatalTexture("Unable to generate SkSurface.", dataspace, colorType);
+ }
+ return surface;
+}
+
+void GraphiteBackendTexture::logFatalTexture(const char* msg, ui::Dataspace dataspace,
+ SkColorType colorType) {
+ // TODO: b/293371537 - Iterate on this logging (validate failure cases, possibly check
+ // VulkanTextureInfo, etc.)
+ const skgpu::graphite::TextureInfo& textureInfo = mBackendTexture.info();
+ LOG_ALWAYS_FATAL("%s isOutputBuffer:%d, dataspace:%d, colorType:%d"
+ "\n\tBackendTexture: isValid:%d, dimensions:%dx%d"
+ "\n\t\tTextureInfo: isValid:%d, numSamples:%d, mipmapped:%d, isProtected: %d",
+ msg, isOutputBuffer(), static_cast<int32_t>(dataspace), colorType,
+ mBackendTexture.isValid(), mBackendTexture.dimensions().width(),
+ mBackendTexture.dimensions().height(), textureInfo.isValid(),
+ textureInfo.numSamples(), static_cast<int32_t>(textureInfo.mipmapped()),
+ static_cast<int32_t>(textureInfo.isProtected()));
+}
+
+} // namespace android::renderengine::skia
diff --git a/libs/renderengine/skia/compat/GraphiteBackendTexture.h b/libs/renderengine/skia/compat/GraphiteBackendTexture.h
new file mode 100644
index 0000000..3bec3f7
--- /dev/null
+++ b/libs/renderengine/skia/compat/GraphiteBackendTexture.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2024 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 "SkiaBackendTexture.h"
+
+#include <include/core/SkColorSpace.h>
+#include <include/core/SkImage.h>
+#include <include/core/SkSurface.h>
+#include <include/gpu/graphite/BackendTexture.h>
+#include <include/gpu/graphite/Recorder.h>
+
+#include <android-base/macros.h>
+#include <ui/GraphicTypes.h>
+
+#include <memory>
+
+namespace android::renderengine::skia {
+
+class GraphiteBackendTexture : public SkiaBackendTexture {
+public:
+ // Creates an internal skgpu::graphite::BackendTexture whose contents come from the provided
+ // buffer.
+ GraphiteBackendTexture(std::shared_ptr<skgpu::graphite::Recorder> recorder,
+ AHardwareBuffer* buffer, bool isOutputBuffer);
+
+ ~GraphiteBackendTexture() override;
+
+ sk_sp<SkImage> makeImage(SkAlphaType alphaType, ui::Dataspace dataspace,
+ TextureReleaseProc releaseImageProc,
+ ReleaseContext releaseContext) override;
+
+ sk_sp<SkSurface> makeSurface(ui::Dataspace dataspace, TextureReleaseProc releaseSurfaceProc,
+ ReleaseContext releaseContext) override;
+
+private:
+ DISALLOW_COPY_AND_ASSIGN(GraphiteBackendTexture);
+
+ void logFatalTexture(const char* msg, ui::Dataspace dataspace, SkColorType colorType);
+
+ const std::shared_ptr<skgpu::graphite::Recorder> mRecorder;
+ skgpu::graphite::BackendTexture mBackendTexture;
+};
+
+} // namespace android::renderengine::skia
diff --git a/libs/renderengine/skia/compat/GraphiteGpuContext.cpp b/libs/renderengine/skia/compat/GraphiteGpuContext.cpp
new file mode 100644
index 0000000..e19d66f
--- /dev/null
+++ b/libs/renderengine/skia/compat/GraphiteGpuContext.cpp
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2024 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 "GraphiteGpuContext.h"
+
+#include <include/core/SkImageInfo.h>
+#include <include/core/SkSurface.h>
+#include <include/core/SkTraceMemoryDump.h>
+#include <include/gpu/graphite/GraphiteTypes.h>
+#include <include/gpu/graphite/Surface.h>
+#include <include/gpu/graphite/vk/VulkanGraphiteUtils.h>
+
+#include "GpuTypes.h"
+#include "skia/compat/GraphiteBackendTexture.h"
+
+#include <android-base/macros.h>
+#include <log/log_main.h>
+#include <memory>
+
+namespace android::renderengine::skia {
+
+namespace {
+static skgpu::graphite::ContextOptions graphiteOptions() {
+ skgpu::graphite::ContextOptions options;
+ options.fDisableDriverCorrectnessWorkarounds = true;
+ return options;
+}
+} // namespace
+
+std::unique_ptr<SkiaGpuContext> SkiaGpuContext::MakeVulkan_Graphite(
+ const skgpu::VulkanBackendContext& vulkanBackendContext) {
+ return std::make_unique<GraphiteGpuContext>(
+ skgpu::graphite::ContextFactory::MakeVulkan(vulkanBackendContext, graphiteOptions()));
+}
+
+GraphiteGpuContext::GraphiteGpuContext(std::unique_ptr<skgpu::graphite::Context> context)
+ : mContext(std::move(context)) {
+ LOG_ALWAYS_FATAL_IF(mContext.get() == nullptr, "graphite::Context creation failed");
+ LOG_ALWAYS_FATAL_IF(mContext->backend() != skgpu::BackendApi::kVulkan,
+ "graphite::Context::backend() == %d, but GraphiteBackendContext makes "
+ "assumptions that are only valid for Vulkan (%d)",
+ static_cast<int>(mContext->backend()),
+ static_cast<int>(skgpu::BackendApi::kVulkan));
+
+ // TODO: b/293371537 - Iterate on default cache limits (the Recorder should have the majority of
+ // the budget, and the Context should be given a smaller fraction.)
+ skgpu::graphite::RecorderOptions recorderOptions = skgpu::graphite::RecorderOptions();
+ this->mRecorder = mContext->makeRecorder(recorderOptions);
+ LOG_ALWAYS_FATAL_IF(mRecorder.get() == nullptr, "graphite::Recorder creation failed");
+}
+
+std::shared_ptr<skgpu::graphite::Context> GraphiteGpuContext::graphiteContext() {
+ return mContext;
+}
+
+std::shared_ptr<skgpu::graphite::Recorder> GraphiteGpuContext::graphiteRecorder() {
+ return mRecorder;
+}
+
+std::unique_ptr<SkiaBackendTexture> GraphiteGpuContext::makeBackendTexture(AHardwareBuffer* buffer,
+ bool isOutputBuffer) {
+ return std::make_unique<GraphiteBackendTexture>(graphiteRecorder(), buffer, isOutputBuffer);
+}
+
+sk_sp<SkSurface> GraphiteGpuContext::createRenderTarget(SkImageInfo imageInfo) {
+ constexpr SkSurfaceProps* kProps = nullptr;
+ return SkSurfaces::RenderTarget(mRecorder.get(), imageInfo, skgpu::Mipmapped::kNo, kProps);
+}
+
+size_t GraphiteGpuContext::getMaxRenderTargetSize() const {
+ // maxRenderTargetSize only differs from maxTextureSize on GL, so as long as Graphite implies
+ // Vk, then the distinction is irrelevant.
+ return getMaxTextureSize();
+};
+
+size_t GraphiteGpuContext::getMaxTextureSize() const {
+ return mContext->maxTextureSize();
+};
+
+bool GraphiteGpuContext::isAbandonedOrDeviceLost() {
+ return mContext->isDeviceLost();
+}
+
+void GraphiteGpuContext::finishRenderingAndAbandonContext() {
+ // TODO: b/293371537 - Validate that nothing else needs to be explicitly abandoned.
+ mContext->submit(skgpu::graphite::SyncToCpu::kYes);
+};
+
+void GraphiteGpuContext::dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const {
+ mContext->dumpMemoryStatistics(traceMemoryDump);
+}
+
+} // namespace android::renderengine::skia
diff --git a/libs/renderengine/skia/compat/GraphiteGpuContext.h b/libs/renderengine/skia/compat/GraphiteGpuContext.h
new file mode 100644
index 0000000..685f899
--- /dev/null
+++ b/libs/renderengine/skia/compat/GraphiteGpuContext.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2024 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 "SkiaGpuContext.h"
+#include "graphite/Recorder.h"
+
+#include <android-base/macros.h>
+
+namespace android::renderengine::skia {
+
+class GraphiteGpuContext : public SkiaGpuContext {
+public:
+ GraphiteGpuContext(std::unique_ptr<skgpu::graphite::Context> context);
+ ~GraphiteGpuContext() override = default;
+
+ std::shared_ptr<skgpu::graphite::Context> graphiteContext() override;
+ std::shared_ptr<skgpu::graphite::Recorder> graphiteRecorder() override;
+
+ std::unique_ptr<SkiaBackendTexture> makeBackendTexture(AHardwareBuffer* buffer,
+ bool isOutputBuffer) override;
+
+ sk_sp<SkSurface> createRenderTarget(SkImageInfo imageInfo) override;
+
+ size_t getMaxRenderTargetSize() const override;
+ size_t getMaxTextureSize() const override;
+ bool isAbandonedOrDeviceLost() override;
+ // No-op (large resources like textures, surfaces, images, etc. created by clients don't count
+ // towards Graphite's internal caching budgets, so adjusting its limits based on display change
+ // events should be unnecessary. Additionally, Graphite doesn't expose many cache tweaking
+ // functions yet, as its design may evolve.)
+ void setResourceCacheLimit(size_t maxResourceBytes) override{};
+
+ void finishRenderingAndAbandonContext() override;
+ // TODO: b/293371537 - Triple-check and validate that no cleanup is necessary when switching
+ // contexts.
+ // No-op (unnecessary during context switch for Graphite's client-budgeted memory model).
+ void purgeUnlockedScratchResources() override{};
+ // No-op (only applicable to GL).
+ void resetContextIfApplicable() override{};
+
+ void dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const override;
+
+private:
+ DISALLOW_COPY_AND_ASSIGN(GraphiteGpuContext);
+
+ const std::shared_ptr<skgpu::graphite::Context> mContext;
+ std::shared_ptr<skgpu::graphite::Recorder> mRecorder;
+};
+
+} // namespace android::renderengine::skia
diff --git a/libs/renderengine/skia/compat/SkiaGpuContext.h b/libs/renderengine/skia/compat/SkiaGpuContext.h
index 8222e62..a2457e5 100644
--- a/libs/renderengine/skia/compat/SkiaGpuContext.h
+++ b/libs/renderengine/skia/compat/SkiaGpuContext.h
@@ -22,7 +22,9 @@
#include <include/core/SkSurface.h>
#include <include/gpu/GrDirectContext.h>
#include <include/gpu/gl/GrGLInterface.h>
+#include <include/gpu/graphite/Context.h>
#include <include/gpu/vk/GrVkBackendContext.h>
+#include "include/gpu/vk/VulkanBackendContext.h"
#include "SkiaBackendTexture.h"
@@ -41,14 +43,16 @@
sk_sp<const GrGLInterface> glInterface,
GrContextOptions::PersistentCache& skSLCacheMonitor);
- // TODO: b/293371537 - Graphite variant.
static std::unique_ptr<SkiaGpuContext> MakeVulkan_Ganesh(
const GrVkBackendContext& grVkBackendContext,
GrContextOptions::PersistentCache& skSLCacheMonitor);
+ // TODO: b/293371537 - Need shader / pipeline monitoring support in Graphite.
+ static std::unique_ptr<SkiaGpuContext> MakeVulkan_Graphite(
+ const skgpu::VulkanBackendContext& vulkanBackendContext);
+
virtual ~SkiaGpuContext() = default;
- // TODO: b/293371537 - Maybe expose whether this SkiaGpuContext is using Ganesh or Graphite?
/**
* Only callable on Ganesh-backed instances of SkiaGpuContext, otherwise fatal.
*/
@@ -56,6 +60,20 @@
LOG_ALWAYS_FATAL("grDirectContext() called on a non-Ganesh instance of SkiaGpuContext!");
}
+ /**
+ * Only callable on Graphite-backed instances of SkiaGpuContext, otherwise fatal.
+ */
+ virtual std::shared_ptr<skgpu::graphite::Context> graphiteContext() {
+ LOG_ALWAYS_FATAL("graphiteContext() called on a non-Graphite instance of SkiaGpuContext!");
+ }
+
+ /**
+ * Only callable on Graphite-backed instances of SkiaGpuContext, otherwise fatal.
+ */
+ virtual std::shared_ptr<skgpu::graphite::Recorder> graphiteRecorder() {
+ LOG_ALWAYS_FATAL("graphiteRecorder() called on a non-Graphite instance of SkiaGpuContext!");
+ }
+
virtual std::unique_ptr<SkiaBackendTexture> makeBackendTexture(AHardwareBuffer* buffer,
bool isOutputBuffer) = 0;
diff --git a/libs/renderengine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp
index 3a07205..4bd0852 100644
--- a/libs/renderengine/tests/RenderEngineTest.cpp
+++ b/libs/renderengine/tests/RenderEngineTest.cpp
@@ -107,6 +107,7 @@
virtual std::string name() = 0;
virtual renderengine::RenderEngine::GraphicsApi graphicsApi() = 0;
+ virtual renderengine::RenderEngine::SkiaBackend skiaBackend() = 0;
bool apiSupported() { return renderengine::RenderEngine::canSupport(graphicsApi()); }
std::unique_ptr<renderengine::RenderEngine> createRenderEngine() {
renderengine::RenderEngineCreationArgs reCreationArgs =
@@ -119,20 +120,12 @@
.setContextPriority(renderengine::RenderEngine::ContextPriority::MEDIUM)
.setThreaded(renderengine::RenderEngine::Threaded::NO)
.setGraphicsApi(graphicsApi())
+ .setSkiaBackend(skiaBackend())
.build();
return renderengine::RenderEngine::create(reCreationArgs);
}
};
-class SkiaVkRenderEngineFactory : public RenderEngineFactory {
-public:
- std::string name() override { return "SkiaVkRenderEngineFactory"; }
-
- renderengine::RenderEngine::GraphicsApi graphicsApi() override {
- return renderengine::RenderEngine::GraphicsApi::VK;
- }
-};
-
class SkiaGLESRenderEngineFactory : public RenderEngineFactory {
public:
std::string name() override { return "SkiaGLRenderEngineFactory"; }
@@ -140,6 +133,36 @@
renderengine::RenderEngine::GraphicsApi graphicsApi() {
return renderengine::RenderEngine::GraphicsApi::GL;
}
+
+ renderengine::RenderEngine::SkiaBackend skiaBackend() override {
+ return renderengine::RenderEngine::SkiaBackend::GANESH;
+ }
+};
+
+class GaneshVkRenderEngineFactory : public RenderEngineFactory {
+public:
+ std::string name() override { return "GaneshVkRenderEngineFactory"; }
+
+ renderengine::RenderEngine::GraphicsApi graphicsApi() override {
+ return renderengine::RenderEngine::GraphicsApi::VK;
+ }
+
+ renderengine::RenderEngine::SkiaBackend skiaBackend() override {
+ return renderengine::RenderEngine::SkiaBackend::GANESH;
+ }
+};
+
+class GraphiteVkRenderEngineFactory : public RenderEngineFactory {
+public:
+ std::string name() override { return "GraphiteVkRenderEngineFactory"; }
+
+ renderengine::RenderEngine::GraphicsApi graphicsApi() override {
+ return renderengine::RenderEngine::GraphicsApi::VK;
+ }
+
+ renderengine::RenderEngine::SkiaBackend skiaBackend() override {
+ return renderengine::RenderEngine::SkiaBackend::GRAPHITE;
+ }
};
class RenderEngineTest : public ::testing::TestWithParam<std::shared_ptr<RenderEngineFactory>> {
@@ -1471,7 +1494,8 @@
INSTANTIATE_TEST_SUITE_P(PerRenderEngineType, RenderEngineTest,
testing::Values(std::make_shared<SkiaGLESRenderEngineFactory>(),
- std::make_shared<SkiaVkRenderEngineFactory>()));
+ std::make_shared<GaneshVkRenderEngineFactory>(),
+ std::make_shared<GraphiteVkRenderEngineFactory>()));
TEST_P(RenderEngineTest, drawLayers_noLayersToDraw) {
if (!GetParam()->apiSupported()) {
@@ -1663,6 +1687,11 @@
}
TEST_P(RenderEngineTest, drawLayers_fillBufferColorTransform_outputDataspace) {
+ // TODO: b/331445583 - Fix in Graphite and re-enable.
+ if (GetParam()->skiaBackend() == renderengine::RenderEngine::SkiaBackend::GRAPHITE) {
+ GTEST_SKIP();
+ }
+
const auto& renderEngineFactory = GetParam();
// skip for non color management
if (!renderEngineFactory->apiSupported()) {
@@ -1813,6 +1842,11 @@
}
TEST_P(RenderEngineTest, drawLayers_fillBufferColorTransformAndOutputDataspace_opaqueBufferSource) {
+ // TODO: b/331447131 - Fix in Graphite and re-enable.
+ if (GetParam()->skiaBackend() == renderengine::RenderEngine::SkiaBackend::GRAPHITE) {
+ GTEST_SKIP();
+ }
+
const auto& renderEngineFactory = GetParam();
// skip for non color management
if (!renderEngineFactory->apiSupported()) {
@@ -1963,6 +1997,11 @@
}
TEST_P(RenderEngineTest, drawLayers_fillBufferColorTransformAndOutputDataspace_bufferSource) {
+ // TODO: b/331446495 - Fix in Graphite and re-enable.
+ if (GetParam()->skiaBackend() == renderengine::RenderEngine::SkiaBackend::GRAPHITE) {
+ GTEST_SKIP();
+ }
+
const auto& renderEngineFactory = GetParam();
// skip for non color management
if (!renderEngineFactory->apiSupported()) {
@@ -2022,6 +2061,11 @@
}
TEST_P(RenderEngineTest, drawLayers_fillBuffer_premultipliesAlpha) {
+ // TODO: b/331446496 - Fix in Graphite and re-enable.
+ if (GetParam()->skiaBackend() == renderengine::RenderEngine::SkiaBackend::GRAPHITE) {
+ GTEST_SKIP();
+ }
+
if (!GetParam()->apiSupported()) {
GTEST_SKIP();
}
@@ -3102,6 +3146,11 @@
}
TEST_P(RenderEngineTest, primeShaderCache) {
+ // TODO: b/331447071 - Fix in Graphite and re-enable.
+ if (GetParam()->skiaBackend() == renderengine::RenderEngine::SkiaBackend::GRAPHITE) {
+ GTEST_SKIP();
+ }
+
if (!GetParam()->apiSupported()) {
GTEST_SKIP();
}
diff --git a/libs/sensor/Android.bp b/libs/sensor/Android.bp
index cc92bc3..7fa47b4 100644
--- a/libs/sensor/Android.bp
+++ b/libs/sensor/Android.bp
@@ -24,6 +24,7 @@
aconfig_declarations {
name: "libsensor_flags",
package: "com.android.hardware.libsensor.flags",
+ container: "system",
srcs: ["libsensor_flags.aconfig"],
}
diff --git a/libs/sensor/libsensor_flags.aconfig b/libs/sensor/libsensor_flags.aconfig
index ef4d737..c511f4a 100644
--- a/libs/sensor/libsensor_flags.aconfig
+++ b/libs/sensor/libsensor_flags.aconfig
@@ -1,4 +1,5 @@
package: "com.android.hardware.libsensor.flags"
+container: "system"
flag {
name: "sensormanager_ping_binder"
@@ -6,4 +7,4 @@
description: "Whether to pingBinder on SensorManager init"
bug: "322228259"
is_fixed_read_only: true
-}
\ No newline at end of file
+}
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index cf94f94..4164dc5 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -793,6 +793,8 @@
char prop[PROPERTY_VALUE_MAX];
property_get(PROPERTY_DEBUG_RENDERENGINE_BACKEND, prop, "");
+ // TODO: b/293371537 - Once GraphiteVk is deemed relatively stable, log a warning that
+ // PROPERTY_DEBUG_RENDERENGINE_BACKEND is deprecated
if (strcmp(prop, "skiagl") == 0) {
builder.setThreaded(renderengine::RenderEngine::Threaded::NO)
.setGraphicsApi(renderengine::RenderEngine::GraphicsApi::GL);
@@ -807,8 +809,14 @@
.setGraphicsApi(renderengine::RenderEngine::GraphicsApi::VK);
} else {
const auto kVulkan = renderengine::RenderEngine::GraphicsApi::VK;
- const bool useVulkan = FlagManager::getInstance().vulkan_renderengine() &&
- renderengine::RenderEngine::canSupport(kVulkan);
+ const bool canSupportVulkan = renderengine::RenderEngine::canSupport(kVulkan);
+ const bool useGraphite =
+ canSupportVulkan && FlagManager::getInstance().graphite_renderengine();
+ const bool useVulkan = useGraphite ||
+ (canSupportVulkan && FlagManager::getInstance().vulkan_renderengine());
+
+ builder.setSkiaBackend(useGraphite ? renderengine::RenderEngine::SkiaBackend::GRAPHITE
+ : renderengine::RenderEngine::SkiaBackend::GANESH);
builder.setGraphicsApi(useVulkan ? kVulkan : renderengine::RenderEngine::GraphicsApi::GL);
}
}
diff --git a/services/surfaceflinger/common/FlagManager.cpp b/services/surfaceflinger/common/FlagManager.cpp
index 6507aba..d9334d6 100644
--- a/services/surfaceflinger/common/FlagManager.cpp
+++ b/services/surfaceflinger/common/FlagManager.cpp
@@ -139,6 +139,7 @@
DUMP_READ_ONLY_FLAG(protected_if_client);
DUMP_READ_ONLY_FLAG(ce_fence_promise);
DUMP_READ_ONLY_FLAG(idle_screen_refresh_rate_timeout);
+ DUMP_READ_ONLY_FLAG(graphite_renderengine);
#undef DUMP_READ_ONLY_FLAG
#undef DUMP_SERVER_FLAG
#undef DUMP_FLAG_INTERVAL
@@ -227,6 +228,7 @@
FLAG_MANAGER_READ_ONLY_FLAG(dont_skip_on_early_ro, "")
FLAG_MANAGER_READ_ONLY_FLAG(protected_if_client, "")
FLAG_MANAGER_READ_ONLY_FLAG(ce_fence_promise, "");
+FLAG_MANAGER_READ_ONLY_FLAG(graphite_renderengine, "debug.renderengine.graphite")
/// Trunk stable server flags ///
FLAG_MANAGER_SERVER_FLAG(refresh_rate_overlay_on_external_display, "")
diff --git a/services/surfaceflinger/common/include/common/FlagManager.h b/services/surfaceflinger/common/include/common/FlagManager.h
index 964943c..819e587 100644
--- a/services/surfaceflinger/common/include/common/FlagManager.h
+++ b/services/surfaceflinger/common/include/common/FlagManager.h
@@ -77,6 +77,7 @@
bool protected_if_client() const;
bool ce_fence_promise() const;
bool idle_screen_refresh_rate_timeout() const;
+ bool graphite_renderengine() const;
protected:
// overridden for unit tests
diff --git a/services/vibratorservice/TEST_MAPPING b/services/vibratorservice/TEST_MAPPING
index 63a2bd0..81c37b0 100644
--- a/services/vibratorservice/TEST_MAPPING
+++ b/services/vibratorservice/TEST_MAPPING
@@ -3,9 +3,13 @@
{
"name": "libvibratorservice_test",
"options": [
- // TODO(b/293603710): Fix flakiness
{
+ // TODO(b/293603710): Fix flakiness
"exclude-filter": "VibratorCallbackSchedulerTest#TestScheduleRunsOnlyAfterDelay"
+ },
+ {
+ // TODO(b/293623689): Fix flakiness
+ "exclude-filter": "VibratorCallbackSchedulerTest#TestScheduleMultipleCallbacksRunsInDelayOrder"
}
]
}