Merge "VR: Rename HIDL service name from vr_hwcomposer to vr"
diff --git a/include/ui/ColorSpace.h b/include/ui/ColorSpace.h
index 8c4acb7..8ccf6d3 100644
--- a/include/ui/ColorSpace.h
+++ b/include/ui/ColorSpace.h
@@ -35,6 +35,16 @@
typedef std::function<float(float)> transfer_function;
typedef std::function<float(float)> clamping_function;
+ struct TransferParameters {
+ float g = 0.0f;
+ float a = 0.0f;
+ float b = 0.0f;
+ float c = 0.0f;
+ float d = 0.0f;
+ float e = 0.0f;
+ float f = 0.0f;
+ };
+
/**
* Creates a named color space with the specified RGB->XYZ
* conversion matrix. The white point and primaries will be
@@ -47,8 +57,39 @@
ColorSpace(
const std::string& name,
const mat3& rgbToXYZ,
- transfer_function OETF = linearReponse,
- transfer_function EOTF = linearReponse,
+ transfer_function OETF = linearResponse,
+ transfer_function EOTF = linearResponse,
+ clamping_function clamper = saturate<float>
+ ) noexcept;
+
+ /**
+ * Creates a named color space with the specified RGB->XYZ
+ * conversion matrix. The white point and primaries will be
+ * computed from the supplied matrix.
+ *
+ * The transfer functions are defined by the set of supplied
+ * transfer parameters. The default clamping function is a
+ * simple saturate (clamp(x, 0, 1)).
+ */
+ ColorSpace(
+ const std::string& name,
+ const mat3& rgbToXYZ,
+ const TransferParameters parameters,
+ clamping_function clamper = saturate<float>
+ ) noexcept;
+
+ /**
+ * Creates a named color space with the specified RGB->XYZ
+ * conversion matrix. The white point and primaries will be
+ * computed from the supplied matrix.
+ *
+ * The transfer functions are defined by a simple gamma value.
+ * The default clamping function is a saturate (clamp(x, 0, 1)).
+ */
+ ColorSpace(
+ const std::string& name,
+ const mat3& rgbToXYZ,
+ float gamma,
clamping_function clamper = saturate<float>
) noexcept;
@@ -65,8 +106,41 @@
const std::string& name,
const std::array<float2, 3>& primaries,
const float2& whitePoint,
- transfer_function OETF = linearReponse,
- transfer_function EOTF = linearReponse,
+ transfer_function OETF = linearResponse,
+ transfer_function EOTF = linearResponse,
+ clamping_function clamper = saturate<float>
+ ) noexcept;
+
+ /**
+ * Creates a named color space with the specified primaries
+ * and white point. The RGB<>XYZ conversion matrices are
+ * computed from the primaries and white point.
+ *
+ * The transfer functions are defined by the set of supplied
+ * transfer parameters. The default clamping function is a
+ * simple saturate (clamp(x, 0, 1)).
+ */
+ ColorSpace(
+ const std::string& name,
+ const std::array<float2, 3>& primaries,
+ const float2& whitePoint,
+ const TransferParameters parameters,
+ clamping_function clamper = saturate<float>
+ ) noexcept;
+
+ /**
+ * Creates a named color space with the specified primaries
+ * and white point. The RGB<>XYZ conversion matrices are
+ * computed from the primaries and white point.
+ *
+ * The transfer functions are defined by a single gamma value.
+ * The default clamping function is a saturate (clamp(x, 0, 1)).
+ */
+ ColorSpace(
+ const std::string& name,
+ const std::array<float2, 3>& primaries,
+ const float2& whitePoint,
+ float gamma,
clamping_function clamper = saturate<float>
) noexcept;
@@ -138,6 +212,10 @@
return mWhitePoint;
}
+ constexpr const TransferParameters& getTransferParameters() const noexcept {
+ return mParameters;
+ }
+
/**
* Converts the supplied XYZ value to xyY.
*/
@@ -166,35 +244,6 @@
static const ColorSpace ACES();
static const ColorSpace ACEScg();
- class Connector {
- public:
- Connector(const ColorSpace& src, const ColorSpace& dst) noexcept;
-
- constexpr const ColorSpace& getSource() const noexcept { return mSource; }
- constexpr const ColorSpace& getDestination() const noexcept { return mDestination; }
-
- constexpr const mat3& getTransform() const noexcept { return mTransform; }
-
- constexpr float3 transform(const float3& v) const noexcept {
- float3 linear = mSource.toLinear(apply(v, mSource.getClamper()));
- return apply(mDestination.fromLinear(mTransform * linear), mDestination.getClamper());
- }
-
- constexpr float3 transformLinear(const float3& v) const noexcept {
- float3 linear = apply(v, mSource.getClamper());
- return apply(mTransform * linear, mDestination.getClamper());
- }
-
- private:
- const ColorSpace& mSource;
- const ColorSpace& mDestination;
- mat3 mTransform;
- };
-
- static const Connector connect(const ColorSpace& src, const ColorSpace& dst) {
- return Connector(src, dst);
- }
-
// Creates a NxNxN 3D LUT, where N is the specified size (min=2, max=256)
// The 3D lookup coordinates map to the RGB components: u=R, v=G, w=B
// The generated 3D LUT is meant to be used as a 3D texture and its Y
@@ -208,7 +257,7 @@
static constexpr mat3 computeXYZMatrix(
const std::array<float2, 3>& primaries, const float2& whitePoint);
- static constexpr float linearReponse(float v) {
+ static constexpr float linearResponse(float v) {
return v;
}
@@ -217,6 +266,7 @@
mat3 mRGBtoXYZ;
mat3 mXYZtoRGB;
+ TransferParameters mParameters;
transfer_function mOETF;
transfer_function mEOTF;
clamping_function mClamper;
@@ -225,6 +275,31 @@
float2 mWhitePoint;
};
+class ColorSpaceConnector {
+public:
+ ColorSpaceConnector(const ColorSpace& src, const ColorSpace& dst) noexcept;
+
+ constexpr const ColorSpace& getSource() const noexcept { return mSource; }
+ constexpr const ColorSpace& getDestination() const noexcept { return mDestination; }
+
+ constexpr const mat3& getTransform() const noexcept { return mTransform; }
+
+ constexpr float3 transform(const float3& v) const noexcept {
+ float3 linear = mSource.toLinear(apply(v, mSource.getClamper()));
+ return apply(mDestination.fromLinear(mTransform * linear), mDestination.getClamper());
+ }
+
+ constexpr float3 transformLinear(const float3& v) const noexcept {
+ float3 linear = apply(v, mSource.getClamper());
+ return apply(mTransform * linear, mDestination.getClamper());
+ }
+
+private:
+ ColorSpace mSource;
+ ColorSpace mDestination;
+ mat3 mTransform;
+};
+
}; // namespace android
#endif // ANDROID_UI_COLOR_SPACE
diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp
index 0dc4469..327ecad 100644
--- a/libs/binder/tests/Android.bp
+++ b/libs/binder/tests/Android.bp
@@ -70,3 +70,13 @@
"libbase",
],
}
+
+cc_test {
+ name: "schd-dbg",
+ srcs: ["schd-dbg.cpp"],
+ shared_libs: [
+ "libbinder",
+ "libutils",
+ "libbase",
+ ],
+}
diff --git a/libs/binder/tests/schd-dbg.cpp b/libs/binder/tests/schd-dbg.cpp
new file mode 100644
index 0000000..2732071
--- /dev/null
+++ b/libs/binder/tests/schd-dbg.cpp
@@ -0,0 +1,426 @@
+#include <binder/Binder.h>
+#include <binder/IBinder.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <string>
+
+#include <iomanip>
+#include <iostream>
+#include <tuple>
+#include <vector>
+
+#include <pthread.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+using namespace std;
+using namespace android;
+
+enum BinderWorkerServiceCode {
+ BINDER_NOP = IBinder::FIRST_CALL_TRANSACTION,
+};
+
+#define ASSERT(cond) \
+ do { \
+ if (!(cond)) { \
+ cerr << __func__ << ":" << __LINE__ << " condition:" << #cond \
+ << " failed\n" \
+ << endl; \
+ exit(EXIT_FAILURE); \
+ } \
+ } while (0)
+
+vector<sp<IBinder> > workers;
+
+// the ratio that the service is synced on the same cpu beyond
+// GOOD_SYNC_MIN is considered as good
+#define GOOD_SYNC_MIN (0.6)
+
+#define DUMP_PRICISION 3
+
+// the default value
+int no_process = 2;
+int iterations = 100;
+int payload_size = 16;
+int no_inherent = 0;
+int no_sync = 0;
+int verbose = 0;
+
+// the deadline latency that we are interested in
+uint64_t deadline_us = 2500;
+
+int thread_pri() {
+ struct sched_param param;
+ int policy;
+ ASSERT(!pthread_getschedparam(pthread_self(), &policy, ¶m));
+ return param.sched_priority;
+}
+
+void thread_dump(const char* prefix) {
+ struct sched_param param;
+ int policy;
+ if (!verbose) return;
+ cout << "--------------------------------------------------" << endl;
+ cout << setw(12) << left << prefix << " pid: " << getpid()
+ << " tid: " << gettid() << " cpu: " << sched_getcpu() << endl;
+ ASSERT(!pthread_getschedparam(pthread_self(), &policy, ¶m));
+ string s = (policy == SCHED_OTHER)
+ ? "SCHED_OTHER"
+ : (policy == SCHED_FIFO)
+ ? "SCHED_FIFO"
+ : (policy == SCHED_RR) ? "SCHED_RR" : "???";
+ cout << setw(12) << left << s << param.sched_priority << endl;
+ return;
+}
+
+class BinderWorkerService : public BBinder {
+ public:
+ BinderWorkerService() {
+ }
+ ~BinderWorkerService() {
+ }
+ virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+ uint32_t flags = 0) {
+ (void)flags;
+ (void)data;
+ (void)reply;
+ switch (code) {
+ // The transaction format is like
+ //
+ // data[in]: int32: caller priority
+ // int32: caller cpu
+ //
+ // reply[out]: int32: 1 if caller's priority != callee's priority
+ // int32: 1 if caller's cpu != callee's cpu
+ //
+ // note the caller cpu read here is not always correct
+ // there're still chances that the caller got switched out
+ // right after it read the cpu number and still before the transaction.
+ case BINDER_NOP: {
+ thread_dump("binder");
+ int priority = thread_pri();
+ int priority_caller = data.readInt32();
+ int h = 0, s = 0;
+ if (priority_caller != priority) {
+ h++;
+ if (verbose) {
+ cout << "err priority_caller:" << priority_caller
+ << ", priority:" << priority << endl;
+ }
+ }
+ if (priority == sched_get_priority_max(SCHED_FIFO)) {
+ int cpu = sched_getcpu();
+ int cpu_caller = data.readInt32();
+ if (cpu != cpu_caller) {
+ s++;
+ }
+ }
+ reply->writeInt32(h);
+ reply->writeInt32(s);
+ return NO_ERROR;
+ }
+ default:
+ return UNKNOWN_TRANSACTION;
+ };
+ }
+};
+
+class Pipe {
+ int m_readFd;
+ int m_writeFd;
+ Pipe(int readFd, int writeFd) : m_readFd{readFd}, m_writeFd{writeFd} {
+ }
+ Pipe(const Pipe&) = delete;
+ Pipe& operator=(const Pipe&) = delete;
+ Pipe& operator=(const Pipe&&) = delete;
+
+ public:
+ Pipe(Pipe&& rval) noexcept {
+ m_readFd = rval.m_readFd;
+ m_writeFd = rval.m_writeFd;
+ rval.m_readFd = 0;
+ rval.m_writeFd = 0;
+ }
+ ~Pipe() {
+ if (m_readFd) close(m_readFd);
+ if (m_writeFd) close(m_writeFd);
+ }
+ void signal() {
+ bool val = true;
+ int error = write(m_writeFd, &val, sizeof(val));
+ ASSERT(error >= 0);
+ };
+ void wait() {
+ bool val = false;
+ int error = read(m_readFd, &val, sizeof(val));
+ ASSERT(error >= 0);
+ }
+ template <typename T>
+ void send(const T& v) {
+ int error = write(m_writeFd, &v, sizeof(T));
+ ASSERT(error >= 0);
+ }
+ template <typename T>
+ void recv(T& v) {
+ int error = read(m_readFd, &v, sizeof(T));
+ ASSERT(error >= 0);
+ }
+ static tuple<Pipe, Pipe> createPipePair() {
+ int a[2];
+ int b[2];
+
+ int error1 = pipe(a);
+ int error2 = pipe(b);
+ ASSERT(error1 >= 0);
+ ASSERT(error2 >= 0);
+
+ return make_tuple(Pipe(a[0], b[1]), Pipe(b[0], a[1]));
+ }
+};
+
+typedef chrono::time_point<chrono::high_resolution_clock> Tick;
+
+static inline Tick tickNow() {
+ return chrono::high_resolution_clock::now();
+}
+
+static inline uint64_t tickNano(Tick& sta, Tick& end) {
+ return uint64_t(chrono::duration_cast<chrono::nanoseconds>(end - sta).count());
+}
+
+struct Results {
+ uint64_t m_best = 0xffffffffffffffffULL;
+ uint64_t m_worst = 0;
+ uint64_t m_transactions = 0;
+ uint64_t m_total_time = 0;
+ uint64_t m_miss = 0;
+
+ void add_time(uint64_t nano) {
+ m_best = min(nano, m_best);
+ m_worst = max(nano, m_worst);
+ m_transactions += 1;
+ m_total_time += nano;
+ if (nano > deadline_us * 1000) m_miss++;
+ }
+ void dump() {
+ double best = (double)m_best / 1.0E6;
+ double worst = (double)m_worst / 1.0E6;
+ double average = (double)m_total_time / m_transactions / 1.0E6;
+ // FIXME: libjson?
+ cout << std::setprecision(DUMP_PRICISION) << "{ \"avg\":" << setw(5) << left
+ << average << ", \"wst\":" << setw(5) << left << worst
+ << ", \"bst\":" << setw(5) << left << best << ", \"miss\":" << m_miss
+ << "}";
+ }
+};
+
+String16 generateServiceName(int num) {
+ char num_str[32];
+ snprintf(num_str, sizeof(num_str), "%d", num);
+ String16 serviceName = String16("binderWorker") + String16(num_str);
+ return serviceName;
+}
+
+static void parcel_fill(Parcel& data, int sz, int priority, int cpu) {
+ ASSERT(sz >= (int)sizeof(uint32_t) * 2);
+ data.writeInt32(priority);
+ data.writeInt32(cpu);
+ sz -= sizeof(uint32_t);
+ while (sz > (int)sizeof(uint32_t)) {
+ data.writeInt32(0);
+ sz -= sizeof(uint32_t);
+ }
+}
+
+static void* thread_start(void* p) {
+ Results* results_fifo = (Results*)p;
+ Parcel data, reply;
+ Tick sta, end;
+
+ parcel_fill(data, payload_size, thread_pri(), sched_getcpu());
+ thread_dump("fifo-caller");
+
+ sta = tickNow();
+ status_t ret = workers[0]->transact(BINDER_NOP, data, &reply);
+ end = tickNow();
+ results_fifo->add_time(tickNano(sta, end));
+
+ no_inherent += reply.readInt32();
+ no_sync += reply.readInt32();
+ return 0;
+}
+
+// create a fifo thread to transact and wait it to finished
+static void thread_transaction(Results* results_fifo) {
+ void* dummy;
+ pthread_t thread;
+ pthread_attr_t attr;
+ struct sched_param param;
+ ASSERT(!pthread_attr_init(&attr));
+ ASSERT(!pthread_attr_setschedpolicy(&attr, SCHED_FIFO));
+ param.sched_priority = sched_get_priority_max(SCHED_FIFO);
+ ASSERT(!pthread_attr_setschedparam(&attr, ¶m));
+ ASSERT(!pthread_create(&thread, &attr, &thread_start, results_fifo));
+ ASSERT(!pthread_join(thread, &dummy));
+}
+
+#define is_client(_num) ((_num) >= (no_process / 2))
+
+void worker_fx(int num, int no_process, int iterations, int payload_size,
+ Pipe p) {
+ int dummy;
+ Results results_other, results_fifo;
+
+ // Create BinderWorkerService and for go.
+ ProcessState::self()->startThreadPool();
+ sp<IServiceManager> serviceMgr = defaultServiceManager();
+ sp<BinderWorkerService> service = new BinderWorkerService;
+ serviceMgr->addService(generateServiceName(num), service);
+ p.signal();
+ p.wait();
+
+ // If client/server pairs, then half the workers are
+ // servers and half are clients
+ int server_count = no_process / 2;
+
+ for (int i = 0; i < server_count; i++) {
+ // self service is in-process so just skip
+ if (num == i) continue;
+ workers.push_back(serviceMgr->getService(generateServiceName(i)));
+ }
+
+ // Client for each pair iterates here
+ // each iterations contains exatcly 2 transactions
+ for (int i = 0; is_client(num) && i < iterations; i++) {
+ Parcel data, reply;
+ Tick sta, end;
+ // the target is paired to make it easier to diagnose
+ int target = num % server_count;
+
+ // 1. transaction by fifo thread
+ thread_transaction(&results_fifo);
+ parcel_fill(data, payload_size, thread_pri(), sched_getcpu());
+ thread_dump("other-caller");
+
+ // 2. transaction by other thread
+ sta = tickNow();
+ ASSERT(NO_ERROR == workers[target]->transact(BINDER_NOP, data, &reply));
+ end = tickNow();
+ results_other.add_time(tickNano(sta, end));
+
+ no_inherent += reply.readInt32();
+ no_sync += reply.readInt32();
+ }
+ // Signal completion to master and wait.
+ p.signal();
+ p.wait();
+
+ p.send(&dummy);
+ p.wait();
+ // Client for each pair dump here
+ if (is_client(num)) {
+ int no_trans = iterations * 2;
+ double sync_ratio = (1.0 - (double)no_sync / no_trans);
+ // FIXME: libjson?
+ cout << "\"P" << (num - server_count) << "\":{\"SYNC\":\""
+ << ((sync_ratio > GOOD_SYNC_MIN) ? "GOOD" : "POOR") << "\","
+ << "\"S\":" << (no_trans - no_sync) << ",\"I\":" << no_trans << ","
+ << "\"R\":" << sync_ratio << "," << endl;
+
+ cout << " \"other_ms\":";
+ results_other.dump();
+ cout << "," << endl;
+ cout << " \"fifo_ms\": ";
+ results_fifo.dump();
+ cout << endl;
+ cout << "}," << endl;
+ }
+ exit(no_inherent);
+}
+
+Pipe make_process(int num, int iterations, int no_process, int payload_size) {
+ auto pipe_pair = Pipe::createPipePair();
+ pid_t pid = fork();
+ if (pid) {
+ // parent
+ return move(get<0>(pipe_pair));
+ } else {
+ // child
+ thread_dump(is_client(num) ? "client" : "server");
+ worker_fx(num, no_process, iterations, payload_size,
+ move(get<1>(pipe_pair)));
+ // never get here
+ return move(get<0>(pipe_pair));
+ }
+}
+
+void wait_all(vector<Pipe>& v) {
+ for (size_t i = 0; i < v.size(); i++) {
+ v[i].wait();
+ }
+}
+
+void signal_all(vector<Pipe>& v) {
+ for (size_t i = 0; i < v.size(); i++) {
+ v[i].signal();
+ }
+}
+
+// This test is modified from binderThroughputTest.cpp
+int main(int argc, char** argv) {
+ for (int i = 1; i < argc; i++) {
+ if (string(argv[i]) == "-i") {
+ iterations = atoi(argv[i + 1]);
+ i++;
+ continue;
+ }
+ if (string(argv[i]) == "-pair") {
+ no_process = 2 * atoi(argv[i + 1]);
+ i++;
+ continue;
+ }
+ if (string(argv[i]) == "-deadline_us") {
+ deadline_us = atoi(argv[i + 1]);
+ i++;
+ continue;
+ }
+ if (string(argv[i]) == "-v") {
+ verbose = 1;
+ i++;
+ }
+ }
+ vector<Pipe> pipes;
+ thread_dump("main");
+ // FIXME: libjson?
+ cout << "{" << endl;
+ cout << "\"cfg\":{\"pair\":" << (no_process / 2)
+ << ",\"iterations\":" << iterations << ",\"deadline_us\":" << deadline_us
+ << "}," << endl;
+
+ // the main process fork 2 processes for each pairs
+ // 1 server + 1 client
+ // each has a pipe to communicate with
+ for (int i = 0; i < no_process; i++) {
+ pipes.push_back(make_process(i, iterations, no_process, payload_size));
+ }
+ wait_all(pipes);
+ signal_all(pipes);
+ wait_all(pipes);
+ signal_all(pipes);
+ for (int i = 0; i < no_process; i++) {
+ int status;
+ pipes[i].signal();
+ wait(&status);
+ // the exit status is number of transactions without priority inheritance
+ // detected in the child process
+ no_inherent += status;
+ }
+ // FIXME: libjson?
+ cout << "\"inheritance\": " << (no_inherent == 0 ? "\"PASS\"" : "\"FAIL\"")
+ << endl;
+ cout << "}" << endl;
+ return -no_inherent;
+}
diff --git a/libs/ui/ColorSpace.cpp b/libs/ui/ColorSpace.cpp
index 49390d9..5b4bf23 100644
--- a/libs/ui/ColorSpace.cpp
+++ b/libs/ui/ColorSpace.cpp
@@ -20,6 +20,83 @@
namespace android {
+static constexpr float linearResponse(float v) {
+ return v;
+}
+
+static constexpr float rcpResponse(float x, const ColorSpace::TransferParameters& p) {
+ return x >= p.d * p.c ? (std::pow(x, 1.0f / p.g) - p.b) / p.a : x / p.c;
+}
+
+static constexpr float response(float x, const ColorSpace::TransferParameters& p) {
+ return x >= p.d ? std::pow(p.a * x + p.b, p.g) : p.c * x;
+}
+
+static constexpr float rcpFullResponse(float x, const ColorSpace::TransferParameters& p) {
+ return x >= p.d * p.c ? (std::pow(x - p.e, 1.0f / p.g) - p.b) / p.a : (x - p.f) / p.c;
+}
+
+static constexpr float fullResponse(float x, const ColorSpace::TransferParameters& p) {
+ return x >= p.d ? std::pow(p.a * x + p.b, p.g) + p.e : p.c * x + p.f;
+}
+
+static float absRcpResponse(float x, float g,float a, float b, float c, float d) {
+ float xx = std::abs(x);
+ return std::copysign(xx >= d * c ? (std::pow(xx, 1.0f / g) - b) / a : xx / c, x);
+}
+
+static float absResponse(float x, float g, float a, float b, float c, float d) {
+ float xx = std::abs(x);
+ return std::copysign(xx >= d ? std::pow(a * xx + b, g) : c * xx, x);
+}
+
+static float safePow(float x, float e) {
+ return powf(x < 0.0f ? 0.0f : x, e);
+}
+
+static ColorSpace::transfer_function toOETF(const ColorSpace::TransferParameters& parameters) {
+ if (parameters.e == 0.0f && parameters.f == 0.0f) {
+ return std::bind(rcpResponse, _1, parameters);
+ }
+ return std::bind(rcpFullResponse, _1, parameters);
+}
+
+static ColorSpace::transfer_function toEOTF( const ColorSpace::TransferParameters& parameters) {
+ if (parameters.e == 0.0f && parameters.f == 0.0f) {
+ return std::bind(response, _1, parameters);
+ }
+ return std::bind(fullResponse, _1, parameters);
+}
+
+static ColorSpace::transfer_function toOETF(float gamma) {
+ if (gamma == 1.0f) {
+ return linearResponse;
+ }
+ return std::bind(safePow, _1, 1.0f / gamma);
+}
+
+static ColorSpace::transfer_function toEOTF(float gamma) {
+ if (gamma == 1.0f) {
+ return linearResponse;
+ }
+ return std::bind(safePow, _1, gamma);
+}
+
+static constexpr std::array<float2, 3> computePrimaries(const mat3& rgbToXYZ) {
+ float3 r(rgbToXYZ * float3{1, 0, 0});
+ float3 g(rgbToXYZ * float3{0, 1, 0});
+ float3 b(rgbToXYZ * float3{0, 0, 1});
+
+ return {{r.xy / dot(r, float3{1}),
+ g.xy / dot(g, float3{1}),
+ b.xy / dot(b, float3{1})}};
+}
+
+static constexpr float2 computeWhitePoint(const mat3& rgbToXYZ) {
+ float3 w(rgbToXYZ * float3{1});
+ return w.xy / dot(w, float3{1});
+}
+
ColorSpace::ColorSpace(
const std::string& name,
const mat3& rgbToXYZ,
@@ -31,18 +108,41 @@
, mXYZtoRGB(inverse(rgbToXYZ))
, mOETF(std::move(OETF))
, mEOTF(std::move(EOTF))
- , mClamper(std::move(clamper)) {
+ , mClamper(std::move(clamper))
+ , mPrimaries(computePrimaries(rgbToXYZ))
+ , mWhitePoint(computeWhitePoint(rgbToXYZ)) {
+}
- float3 r(rgbToXYZ * float3{1, 0, 0});
- float3 g(rgbToXYZ * float3{0, 1, 0});
- float3 b(rgbToXYZ * float3{0, 0, 1});
+ColorSpace::ColorSpace(
+ const std::string& name,
+ const mat3& rgbToXYZ,
+ const TransferParameters parameters,
+ clamping_function clamper) noexcept
+ : mName(name)
+ , mRGBtoXYZ(rgbToXYZ)
+ , mXYZtoRGB(inverse(rgbToXYZ))
+ , mParameters(parameters)
+ , mOETF(toOETF(mParameters))
+ , mEOTF(toEOTF(mParameters))
+ , mClamper(std::move(clamper))
+ , mPrimaries(computePrimaries(rgbToXYZ))
+ , mWhitePoint(computeWhitePoint(rgbToXYZ)) {
+}
- mPrimaries[0] = r.xy / dot(r, float3{1});
- mPrimaries[1] = g.xy / dot(g, float3{1});
- mPrimaries[2] = b.xy / dot(b, float3{1});
-
- float3 w(rgbToXYZ * float3{1});
- mWhitePoint = w.xy / dot(w, float3{1});
+ColorSpace::ColorSpace(
+ const std::string& name,
+ const mat3& rgbToXYZ,
+ float gamma,
+ clamping_function clamper) noexcept
+ : mName(name)
+ , mRGBtoXYZ(rgbToXYZ)
+ , mXYZtoRGB(inverse(rgbToXYZ))
+ , mParameters({gamma, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f})
+ , mOETF(toOETF(gamma))
+ , mEOTF(toEOTF(gamma))
+ , mClamper(std::move(clamper))
+ , mPrimaries(computePrimaries(rgbToXYZ))
+ , mWhitePoint(computeWhitePoint(rgbToXYZ)) {
}
ColorSpace::ColorSpace(
@@ -62,6 +162,40 @@
, mWhitePoint(whitePoint) {
}
+ColorSpace::ColorSpace(
+ const std::string& name,
+ const std::array<float2, 3>& primaries,
+ const float2& whitePoint,
+ const TransferParameters parameters,
+ clamping_function clamper) noexcept
+ : mName(name)
+ , mRGBtoXYZ(computeXYZMatrix(primaries, whitePoint))
+ , mXYZtoRGB(inverse(mRGBtoXYZ))
+ , mParameters(parameters)
+ , mOETF(toOETF(mParameters))
+ , mEOTF(toEOTF(mParameters))
+ , mClamper(std::move(clamper))
+ , mPrimaries(primaries)
+ , mWhitePoint(whitePoint) {
+}
+
+ColorSpace::ColorSpace(
+ const std::string& name,
+ const std::array<float2, 3>& primaries,
+ const float2& whitePoint,
+ float gamma,
+ clamping_function clamper) noexcept
+ : mName(name)
+ , mRGBtoXYZ(computeXYZMatrix(primaries, whitePoint))
+ , mXYZtoRGB(inverse(mRGBtoXYZ))
+ , mParameters({gamma, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f})
+ , mOETF(toOETF(gamma))
+ , mEOTF(toEOTF(gamma))
+ , mClamper(std::move(clamper))
+ , mPrimaries(primaries)
+ , mWhitePoint(whitePoint) {
+}
+
constexpr mat3 ColorSpace::computeXYZMatrix(
const std::array<float2, 3>& primaries, const float2& whitePoint) {
const float2& R = primaries[0];
@@ -96,33 +230,12 @@
};
}
-static constexpr float rcpResponse(float x, float g,float a, float b, float c, float d) {
- return x >= d * c ? (std::pow(x, 1.0f / g) - b) / a : x / c;
-}
-
-static constexpr float response(float x, float g, float a, float b, float c, float d) {
- return x >= d ? std::pow(a * x + b, g) : c * x;
-}
-
-static float absRcpResponse(float x, float g,float a, float b, float c, float d) {
- return std::copysign(rcpResponse(std::abs(x), g, a, b, c, d), x);
-}
-
-static float absResponse(float x, float g, float a, float b, float c, float d) {
- return std::copysign(response(std::abs(x), g, a, b, c, d), x);
-}
-
-static float safePow(float x, float e) {
- return powf(x < 0.0f ? 0.0f : x, e);
-}
-
const ColorSpace ColorSpace::sRGB() {
return {
"sRGB IEC61966-2.1",
{{float2{0.640f, 0.330f}, {0.300f, 0.600f}, {0.150f, 0.060f}}},
{0.3127f, 0.3290f},
- std::bind(rcpResponse, _1, 2.4f, 1 / 1.055f, 0.055f / 1.055f, 1 / 12.92f, 0.04045f),
- std::bind(response, _1, 2.4f, 1 / 1.055f, 0.055f / 1.055f, 1 / 12.92f, 0.04045f)
+ {2.4f, 1 / 1.055f, 0.055f / 1.055f, 1 / 12.92f, 0.04045f, 0.0f, 0.0f}
};
}
@@ -150,8 +263,7 @@
"scRGB IEC 61966-2-2:2003",
{{float2{0.640f, 0.330f}, {0.300f, 0.600f}, {0.150f, 0.060f}}},
{0.3127f, 0.3290f},
- linearReponse,
- linearReponse,
+ 1.0f,
std::bind(clamp<float>, _1, -0.5f, 7.499f)
};
}
@@ -161,8 +273,7 @@
"NTSC (1953)",
{{float2{0.67f, 0.33f}, {0.21f, 0.71f}, {0.14f, 0.08f}}},
{0.310f, 0.316f},
- std::bind(rcpResponse, _1, 1 / 0.45f, 1 / 1.099f, 0.099f / 1.099f, 1 / 4.5f, 0.081f),
- std::bind(response, _1, 1 / 0.45f, 1 / 1.099f, 0.099f / 1.099f, 1 / 4.5f, 0.081f)
+ {1 / 0.45f, 1 / 1.099f, 0.099f / 1.099f, 1 / 4.5f, 0.081f, 0.0f, 0.0f}
};
}
@@ -171,8 +282,7 @@
"Rec. ITU-R BT.709-5",
{{float2{0.640f, 0.330f}, {0.300f, 0.600f}, {0.150f, 0.060f}}},
{0.3127f, 0.3290f},
- std::bind(rcpResponse, _1, 1 / 0.45f, 1 / 1.099f, 0.099f / 1.099f, 1 / 4.5f, 0.081f),
- std::bind(response, _1, 1 / 0.45f, 1 / 1.099f, 0.099f / 1.099f, 1 / 4.5f, 0.081f)
+ {1 / 0.45f, 1 / 1.099f, 0.099f / 1.099f, 1 / 4.5f, 0.081f, 0.0f, 0.0f}
};
}
@@ -181,8 +291,7 @@
"Rec. ITU-R BT.2020-1",
{{float2{0.708f, 0.292f}, {0.170f, 0.797f}, {0.131f, 0.046f}}},
{0.3127f, 0.3290f},
- std::bind(rcpResponse, _1, 1 / 0.45f, 1 / 1.099f, 0.099f / 1.099f, 1 / 4.5f, 0.081f),
- std::bind(response, _1, 1 / 0.45f, 1 / 1.099f, 0.099f / 1.099f, 1 / 4.5f, 0.081f)
+ {1 / 0.45f, 1 / 1.099f, 0.099f / 1.099f, 1 / 4.5f, 0.081f, 0.0f, 0.0f}
};
}
@@ -191,8 +300,7 @@
"Adobe RGB (1998)",
{{float2{0.64f, 0.33f}, {0.21f, 0.71f}, {0.15f, 0.06f}}},
{0.3127f, 0.3290f},
- std::bind(safePow, _1, 1.0f / 2.2f),
- std::bind(safePow, _1, 2.2f)
+ 2.2f
};
}
@@ -201,8 +309,7 @@
"ROMM RGB ISO 22028-2:2013",
{{float2{0.7347f, 0.2653f}, {0.1596f, 0.8404f}, {0.0366f, 0.0001f}}},
{0.34567f, 0.35850f},
- std::bind(rcpResponse, _1, 1.8f, 1.0f, 0.0f, 1 / 16.0f, 0.031248f),
- std::bind(response, _1, 1.8f, 1.0f, 0.0f, 1 / 16.0f, 0.031248f)
+ {1.8f, 1.0f, 0.0f, 1 / 16.0f, 0.031248f, 0.0f, 0.0f}
};
}
@@ -211,8 +318,7 @@
"Display P3",
{{float2{0.680f, 0.320f}, {0.265f, 0.690f}, {0.150f, 0.060f}}},
{0.3127f, 0.3290f},
- std::bind(rcpResponse, _1, 2.4f, 1 / 1.055f, 0.055f / 1.055f, 1 / 12.92f, 0.039f),
- std::bind(response, _1, 2.4f, 1 / 1.055f, 0.055f / 1.055f, 1 / 12.92f, 0.039f)
+ {2.4f, 1 / 1.055f, 0.055f / 1.055f, 1 / 12.92f, 0.039f, 0.0f, 0.0f}
};
}
@@ -221,8 +327,7 @@
"SMPTE RP 431-2-2007 DCI (P3)",
{{float2{0.680f, 0.320f}, {0.265f, 0.690f}, {0.150f, 0.060f}}},
{0.314f, 0.351f},
- std::bind(safePow, _1, 1.0f / 2.6f),
- std::bind(safePow, _1, 2.6f)
+ 2.6f
};
}
@@ -231,8 +336,7 @@
"SMPTE ST 2065-1:2012 ACES",
{{float2{0.73470f, 0.26530f}, {0.0f, 1.0f}, {0.00010f, -0.0770f}}},
{0.32168f, 0.33767f},
- linearReponse,
- linearReponse,
+ 1.0f,
std::bind(clamp<float>, _1, -65504.0f, 65504.0f)
};
}
@@ -242,12 +346,33 @@
"Academy S-2014-004 ACEScg",
{{float2{0.713f, 0.293f}, {0.165f, 0.830f}, {0.128f, 0.044f}}},
{0.32168f, 0.33767f},
- linearReponse,
- linearReponse,
+ 1.0f,
std::bind(clamp<float>, _1, -65504.0f, 65504.0f)
};
}
+std::unique_ptr<float3> ColorSpace::createLUT(uint32_t size,
+ const ColorSpace& src, const ColorSpace& dst) {
+
+ size = clamp(size, 2u, 256u);
+ float m = 1.0f / float(size - 1);
+
+ std::unique_ptr<float3> lut(new float3[size * size * size]);
+ float3* data = lut.get();
+
+ ColorSpaceConnector connector(src, dst);
+
+ for (uint32_t z = 0; z < size; z++) {
+ for (int32_t y = int32_t(size - 1); y >= 0; y--) {
+ for (uint32_t x = 0; x < size; x++) {
+ *data++ = connector.transform({x * m, y * m, z * m});
+ }
+ }
+ }
+
+ return lut;
+}
+
static const float2 ILLUMINANT_D50_XY = {0.34567f, 0.35850f};
static const float3 ILLUMINANT_D50_XYZ = {0.964212f, 1.0f, 0.825188f};
static const mat3 BRADFORD = mat3{
@@ -262,7 +387,7 @@
return inverse(matrix) * mat3{dstLMS / srcLMS} * matrix;
}
-ColorSpace::Connector::Connector(
+ColorSpaceConnector::ColorSpaceConnector(
const ColorSpace& src,
const ColorSpace& dst) noexcept
: mSource(src)
@@ -274,8 +399,8 @@
mat3 rgbToXYZ(src.getRGBtoXYZ());
mat3 xyzToRGB(dst.getXYZtoRGB());
- float3 srcXYZ = XYZ(float3{src.getWhitePoint(), 1});
- float3 dstXYZ = XYZ(float3{dst.getWhitePoint(), 1});
+ float3 srcXYZ = ColorSpace::XYZ(float3{src.getWhitePoint(), 1});
+ float3 dstXYZ = ColorSpace::XYZ(float3{dst.getWhitePoint(), 1});
if (any(greaterThan(abs(src.getWhitePoint() - ILLUMINANT_D50_XY), float2{1e-3f}))) {
rgbToXYZ = adaptation(BRADFORD, srcXYZ, ILLUMINANT_D50_XYZ) * src.getRGBtoXYZ();
@@ -289,27 +414,4 @@
}
}
-std::unique_ptr<float3> ColorSpace::createLUT(uint32_t size,
- const ColorSpace& src, const ColorSpace& dst) {
-
- size = clamp(size, 2u, 256u);
- float m = 1.0f / float(size - 1);
-
- std::unique_ptr<float3> lut(new float3[size * size * size]);
- float3* data = lut.get();
-
- Connector connector(src, dst);
-
- for (uint32_t z = 0; z < size; z++) {
- for (int32_t y = int32_t(size - 1); y >= 0; y--) {
- for (uint32_t x = 0; x < size; x++) {
- *data++ = connector.transform({x * m, y * m, z * m});
- }
- }
- }
-
- return lut;
-}
-
-
}; // namespace android
diff --git a/libs/ui/tests/colorspace_test.cpp b/libs/ui/tests/colorspace_test.cpp
index 1e359d3..0a4873c 100644
--- a/libs/ui/tests/colorspace_test.cpp
+++ b/libs/ui/tests/colorspace_test.cpp
@@ -152,12 +152,12 @@
TEST_F(ColorSpaceTest, Connect) {
// No chromatic adaptation
- auto r = ColorSpace::connect(ColorSpace::sRGB(), ColorSpace::AdobeRGB())
+ auto r = ColorSpaceConnector(ColorSpace::sRGB(), ColorSpace::AdobeRGB())
.transform({1.0f, 0.5f, 0.0f});
EXPECT_TRUE(all(lessThan(abs(r - float3{0.8912f, 0.4962f, 0.1164f}), float3{1e-4f})));
// Test with chromatic adaptation
- r = ColorSpace::connect(ColorSpace::sRGB(), ColorSpace::ProPhotoRGB())
+ r = ColorSpaceConnector(ColorSpace::sRGB(), ColorSpace::ProPhotoRGB())
.transform({1.0f, 0.0f, 0.0f});
EXPECT_TRUE(all(lessThan(abs(r - float3{0.70226f, 0.2757f, 0.1036f}), float3{1e-4f})));
}
diff --git a/libs/vr/libdvrcommon/Android.bp b/libs/vr/libdvrcommon/Android.bp
index 81404a4..eb78348 100644
--- a/libs/vr/libdvrcommon/Android.bp
+++ b/libs/vr/libdvrcommon/Android.bp
@@ -14,8 +14,6 @@
sourceFiles = [
"frame_time_history.cpp",
- "revision.cpp",
- "revision_path.cpp",
"sync_util.cpp",
]
diff --git a/libs/vr/libdvrcommon/include/private/dvr/revision.h b/libs/vr/libdvrcommon/include/private/dvr/revision.h
deleted file mode 100644
index dda0fce..0000000
--- a/libs/vr/libdvrcommon/include/private/dvr/revision.h
+++ /dev/null
@@ -1,47 +0,0 @@
-#ifndef LIBS_VR_LIBDVRCOMMON_INCLUDE_PRIVATE_DVR_REVISION_H_
-#define LIBS_VR_LIBDVRCOMMON_INCLUDE_PRIVATE_DVR_REVISION_H_
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-// List of DreamOS products
-typedef enum DvrProduct {
- DVR_PRODUCT_UNKNOWN,
- DVR_PRODUCT_A00,
- DVR_PRODUCT_A65R,
- DVR_PRODUCT_TWILIGHT = DVR_PRODUCT_A65R
-} DvrProduct;
-
-// List of possible revisions.
-typedef enum DvrRevision {
- DVR_REVISION_UNKNOWN,
- DVR_REVISION_P1,
- DVR_REVISION_P2,
- DVR_REVISION_P3,
-} DvrRevision;
-
-// Query the device's product.
-//
-// @return DvrProduct value, or DvrProductUnknown on error.
-DvrProduct dvr_get_product();
-
-// Query the device's revision.
-//
-// @return DvrRevision value, or DvrRevisionUnknown on error.
-DvrRevision dvr_get_revision();
-
-// Returns the device's board revision string.
-//
-// @return NULL-terminated string such as 'a00-p1'.
-const char* dvr_get_product_revision_str();
-
-// Returns the device's serial number.
-//
-// @return Returns NULL on error, or a NULL-terminated string.
-const char* dvr_get_serial_number();
-
-#ifdef __cplusplus
-}
-#endif // extern "C"
-#endif // LIBS_VR_LIBDVRCOMMON_INCLUDE_PRIVATE_DVR_REVISION_H_
diff --git a/libs/vr/libdvrcommon/revision.cpp b/libs/vr/libdvrcommon/revision.cpp
deleted file mode 100644
index 7925f65..0000000
--- a/libs/vr/libdvrcommon/revision.cpp
+++ /dev/null
@@ -1,175 +0,0 @@
-#include "private/dvr/revision.h"
-
-#include <errno.h>
-#include <fcntl.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/mman.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <log/log.h>
-
-#include "revision_path.h"
-
-namespace {
-
-// Allows quicker access to the product revision. If non-zero, then
-// the product revision file has already been processed.
-static bool global_product_revision_processed = false;
-
-static bool global_serial_number_processed = false;
-
-// The product.
-static DvrProduct global_product = DVR_PRODUCT_UNKNOWN;
-
-// The revision.
-static DvrRevision global_revision = DVR_REVISION_UNKNOWN;
-
-// Maximum size of the product revision string.
-constexpr int kProductRevisionStringSize = 32;
-
-// Maximum size of the serial number.
-constexpr int kSerialNumberStringSize = 32;
-
-// The product revision string.
-static char global_product_revision_str[kProductRevisionStringSize + 1] = "";
-
-// The serial number string
-static char global_serial_number[kSerialNumberStringSize + 1] = "";
-
-// Product and revision combinations.
-struct DvrProductRevision {
- const char* str;
- DvrProduct product;
- DvrRevision revision;
-};
-
-// Null-terminated list of all product and revision combinations.
-static constexpr DvrProductRevision kProductRevisions[] = {
- {"a00-p1", DVR_PRODUCT_A00, DVR_REVISION_P1},
- {"a00-p2", DVR_PRODUCT_A00, DVR_REVISION_P2},
- {"a00-p3", DVR_PRODUCT_A00, DVR_REVISION_P3},
- {"twilight-p1", DVR_PRODUCT_A65R, DVR_REVISION_P1},
- {"twilight-p2", DVR_PRODUCT_A65R, DVR_REVISION_P2},
- {NULL, DVR_PRODUCT_UNKNOWN, DVR_REVISION_UNKNOWN}};
-
-// Read the product revision string, and store the global data.
-static void process_product_revision() {
- int fd;
- ssize_t read_rc;
- const DvrProductRevision* product_revision = kProductRevisions;
-
- // Of course in a multi-threaded environment, for a few microseconds
- // during process startup, it is possible that this function will be
- // called and execute fully multiple times. That is why the product
- // revision string is statically allocated.
-
- if (global_product_revision_processed)
- return;
-
- // Whether there was a failure or not, we don't want to do this again.
- // Upon failure it's most likely to fail again anyway.
-
- fd = open(dvr_product_revision_file_path(), O_RDONLY);
- if (fd < 0) {
- ALOGE("Could not open '%s' to get product revision: %s",
- dvr_product_revision_file_path(), strerror(errno));
- global_product_revision_processed = true;
- return;
- }
-
- read_rc = read(fd, global_product_revision_str, kProductRevisionStringSize);
- if (read_rc <= 0) {
- ALOGE("Could not read from '%s': %s", dvr_product_revision_file_path(),
- strerror(errno));
- global_product_revision_processed = true;
- return;
- }
-
- close(fd);
-
- global_product_revision_str[read_rc] = '\0';
-
- while (product_revision->str) {
- if (!strcmp(product_revision->str, global_product_revision_str))
- break;
- product_revision++;
- }
-
- if (product_revision->str) {
- global_product = product_revision->product;
- global_revision = product_revision->revision;
- } else {
- ALOGE("Unable to match '%s' to a product/revision.",
- global_product_revision_str);
- }
-
- global_product_revision_processed = true;
-}
-
-} // anonymous namespace
-
-extern "C" DvrProduct dvr_get_product() {
- process_product_revision();
- return global_product;
-}
-
-extern "C" DvrRevision dvr_get_revision() {
- process_product_revision();
- return global_revision;
-}
-
-extern "C" const char* dvr_get_product_revision_str() {
- process_product_revision();
- return global_product_revision_str;
-}
-
-extern "C" const char* dvr_get_serial_number() {
- process_product_revision();
- if (global_product == DVR_PRODUCT_A00) {
- if (!global_serial_number_processed) {
-#ifdef DVR_HOST
- global_serial_number_processed = true;
-#else
- int width = 4;
- uintptr_t addr = 0x00074138;
- uintptr_t endaddr = addr + width - 1;
-
- int fd = open("/dev/mem", O_RDWR | O_SYNC);
- if (fd < 0) {
- if (errno == EPERM)
- global_serial_number_processed = true;
- fprintf(stderr, "cannot open /dev/mem\n");
- return global_serial_number;
- }
-
- off64_t mmap_start = addr & ~(PAGE_SIZE - 1);
- size_t mmap_size = endaddr - mmap_start + 1;
- mmap_size = (mmap_size + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
-
- void* page = mmap64(0, mmap_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd,
- mmap_start);
-
- if (page == MAP_FAILED) {
- global_serial_number_processed = true;
- fprintf(stderr, "cannot mmap region\n");
- close(fd);
- return global_serial_number;
- }
-
- uint32_t* x =
- reinterpret_cast<uint32_t*>((((uintptr_t)page) + (addr & 4095)));
- snprintf(global_serial_number, kSerialNumberStringSize, "%08x", *x);
- global_serial_number_processed = true;
-
- munmap(page, mmap_size);
- close(fd);
-#endif
- }
- return global_serial_number;
- } else {
- return nullptr;
- }
-}
diff --git a/libs/vr/libdvrcommon/revision_path.cpp b/libs/vr/libdvrcommon/revision_path.cpp
deleted file mode 100644
index c49f9aa..0000000
--- a/libs/vr/libdvrcommon/revision_path.cpp
+++ /dev/null
@@ -1,15 +0,0 @@
-#include "revision_path.h"
-
-namespace {
-
-// The path to the product revision file.
-static const char* kProductRevisionFilePath =
- "/sys/firmware/devicetree/base/goog,board-revision";
-
-} // anonymous namespace
-
-// This exists in a separate file so that it can be replaced for
-// testing.
-const char* dvr_product_revision_file_path() {
- return kProductRevisionFilePath;
-}
diff --git a/libs/vr/libdvrcommon/revision_path.h b/libs/vr/libdvrcommon/revision_path.h
deleted file mode 100644
index afcea46..0000000
--- a/libs/vr/libdvrcommon/revision_path.h
+++ /dev/null
@@ -1,9 +0,0 @@
-#ifndef ANDROID_DVR_LIBDVRCOMMON_REVISION_PATH_H_
-#define ANDROID_DVR_LIBDVRCOMMON_REVISION_PATH_H_
-
-// Returns the revision file path.
-// This exists in a separate file so that it can be replaced for
-// testing.
-const char* dvr_product_revision_file_path();
-
-#endif // ANDROID_DVR_LIBDVRCOMMON_REVISION_PATH_H_
diff --git a/libs/vr/libdvrcommon/tests/revision_app_tests.cpp b/libs/vr/libdvrcommon/tests/revision_app_tests.cpp
deleted file mode 100644
index 772481b..0000000
--- a/libs/vr/libdvrcommon/tests/revision_app_tests.cpp
+++ /dev/null
@@ -1,34 +0,0 @@
-#include <dvr/test/app_test.h>
-#include <gtest/gtest.h>
-#include <private/dvr/revision.h>
-
-// Making sure this information is not available
-// inside the sandbox
-
-namespace {
-
-TEST(RevisionTests, GetProduct) {
- ASSERT_EQ(DVR_PRODUCT_UNKNOWN, dvr_get_product());
-}
-
-TEST(RevisionTests, GetRevision) {
- ASSERT_EQ(DVR_REVISION_UNKNOWN, dvr_get_revision());
-}
-
-TEST(RevisionTests, GetRevisionStr) {
- ASSERT_STREQ("", dvr_get_product_revision_str());
-}
-
-TEST(RevisionTests, GetSerialNo) {
- ASSERT_EQ(nullptr, dvr_get_serial_number());
-}
-
-} // namespace
-
-int main(int argc, char* argv[]) {
- dreamos::test::AppTestBegin();
- ::testing::InitGoogleTest(&argc, argv);
- int result = RUN_ALL_TESTS();
- dreamos::test::AppTestEnd(result);
- return result;
-}
diff --git a/libs/vr/libdvrcommon/tests/revision_tests.cpp b/libs/vr/libdvrcommon/tests/revision_tests.cpp
deleted file mode 100644
index 9abf480..0000000
--- a/libs/vr/libdvrcommon/tests/revision_tests.cpp
+++ /dev/null
@@ -1,27 +0,0 @@
-#include <gtest/gtest.h>
-#include <private/dvr/revision.h>
-
-namespace {
-
-TEST(RevisionTests, GetProduct) {
- ASSERT_NE(DVR_PRODUCT_UNKNOWN, dvr_get_product());
-}
-
-TEST(RevisionTests, GetRevision) {
- ASSERT_NE(DVR_REVISION_UNKNOWN, dvr_get_revision());
-}
-
-TEST(RevisionTests, GetRevisionStr) {
- ASSERT_NE(nullptr, dvr_get_product_revision_str());
-}
-
-TEST(RevisionTests, GetSerialNo) {
- ASSERT_NE(nullptr, dvr_get_serial_number());
-}
-
-} // namespace
-
-int main(int argc, char* argv[]) {
- ::testing::InitGoogleTest(&argc, argv);
- return RUN_ALL_TESTS();
-}
diff --git a/libs/vr/libpdx/service.cpp b/libs/vr/libpdx/service.cpp
index d2804d5..daf9af8 100644
--- a/libs/vr/libpdx/service.cpp
+++ b/libs/vr/libpdx/service.cpp
@@ -129,7 +129,7 @@
PDX_TRACE_NAME("Message::PushFileHandle");
if (auto svc = service_.lock()) {
ErrnoGuard errno_guard;
- return svc->endpoint()->PushFileHandle(this, handle);
+ return ReturnCodeOrError(svc->endpoint()->PushFileHandle(this, handle));
} else {
return -ESHUTDOWN;
}
@@ -139,7 +139,7 @@
PDX_TRACE_NAME("Message::PushFileHandle");
if (auto svc = service_.lock()) {
ErrnoGuard errno_guard;
- return svc->endpoint()->PushFileHandle(this, handle);
+ return ReturnCodeOrError(svc->endpoint()->PushFileHandle(this, handle));
} else {
return -ESHUTDOWN;
}
@@ -149,7 +149,7 @@
PDX_TRACE_NAME("Message::PushFileHandle");
if (auto svc = service_.lock()) {
ErrnoGuard errno_guard;
- return svc->endpoint()->PushFileHandle(this, handle);
+ return ReturnCodeOrError(svc->endpoint()->PushFileHandle(this, handle));
} else {
return -ESHUTDOWN;
}
@@ -159,7 +159,7 @@
PDX_TRACE_NAME("Message::PushChannelHandle");
if (auto svc = service_.lock()) {
ErrnoGuard errno_guard;
- return svc->endpoint()->PushChannelHandle(this, handle);
+ return ReturnCodeOrError(svc->endpoint()->PushChannelHandle(this, handle));
} else {
return -ESHUTDOWN;
}
@@ -170,7 +170,7 @@
PDX_TRACE_NAME("Message::PushChannelHandle");
if (auto svc = service_.lock()) {
ErrnoGuard errno_guard;
- return svc->endpoint()->PushChannelHandle(this, handle);
+ return ReturnCodeOrError(svc->endpoint()->PushChannelHandle(this, handle));
} else {
return -ESHUTDOWN;
}
@@ -180,7 +180,7 @@
PDX_TRACE_NAME("Message::PushChannelHandle");
if (auto svc = service_.lock()) {
ErrnoGuard errno_guard;
- return svc->endpoint()->PushChannelHandle(this, handle);
+ return ReturnCodeOrError(svc->endpoint()->PushChannelHandle(this, handle));
} else {
return -ESHUTDOWN;
}
diff --git a/services/sensorservice/SensorDevice.cpp b/services/sensorservice/SensorDevice.cpp
index 2a17a7f..080c02b 100644
--- a/services/sensorservice/SensorDevice.cpp
+++ b/services/sensorservice/SensorDevice.cpp
@@ -52,6 +52,31 @@
}
SensorDevice::SensorDevice() : mHidlTransportErrors(20) {
+ if (!connectHidlService()) {
+ return;
+ }
+ checkReturn(mSensors->getSensorsList(
+ [&](const auto &list) {
+ const size_t count = list.size();
+
+ mActivationCount.setCapacity(count);
+ Info model;
+ for (size_t i=0 ; i < count; i++) {
+ sensor_t sensor;
+ convertToSensor(list[i], &sensor);
+ mSensorList.push_back(sensor);
+
+ mActivationCount.add(list[i].sensorHandle, model);
+
+ checkReturn(mSensors->activate(list[i].sensorHandle, 0 /* enabled */));
+ }
+ }));
+
+ mIsDirectReportSupported =
+ (checkReturn(mSensors->unregisterDirectChannel(-1)) != Result::INVALID_OPERATION);
+}
+
+bool SensorDevice::connectHidlService() {
// SensorDevice may wait upto 100ms * 10 = 1s for hidl service.
constexpr auto RETRY_DELAY = std::chrono::milliseconds(100);
size_t retry = 10;
@@ -74,7 +99,7 @@
if (--retry <= 0) {
ALOGE("Cannot connect to ISensors hidl service!");
- return;
+ break;
}
// Delay 100ms before retry, hidl service is expected to come up in short time after
// crash.
@@ -82,29 +107,11 @@
(initStep == 0) ? "getService()" : "poll() check", retry);
std::this_thread::sleep_for(RETRY_DELAY);
}
-
- checkReturn(mSensors->getSensorsList(
- [&](const auto &list) {
- const size_t count = list.size();
-
- mActivationCount.setCapacity(count);
- Info model;
- for (size_t i=0 ; i < count; i++) {
- sensor_t sensor;
- convertToSensor(list[i], &sensor);
- mSensorList.push_back(sensor);
-
- mActivationCount.add(list[i].sensorHandle, model);
-
- checkReturn(mSensors->activate(list[i].sensorHandle, 0 /* enabled */));
- }
- }));
-
- mIsDirectReportSupported =
- (checkReturn(mSensors->unregisterDirectChannel(-1)) != Result::INVALID_OPERATION);
+ return (mSensors != nullptr);
}
void SensorDevice::handleDynamicSensorConnection(int handle, bool connected) {
+ // not need to check mSensors because this is is only called after successful poll()
if (connected) {
Info model;
mActivationCount.add(handle, model);
@@ -115,64 +122,38 @@
}
std::string SensorDevice::dump() const {
- if (mSensors == NULL) return "HAL not initialized\n";
+ if (mSensors == nullptr) return "HAL not initialized\n";
String8 result;
+ result.appendFormat("Total %zu h/w sensors, %zu running:\n",
+ mSensorList.size(), mActivationCount.size());
- result.appendFormat("Saw %d hidlTransport Errors\n", mTotalHidlTransportErrors);
- for (auto it = mHidlTransportErrors.begin() ; it != mHidlTransportErrors.end(); it++ ) {
- result += "\t";
- result += it->toString();
- result += "\n";
+ Mutex::Autolock _l(mLock);
+ for (const auto & s : mSensorList) {
+ int32_t handle = s.handle;
+ const Info& info = mActivationCount.valueFor(handle);
+ if (info.batchParams.isEmpty()) continue;
+
+ result.appendFormat("0x%08x) active-count = %zu; ", handle, info.batchParams.size());
+
+ result.append("sampling_period(ms) = {");
+ for (size_t j = 0; j < info.batchParams.size(); j++) {
+ const BatchParams& params = info.batchParams.valueAt(j);
+ result.appendFormat("%.1f%s", params.batchDelay / 1e6f,
+ j < info.batchParams.size() - 1 ? ", " : "");
+ }
+ result.appendFormat("}, selected = %.1f ms; ", info.bestBatchParams.batchDelay / 1e6f);
+
+ result.append("batching_period(ms) = {");
+ for (size_t j = 0; j < info.batchParams.size(); j++) {
+ BatchParams params = info.batchParams.valueAt(j);
+
+ result.appendFormat("%.1f%s", params.batchTimeout / 1e6f,
+ j < info.batchParams.size() - 1 ? ", " : "");
+ }
+ result.appendFormat("}, selected = %.1f ms\n", info.bestBatchParams.batchTimeout / 1e6f);
}
- checkReturn(mSensors->getSensorsList([&](const auto &list){
- const size_t count = list.size();
-
- result.appendFormat(
- "Total %zu h/w sensors, %zu running:\n",
- count,
- mActivationCount.size());
-
- Mutex::Autolock _l(mLock);
- for (size_t i = 0 ; i < count ; i++) {
- const Info& info = mActivationCount.valueFor(
- list[i].sensorHandle);
-
- if (info.batchParams.isEmpty()) continue;
- result.appendFormat(
- "0x%08x) active-count = %zu; ",
- list[i].sensorHandle,
- info.batchParams.size());
-
- result.append("sampling_period(ms) = {");
- for (size_t j = 0; j < info.batchParams.size(); j++) {
- const BatchParams& params = info.batchParams.valueAt(j);
- result.appendFormat(
- "%.1f%s",
- params.batchDelay / 1e6f,
- j < info.batchParams.size() - 1 ? ", " : "");
- }
- result.appendFormat(
- "}, selected = %.1f ms; ",
- info.bestBatchParams.batchDelay / 1e6f);
-
- result.append("batching_period(ms) = {");
- for (size_t j = 0; j < info.batchParams.size(); j++) {
- BatchParams params = info.batchParams.valueAt(j);
-
- result.appendFormat(
- "%.1f%s",
- params.batchTimeout / 1e6f,
- j < info.batchParams.size() - 1 ? ", " : "");
- }
-
- result.appendFormat(
- "}, selected = %.1f ms\n",
- info.bestBatchParams.batchTimeout / 1e6f);
- }
- }));
-
return result.string();
}
@@ -187,7 +168,7 @@
}
ssize_t SensorDevice::poll(sensors_event_t* buffer, size_t count) {
- if (mSensors == NULL) return NO_INIT;
+ if (mSensors == nullptr) return NO_INIT;
ssize_t err;
int numHidlTransportErrors = 0;
@@ -239,7 +220,7 @@
}
status_t SensorDevice::activate(void* ident, int handle, int enabled) {
- if (mSensors == NULL) return NO_INIT;
+ if (mSensors == nullptr) return NO_INIT;
status_t err(NO_ERROR);
bool actuateHardware = false;
@@ -328,7 +309,7 @@
int flags,
int64_t samplingPeriodNs,
int64_t maxBatchReportLatencyNs) {
- if (mSensors == NULL) return NO_INIT;
+ if (mSensors == nullptr) return NO_INIT;
if (samplingPeriodNs < MINIMUM_EVENTS_PERIOD) {
samplingPeriodNs = MINIMUM_EVENTS_PERIOD;
@@ -382,7 +363,7 @@
}
status_t SensorDevice::setDelay(void* ident, int handle, int64_t samplingPeriodNs) {
- if (mSensors == NULL) return NO_INIT;
+ if (mSensors == nullptr) return NO_INIT;
if (samplingPeriodNs < MINIMUM_EVENTS_PERIOD) {
samplingPeriodNs = MINIMUM_EVENTS_PERIOD;
}
@@ -407,11 +388,12 @@
}
int SensorDevice::getHalDeviceVersion() const {
- if (mSensors == NULL) return -1;
+ if (mSensors == nullptr) return -1;
return SENSORS_DEVICE_API_VERSION_1_4;
}
status_t SensorDevice::flush(void* ident, int handle) {
+ if (mSensors == nullptr) return NO_INIT;
if (isClientDisabled(ident)) return INVALID_OPERATION;
ALOGD_IF(DEBUG_CONNECTIONS, "\t>>> actuating h/w flush %d", handle);
return StatusFromResult(checkReturn(mSensors->flush(handle)));
@@ -427,6 +409,7 @@
}
void SensorDevice::enableAllSensors() {
+ if (mSensors == nullptr) return;
Mutex::Autolock _l(mLock);
mDisabledClients.clear();
ALOGI("cleared mDisabledClients");
@@ -453,8 +436,9 @@
}
void SensorDevice::disableAllSensors() {
+ if (mSensors == nullptr) return;
Mutex::Autolock _l(mLock);
- for (size_t i = 0; i< mActivationCount.size(); ++i) {
+ for (size_t i = 0; i< mActivationCount.size(); ++i) {
const Info& info = mActivationCount.valueAt(i);
// Check if this sensor has been activated previously and disable it.
if (info.batchParams.size() > 0) {
@@ -475,6 +459,7 @@
status_t SensorDevice::injectSensorData(
const sensors_event_t *injected_sensor_event) {
+ if (mSensors == nullptr) return NO_INIT;
ALOGD_IF(DEBUG_CONNECTIONS,
"sensor_event handle=%d ts=%" PRId64 " data=%.2f, %.2f, %.2f %.2f %.2f %.2f",
injected_sensor_event->sensor,
@@ -490,10 +475,97 @@
}
status_t SensorDevice::setMode(uint32_t mode) {
+ if (mSensors == nullptr) return NO_INIT;
+ return StatusFromResult(
+ checkReturn(mSensors->setOperationMode(
+ static_cast<hardware::sensors::V1_0::OperationMode>(mode))));
+}
- return StatusFromResult(
- checkReturn(mSensors->setOperationMode(
- static_cast<hardware::sensors::V1_0::OperationMode>(mode))));
+int32_t SensorDevice::registerDirectChannel(const sensors_direct_mem_t* memory) {
+ if (mSensors == nullptr) return NO_INIT;
+ Mutex::Autolock _l(mLock);
+
+ SharedMemType type;
+ switch (memory->type) {
+ case SENSOR_DIRECT_MEM_TYPE_ASHMEM:
+ type = SharedMemType::ASHMEM;
+ break;
+ case SENSOR_DIRECT_MEM_TYPE_GRALLOC:
+ type = SharedMemType::GRALLOC;
+ break;
+ default:
+ return BAD_VALUE;
+ }
+
+ SharedMemFormat format;
+ if (memory->format != SENSOR_DIRECT_FMT_SENSORS_EVENT) {
+ return BAD_VALUE;
+ }
+ format = SharedMemFormat::SENSORS_EVENT;
+
+ SharedMemInfo mem = {
+ .type = type,
+ .format = format,
+ .size = static_cast<uint32_t>(memory->size),
+ .memoryHandle = memory->handle,
+ };
+
+ int32_t ret;
+ checkReturn(mSensors->registerDirectChannel(mem,
+ [&ret](auto result, auto channelHandle) {
+ if (result == Result::OK) {
+ ret = channelHandle;
+ } else {
+ ret = StatusFromResult(result);
+ }
+ }));
+ return ret;
+}
+
+void SensorDevice::unregisterDirectChannel(int32_t channelHandle) {
+ if (mSensors == nullptr) return;
+ Mutex::Autolock _l(mLock);
+ checkReturn(mSensors->unregisterDirectChannel(channelHandle));
+}
+
+int32_t SensorDevice::configureDirectChannel(int32_t sensorHandle,
+ int32_t channelHandle, const struct sensors_direct_cfg_t *config) {
+ if (mSensors == nullptr) return NO_INIT;
+ Mutex::Autolock _l(mLock);
+
+ RateLevel rate;
+ switch(config->rate_level) {
+ case SENSOR_DIRECT_RATE_STOP:
+ rate = RateLevel::STOP;
+ break;
+ case SENSOR_DIRECT_RATE_NORMAL:
+ rate = RateLevel::NORMAL;
+ break;
+ case SENSOR_DIRECT_RATE_FAST:
+ rate = RateLevel::FAST;
+ break;
+ case SENSOR_DIRECT_RATE_VERY_FAST:
+ rate = RateLevel::VERY_FAST;
+ break;
+ default:
+ return BAD_VALUE;
+ }
+
+ int32_t ret;
+ checkReturn(mSensors->configDirectReport(sensorHandle, channelHandle, rate,
+ [&ret, rate] (auto result, auto token) {
+ if (rate == RateLevel::STOP) {
+ ret = StatusFromResult(result);
+ } else {
+ if (result == Result::OK) {
+ ret = token;
+ } else {
+ ret = StatusFromResult(result);
+ }
+ }
+ }));
+
+ return ret;
}
// ---------------------------------------------------------------------------
@@ -555,90 +627,6 @@
mDisabledClients.remove(ident);
}
-int32_t SensorDevice::registerDirectChannel(const sensors_direct_mem_t* memory) {
- Mutex::Autolock _l(mLock);
-
- SharedMemType type;
- switch (memory->type) {
- case SENSOR_DIRECT_MEM_TYPE_ASHMEM:
- type = SharedMemType::ASHMEM;
- break;
- case SENSOR_DIRECT_MEM_TYPE_GRALLOC:
- type = SharedMemType::GRALLOC;
- break;
- default:
- return BAD_VALUE;
- }
-
- SharedMemFormat format;
- if (memory->format != SENSOR_DIRECT_FMT_SENSORS_EVENT) {
- return BAD_VALUE;
- }
- format = SharedMemFormat::SENSORS_EVENT;
-
- SharedMemInfo mem = {
- .type = type,
- .format = format,
- .size = static_cast<uint32_t>(memory->size),
- .memoryHandle = memory->handle,
- };
-
- int32_t ret;
- checkReturn(mSensors->registerDirectChannel(mem,
- [&ret](auto result, auto channelHandle) {
- if (result == Result::OK) {
- ret = channelHandle;
- } else {
- ret = StatusFromResult(result);
- }
- }));
- return ret;
-}
-
-void SensorDevice::unregisterDirectChannel(int32_t channelHandle) {
- Mutex::Autolock _l(mLock);
- checkReturn(mSensors->unregisterDirectChannel(channelHandle));
-}
-
-int32_t SensorDevice::configureDirectChannel(int32_t sensorHandle,
- int32_t channelHandle, const struct sensors_direct_cfg_t *config) {
- Mutex::Autolock _l(mLock);
-
- RateLevel rate;
- switch(config->rate_level) {
- case SENSOR_DIRECT_RATE_STOP:
- rate = RateLevel::STOP;
- break;
- case SENSOR_DIRECT_RATE_NORMAL:
- rate = RateLevel::NORMAL;
- break;
- case SENSOR_DIRECT_RATE_FAST:
- rate = RateLevel::FAST;
- break;
- case SENSOR_DIRECT_RATE_VERY_FAST:
- rate = RateLevel::VERY_FAST;
- break;
- default:
- return BAD_VALUE;
- }
-
- int32_t ret;
- checkReturn(mSensors->configDirectReport(sensorHandle, channelHandle, rate,
- [&ret, rate] (auto result, auto token) {
- if (rate == RateLevel::STOP) {
- ret = StatusFromResult(result);
- } else {
- if (result == Result::OK) {
- ret = token;
- } else {
- ret = StatusFromResult(result);
- }
- }
- }));
-
- return ret;
-}
-
bool SensorDevice::isDirectReportSupported() const {
return mIsDirectReportSupported;
}
diff --git a/services/sensorservice/SensorDevice.h b/services/sensorservice/SensorDevice.h
index 410531b..2520a81 100644
--- a/services/sensorservice/SensorDevice.h
+++ b/services/sensorservice/SensorDevice.h
@@ -161,6 +161,7 @@
// Use this vector to determine which client is activated or deactivated.
SortedVector<void *> mDisabledClients;
SensorDevice();
+ bool connectHidlService();
static void handleHidlDeath(const std::string &detail);
template<typename T>
diff --git a/services/vr/vr_window_manager/application.cpp b/services/vr/vr_window_manager/application.cpp
index c7d7d50..b2f02e5 100644
--- a/services/vr/vr_window_manager/application.cpp
+++ b/services/vr/vr_window_manager/application.cpp
@@ -174,7 +174,12 @@
// TODO(steventhomas): If we're not visible, block until we are. For now we
// throttle by calling dvrGraphicsWaitNextFrame.
DvrFrameSchedule schedule;
- dvrGraphicsWaitNextFrame(graphics_context_, 0, &schedule);
+ int status = dvrGraphicsWaitNextFrame(graphics_context_, 0, &schedule);
+ if (status < 0) {
+ ALOGE("Context lost, deallocating graphics resources");
+ SetVisibility(false);
+ DeallocateResources();
+ }
OnDrawFrame();
diff --git a/services/vr/vr_window_manager/shell_view.cpp b/services/vr/vr_window_manager/shell_view.cpp
index 67ef5d4..c270be2 100644
--- a/services/vr/vr_window_manager/shell_view.cpp
+++ b/services/vr/vr_window_manager/shell_view.cpp
@@ -126,10 +126,6 @@
if (!surface_flinger_view_->Initialize(this))
return 1;
- // This is a temporary fix for now. These APIs will be changed when everything
- // is moved into vrcore.
- display_client_ = DisplayClient::Create();
-
return 0;
}
@@ -164,7 +160,14 @@
}
void ShellView::DeallocateResources() {
- surface_flinger_view_.reset();
+ {
+ std::unique_lock<std::mutex> l(display_frame_mutex_);
+ removed_displays_.clear();
+ new_displays_.clear();
+ displays_.clear();
+ }
+
+ display_client_.reset();
reticle_.reset();
controller_mesh_.reset();
program_.reset(new ShaderProgram);
@@ -283,6 +286,20 @@
bool showing = false;
+ // This is a temporary fix for now. These APIs will be changed when everything
+ // is moved into vrcore.
+ // Do this on demand in case vr_flinger crashed and we are reconnecting.
+ if (!display_client_.get()) {
+ int error = 0;
+ display_client_ = DisplayClient::Create(&error);
+
+ if (error) {
+ ALOGE("Could not connect to display service : %s(%d)", strerror(error),
+ error);
+ return base::unique_fd();
+ }
+ }
+
// TODO(achaulk): change when moved into vrcore.
bool vr_running = display_client_->IsVrAppRunning();