diff options
| -rw-r--r-- | include/ui/ColorSpace.h | 143 | ||||
| -rw-r--r-- | libs/binder/tests/Android.bp | 10 | ||||
| -rw-r--r-- | libs/binder/tests/schd-dbg.cpp | 426 | ||||
| -rw-r--r-- | libs/ui/ColorSpace.cpp | 258 | ||||
| -rw-r--r-- | libs/ui/tests/colorspace_test.cpp | 4 | ||||
| -rw-r--r-- | libs/vr/libdvrcommon/Android.bp | 2 | ||||
| -rw-r--r-- | libs/vr/libdvrcommon/include/private/dvr/revision.h | 47 | ||||
| -rw-r--r-- | libs/vr/libdvrcommon/revision.cpp | 175 | ||||
| -rw-r--r-- | libs/vr/libdvrcommon/revision_path.cpp | 15 | ||||
| -rw-r--r-- | libs/vr/libdvrcommon/revision_path.h | 9 | ||||
| -rw-r--r-- | libs/vr/libdvrcommon/tests/revision_app_tests.cpp | 34 | ||||
| -rw-r--r-- | libs/vr/libdvrcommon/tests/revision_tests.cpp | 27 | ||||
| -rw-r--r-- | libs/vr/libpdx/service.cpp | 12 | ||||
| -rw-r--r-- | services/sensorservice/SensorDevice.cpp | 270 | ||||
| -rw-r--r-- | services/sensorservice/SensorDevice.h | 1 |
15 files changed, 863 insertions, 570 deletions
diff --git a/include/ui/ColorSpace.h b/include/ui/ColorSpace.h index 8c4acb79c6..8ccf6d36e5 100644 --- a/include/ui/ColorSpace.h +++ b/include/ui/ColorSpace.h @@ -35,6 +35,16 @@ public: 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 @@ public: 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 @@ public: 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 @@ public: return mWhitePoint; } + constexpr const TransferParameters& getTransferParameters() const noexcept { + return mParameters; + } + /** * Converts the supplied XYZ value to xyY. */ @@ -166,35 +244,6 @@ public: 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 @@ private: 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 @@ private: mat3 mRGBtoXYZ; mat3 mXYZtoRGB; + TransferParameters mParameters; transfer_function mOETF; transfer_function mEOTF; clamping_function mClamper; @@ -225,6 +275,31 @@ private: 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 0dc4469eb1..327ecad0cd 100644 --- a/libs/binder/tests/Android.bp +++ b/libs/binder/tests/Android.bp @@ -70,3 +70,13 @@ cc_test { "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 0000000000..27320712f0 --- /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 49390d955e..5b4bf2353e 100644 --- a/libs/ui/ColorSpace.cpp +++ b/libs/ui/ColorSpace.cpp @@ -20,6 +20,83 @@ using namespace std::placeholders; 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 @@ ColorSpace::ColorSpace( , mXYZtoRGB(inverse(rgbToXYZ)) , mOETF(std::move(OETF)) , mEOTF(std::move(EOTF)) - , mClamper(std::move(clamper)) { - - float3 r(rgbToXYZ * float3{1, 0, 0}); - float3 g(rgbToXYZ * float3{0, 1, 0}); - float3 b(rgbToXYZ * float3{0, 0, 1}); + , 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}); +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)) { +} - 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 @@ ColorSpace::ColorSpace( , 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 @@ constexpr mat3 ColorSpace::computeXYZMatrix( }; } -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 @@ const ColorSpace ColorSpace::linearExtendedSRGB() { "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 @@ const ColorSpace ColorSpace::NTSC() { "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 @@ const ColorSpace ColorSpace::BT709() { "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 @@ const ColorSpace ColorSpace::BT2020() { "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 @@ const ColorSpace ColorSpace::AdobeRGB() { "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 @@ const ColorSpace ColorSpace::ProPhotoRGB() { "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 @@ const ColorSpace ColorSpace::DisplayP3() { "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 @@ const ColorSpace ColorSpace::DCIP3() { "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 @@ const ColorSpace ColorSpace::ACES() { "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 @@ const ColorSpace ColorSpace::ACEScg() { "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 @@ static mat3 adaptation(const mat3& matrix, const float3& srcWhitePoint, const fl 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 @@ ColorSpace::Connector::Connector( 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 @@ ColorSpace::Connector::Connector( } } -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 1e359d3555..0a4873c8d3 100644 --- a/libs/ui/tests/colorspace_test.cpp +++ b/libs/ui/tests/colorspace_test.cpp @@ -152,12 +152,12 @@ TEST_F(ColorSpaceTest, Clamping) { 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 81404a4fc3..eb78348f4a 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 dda0fceb62..0000000000 --- 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 7925f657a2..0000000000 --- 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 c49f9aafef..0000000000 --- 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 afcea46e88..0000000000 --- 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 772481b8f6..0000000000 --- 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 9abf4805a6..0000000000 --- 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 d2804d5f95..daf9af89ed 100644 --- a/libs/vr/libpdx/service.cpp +++ b/libs/vr/libpdx/service.cpp @@ -129,7 +129,7 @@ FileReference Message::PushFileHandle(const LocalHandle& handle) { 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 @@ FileReference Message::PushFileHandle(const BorrowedHandle& handle) { 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 @@ FileReference Message::PushFileHandle(const RemoteHandle& handle) { 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 @@ ChannelReference Message::PushChannelHandle(const LocalChannelHandle& handle) { 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 @@ ChannelReference Message::PushChannelHandle( 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 @@ ChannelReference Message::PushChannelHandle(const RemoteChannelHandle& handle) { 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 2a17a7f2a1..080c02bc91 100644 --- a/services/sensorservice/SensorDevice.cpp +++ b/services/sensorservice/SensorDevice.cpp @@ -52,6 +52,31 @@ static status_t StatusFromResult(Result result) { } 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 @@ SensorDevice::SensorDevice() : mHidlTransportErrors(20) { 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 @@ SensorDevice::SensorDevice() : mHidlTransportErrors(20) { (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,63 +122,37 @@ void SensorDevice::handleDynamicSensorConnection(int handle, bool connected) { } 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; - checkReturn(mSensors->getSensorsList([&](const auto &list){ - const size_t count = list.size(); + result.appendFormat("0x%08x) active-count = %zu; ", handle, info.batchParams.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.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.appendFormat( - "}, selected = %.1f ms\n", - info.bestBatchParams.batchTimeout / 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 @@ status_t SensorDevice::initCheck() const { } 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 @@ void SensorDevice::autoDisable(void *ident, int handle) { } 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 @@ status_t SensorDevice::batch( 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::batch( } 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 @@ status_t SensorDevice::setDelay(void* ident, int handle, int64_t samplingPeriodN } 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 @@ bool SensorDevice::isClientDisabledLocked(void* ident) { } void SensorDevice::enableAllSensors() { + if (mSensors == nullptr) return; Mutex::Autolock _l(mLock); mDisabledClients.clear(); ALOGI("cleared mDisabledClients"); @@ -453,8 +436,9 @@ void SensorDevice::enableAllSensors() { } 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 @@ void SensorDevice::disableAllSensors() { 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,72 +475,14 @@ status_t SensorDevice::injectSensorData( } status_t SensorDevice::setMode(uint32_t mode) { - - return StatusFromResult( - checkReturn(mSensors->setOperationMode( - static_cast<hardware::sensors::V1_0::OperationMode>(mode)))); -} - -// --------------------------------------------------------------------------- - -int SensorDevice::Info::numActiveClients() { - SensorDevice& device(SensorDevice::getInstance()); - int num = 0; - for (size_t i = 0; i < batchParams.size(); ++i) { - if (!device.isClientDisabledLocked(batchParams.keyAt(i))) { - ++num; - } - } - return num; -} - -status_t SensorDevice::Info::setBatchParamsForIdent(void* ident, int flags, - int64_t samplingPeriodNs, - int64_t maxBatchReportLatencyNs) { - ssize_t index = batchParams.indexOfKey(ident); - if (index < 0) { - ALOGE("Info::setBatchParamsForIdent(ident=%p, period_ns=%" PRId64 " timeout=%" PRId64 ") failed (%s)", - ident, samplingPeriodNs, maxBatchReportLatencyNs, strerror(-index)); - return BAD_INDEX; - } - BatchParams& params = batchParams.editValueAt(index); - params.flags = flags; - params.batchDelay = samplingPeriodNs; - params.batchTimeout = maxBatchReportLatencyNs; - return NO_ERROR; -} - -void SensorDevice::Info::selectBatchParams() { - BatchParams bestParams(0, -1, -1); - SensorDevice& device(SensorDevice::getInstance()); - - for (size_t i = 0; i < batchParams.size(); ++i) { - if (device.isClientDisabledLocked(batchParams.keyAt(i))) continue; - BatchParams params = batchParams.valueAt(i); - if (bestParams.batchDelay == -1 || params.batchDelay < bestParams.batchDelay) { - bestParams.batchDelay = params.batchDelay; - } - if (bestParams.batchTimeout == -1 || params.batchTimeout < bestParams.batchTimeout) { - bestParams.batchTimeout = params.batchTimeout; - } - } - bestBatchParams = bestParams; -} - -ssize_t SensorDevice::Info::removeBatchParamsForIdent(void* ident) { - ssize_t idx = batchParams.removeItem(ident); - if (idx >= 0) { - selectBatchParams(); - } - return idx; -} - -void SensorDevice::notifyConnectionDestroyed(void* ident) { - Mutex::Autolock _l(mLock); - mDisabledClients.remove(ident); + if (mSensors == nullptr) return NO_INIT; + 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; @@ -596,12 +523,14 @@ int32_t SensorDevice::registerDirectChannel(const sensors_direct_mem_t* memory) } 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; @@ -639,6 +568,65 @@ int32_t SensorDevice::configureDirectChannel(int32_t sensorHandle, return ret; } +// --------------------------------------------------------------------------- + +int SensorDevice::Info::numActiveClients() { + SensorDevice& device(SensorDevice::getInstance()); + int num = 0; + for (size_t i = 0; i < batchParams.size(); ++i) { + if (!device.isClientDisabledLocked(batchParams.keyAt(i))) { + ++num; + } + } + return num; +} + +status_t SensorDevice::Info::setBatchParamsForIdent(void* ident, int flags, + int64_t samplingPeriodNs, + int64_t maxBatchReportLatencyNs) { + ssize_t index = batchParams.indexOfKey(ident); + if (index < 0) { + ALOGE("Info::setBatchParamsForIdent(ident=%p, period_ns=%" PRId64 " timeout=%" PRId64 ") failed (%s)", + ident, samplingPeriodNs, maxBatchReportLatencyNs, strerror(-index)); + return BAD_INDEX; + } + BatchParams& params = batchParams.editValueAt(index); + params.flags = flags; + params.batchDelay = samplingPeriodNs; + params.batchTimeout = maxBatchReportLatencyNs; + return NO_ERROR; +} + +void SensorDevice::Info::selectBatchParams() { + BatchParams bestParams(0, -1, -1); + SensorDevice& device(SensorDevice::getInstance()); + + for (size_t i = 0; i < batchParams.size(); ++i) { + if (device.isClientDisabledLocked(batchParams.keyAt(i))) continue; + BatchParams params = batchParams.valueAt(i); + if (bestParams.batchDelay == -1 || params.batchDelay < bestParams.batchDelay) { + bestParams.batchDelay = params.batchDelay; + } + if (bestParams.batchTimeout == -1 || params.batchTimeout < bestParams.batchTimeout) { + bestParams.batchTimeout = params.batchTimeout; + } + } + bestBatchParams = bestParams; +} + +ssize_t SensorDevice::Info::removeBatchParamsForIdent(void* ident) { + ssize_t idx = batchParams.removeItem(ident); + if (idx >= 0) { + selectBatchParams(); + } + return idx; +} + +void SensorDevice::notifyConnectionDestroyed(void* ident) { + Mutex::Autolock _l(mLock); + mDisabledClients.remove(ident); +} + bool SensorDevice::isDirectReportSupported() const { return mIsDirectReportSupported; } diff --git a/services/sensorservice/SensorDevice.h b/services/sensorservice/SensorDevice.h index 410531be6e..2520a813c5 100644 --- a/services/sensorservice/SensorDevice.h +++ b/services/sensorservice/SensorDevice.h @@ -161,6 +161,7 @@ private: // 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> |