diff options
Diffstat (limited to 'services')
66 files changed, 9126 insertions, 3355 deletions
diff --git a/services/powermanager/IPowerManager.cpp b/services/powermanager/IPowerManager.cpp index a0f19d4..0265df3 100644 --- a/services/powermanager/IPowerManager.cpp +++ b/services/powermanager/IPowerManager.cpp @@ -30,7 +30,7 @@ namespace android { // must be kept in sync with IPowerManager.aidl enum { ACQUIRE_WAKE_LOCK = IBinder::FIRST_CALL_TRANSACTION, - RELEASE_WAKE_LOCK = IBinder::FIRST_CALL_TRANSACTION + 4, + RELEASE_WAKE_LOCK = IBinder::FIRST_CALL_TRANSACTION + 1, }; class BpPowerManager : public BpInterface<IPowerManager> @@ -46,11 +46,10 @@ public: Parcel data, reply; data.writeInterfaceToken(IPowerManager::getInterfaceDescriptor()); - data.writeInt32(flags); data.writeStrongBinder(lock); + data.writeInt32(flags); data.writeString16(tag); - // no WorkSource passed - data.writeInt32(0); + data.writeInt32(0); // no WorkSource return remote()->transact(ACQUIRE_WAKE_LOCK, data, &reply); } diff --git a/services/sensorservice/Android.mk b/services/sensorservice/Android.mk new file mode 100644 index 0000000..e0cfaa6 --- /dev/null +++ b/services/sensorservice/Android.mk @@ -0,0 +1,32 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES:= \ + BatteryService.cpp \ + CorrectedGyroSensor.cpp \ + Fusion.cpp \ + GravitySensor.cpp \ + LinearAccelerationSensor.cpp \ + OrientationSensor.cpp \ + RotationVectorSensor.cpp \ + SensorDevice.cpp \ + SensorFusion.cpp \ + SensorInterface.cpp \ + SensorService.cpp \ + + +LOCAL_CFLAGS:= -DLOG_TAG=\"SensorService\" + +LOCAL_SHARED_LIBRARIES := \ + libcutils \ + libhardware \ + libutils \ + libbinder \ + libui \ + libgui + + + +LOCAL_MODULE:= libsensorservice + +include $(BUILD_SHARED_LIBRARY) diff --git a/services/sensorservice/BatteryService.cpp b/services/sensorservice/BatteryService.cpp new file mode 100644 index 0000000..70b65ab --- /dev/null +++ b/services/sensorservice/BatteryService.cpp @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <stdint.h> +#include <math.h> +#include <sys/types.h> + +#include <utils/Atomic.h> +#include <utils/Errors.h> +#include <utils/Singleton.h> + +#include <binder/BinderService.h> +#include <binder/Parcel.h> + +#include "BatteryService.h" + +namespace android { +// --------------------------------------------------------------------------- + +BatteryService::BatteryService() { + const sp<IServiceManager> sm(defaultServiceManager()); + if (sm != NULL) { + const String16 name("batteryinfo"); + mBatteryStatService = sm->getService(name); + } +} + +status_t BatteryService::noteStartSensor(int uid, int handle) { + Parcel data, reply; + data.writeInterfaceToken(DESCRIPTOR); + data.writeInt32(uid); + data.writeInt32(handle); + status_t err = mBatteryStatService->transact( + TRANSACTION_noteStartSensor, data, &reply, 0); + err = reply.readExceptionCode(); + return err; +} + +status_t BatteryService::noteStopSensor(int uid, int handle) { + Parcel data, reply; + data.writeInterfaceToken(DESCRIPTOR); + data.writeInt32(uid); + data.writeInt32(handle); + status_t err = mBatteryStatService->transact( + TRANSACTION_noteStopSensor, data, &reply, 0); + err = reply.readExceptionCode(); + return err; +} + +bool BatteryService::addSensor(uid_t uid, int handle) { + Mutex::Autolock _l(mActivationsLock); + Info key(uid, handle); + ssize_t index = mActivations.indexOf(key); + if (index < 0) { + index = mActivations.add(key); + } + Info& info(mActivations.editItemAt(index)); + info.count++; + return info.count == 1; +} + +bool BatteryService::removeSensor(uid_t uid, int handle) { + Mutex::Autolock _l(mActivationsLock); + ssize_t index = mActivations.indexOf(Info(uid, handle)); + if (index < 0) return false; + Info& info(mActivations.editItemAt(index)); + info.count--; + return info.count == 0; +} + + +void BatteryService::enableSensorImpl(uid_t uid, int handle) { + if (mBatteryStatService != 0) { + if (addSensor(uid, handle)) { + int64_t identity = IPCThreadState::self()->clearCallingIdentity(); + noteStartSensor(uid, handle); + IPCThreadState::self()->restoreCallingIdentity(identity); + } + } +} +void BatteryService::disableSensorImpl(uid_t uid, int handle) { + if (mBatteryStatService != 0) { + if (removeSensor(uid, handle)) { + int64_t identity = IPCThreadState::self()->clearCallingIdentity(); + noteStopSensor(uid, handle); + IPCThreadState::self()->restoreCallingIdentity(identity); + } + } +} + +void BatteryService::cleanupImpl(uid_t uid) { + if (mBatteryStatService != 0) { + Mutex::Autolock _l(mActivationsLock); + int64_t identity = IPCThreadState::self()->clearCallingIdentity(); + for (ssize_t i=0 ; i<mActivations.size() ; i++) { + const Info& info(mActivations[i]); + if (info.uid == uid) { + noteStopSensor(info.uid, info.handle); + mActivations.removeAt(i); + i--; + } + } + IPCThreadState::self()->restoreCallingIdentity(identity); + } +} + +const String16 BatteryService::DESCRIPTOR("com.android.internal.app.IBatteryStats"); + +ANDROID_SINGLETON_STATIC_INSTANCE(BatteryService) + +// --------------------------------------------------------------------------- +}; // namespace android + diff --git a/services/sensorservice/BatteryService.h b/services/sensorservice/BatteryService.h new file mode 100644 index 0000000..86cc884 --- /dev/null +++ b/services/sensorservice/BatteryService.h @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <stdint.h> +#include <sys/types.h> + +#include <utils/Singleton.h> + +namespace android { +// --------------------------------------------------------------------------- + +class BatteryService : public Singleton<BatteryService> { + static const int TRANSACTION_noteStartSensor = IBinder::FIRST_CALL_TRANSACTION + 3; + static const int TRANSACTION_noteStopSensor = IBinder::FIRST_CALL_TRANSACTION + 4; + static const String16 DESCRIPTOR; + + friend class Singleton<BatteryService>; + sp<IBinder> mBatteryStatService; + + BatteryService(); + status_t noteStartSensor(int uid, int handle); + status_t noteStopSensor(int uid, int handle); + + void enableSensorImpl(uid_t uid, int handle); + void disableSensorImpl(uid_t uid, int handle); + void cleanupImpl(uid_t uid); + + struct Info { + uid_t uid; + int handle; + int32_t count; + Info() : uid(0), handle(0), count(0) { } + Info(uid_t uid, int handle) : uid(uid), handle(handle), count(0) { } + bool operator < (const Info& rhs) const { + return (uid == rhs.uid) ? (handle < rhs.handle) : (uid < rhs.uid); + } + }; + + Mutex mActivationsLock; + SortedVector<Info> mActivations; + bool addSensor(uid_t uid, int handle); + bool removeSensor(uid_t uid, int handle); + +public: + static void enableSensor(uid_t uid, int handle) { + BatteryService::getInstance().enableSensorImpl(uid, handle); + } + static void disableSensor(uid_t uid, int handle) { + BatteryService::getInstance().disableSensorImpl(uid, handle); + } + static void cleanup(uid_t uid) { + BatteryService::getInstance().cleanupImpl(uid); + } +}; + +// --------------------------------------------------------------------------- +}; // namespace android + diff --git a/services/sensorservice/CorrectedGyroSensor.cpp b/services/sensorservice/CorrectedGyroSensor.cpp new file mode 100644 index 0000000..1857443 --- /dev/null +++ b/services/sensorservice/CorrectedGyroSensor.cpp @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <stdint.h> +#include <math.h> +#include <sys/types.h> + +#include <utils/Errors.h> + +#include <hardware/sensors.h> + +#include "CorrectedGyroSensor.h" +#include "SensorDevice.h" +#include "SensorFusion.h" + +namespace android { +// --------------------------------------------------------------------------- + +CorrectedGyroSensor::CorrectedGyroSensor(sensor_t const* list, size_t count) + : mSensorDevice(SensorDevice::getInstance()), + mSensorFusion(SensorFusion::getInstance()) +{ + for (size_t i=0 ; i<count ; i++) { + if (list[i].type == SENSOR_TYPE_GYROSCOPE) { + mGyro = Sensor(list + i); + break; + } + } +} + +bool CorrectedGyroSensor::process(sensors_event_t* outEvent, + const sensors_event_t& event) +{ + if (event.type == SENSOR_TYPE_GYROSCOPE) { + const vec3_t bias(mSensorFusion.getGyroBias()); + *outEvent = event; + outEvent->data[0] -= bias.x; + outEvent->data[1] -= bias.y; + outEvent->data[2] -= bias.z; + outEvent->sensor = '_cgy'; + return true; + } + return false; +} + +status_t CorrectedGyroSensor::activate(void* ident, bool enabled) { + mSensorDevice.activate(this, mGyro.getHandle(), enabled); + return mSensorFusion.activate(this, enabled); +} + +status_t CorrectedGyroSensor::setDelay(void* ident, int handle, int64_t ns) { + mSensorDevice.setDelay(this, mGyro.getHandle(), ns); + return mSensorFusion.setDelay(this, ns); +} + +Sensor CorrectedGyroSensor::getSensor() const { + sensor_t hwSensor; + hwSensor.name = "Corrected Gyroscope Sensor"; + hwSensor.vendor = "Google Inc."; + hwSensor.version = 1; + hwSensor.handle = '_cgy'; + hwSensor.type = SENSOR_TYPE_GYROSCOPE; + hwSensor.maxRange = mGyro.getMaxValue(); + hwSensor.resolution = mGyro.getResolution(); + hwSensor.power = mSensorFusion.getPowerUsage(); + hwSensor.minDelay = mGyro.getMinDelay(); + Sensor sensor(&hwSensor); + return sensor; +} + +// --------------------------------------------------------------------------- +}; // namespace android + diff --git a/services/sensorservice/CorrectedGyroSensor.h b/services/sensorservice/CorrectedGyroSensor.h new file mode 100644 index 0000000..3c49c08 --- /dev/null +++ b/services/sensorservice/CorrectedGyroSensor.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_CORRECTED_GYRO_SENSOR_H +#define ANDROID_CORRECTED_GYRO_SENSOR_H + +#include <stdint.h> +#include <sys/types.h> + +#include <gui/Sensor.h> + +#include "SensorInterface.h" + +// --------------------------------------------------------------------------- +namespace android { +// --------------------------------------------------------------------------- + +class SensorDevice; +class SensorFusion; + +class CorrectedGyroSensor : public SensorInterface { + SensorDevice& mSensorDevice; + SensorFusion& mSensorFusion; + Sensor mGyro; + +public: + CorrectedGyroSensor(sensor_t const* list, size_t count); + virtual bool process(sensors_event_t* outEvent, + const sensors_event_t& event); + virtual status_t activate(void* ident, bool enabled); + virtual status_t setDelay(void* ident, int handle, int64_t ns); + virtual Sensor getSensor() const; + virtual bool isVirtual() const { return true; } +}; + +// --------------------------------------------------------------------------- +}; // namespace android + +#endif // ANDROID_CORRECTED_GYRO_SENSOR_H diff --git a/services/sensorservice/Fusion.cpp b/services/sensorservice/Fusion.cpp new file mode 100644 index 0000000..b88a647 --- /dev/null +++ b/services/sensorservice/Fusion.cpp @@ -0,0 +1,450 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <stdio.h> + +#include <utils/Log.h> + +#include "Fusion.h" + +namespace android { + +// ----------------------------------------------------------------------- + +/* + * gyroVAR gives the measured variance of the gyro's output per + * Hz (or variance at 1 Hz). This is an "intrinsic" parameter of the gyro, + * which is independent of the sampling frequency. + * + * The variance of gyro's output at a given sampling period can be + * calculated as: + * variance(T) = gyroVAR / T + * + * The variance of the INTEGRATED OUTPUT at a given sampling period can be + * calculated as: + * variance_integrate_output(T) = gyroVAR * T + * + */ +static const float gyroVAR = 1e-7; // (rad/s)^2 / Hz +static const float biasVAR = 1e-8; // (rad/s)^2 / s (guessed) + +/* + * Standard deviations of accelerometer and magnetometer + */ +static const float accSTDEV = 0.05f; // m/s^2 (measured 0.08 / CDD 0.05) +static const float magSTDEV = 0.5f; // uT (measured 0.7 / CDD 0.5) + +static const float SYMMETRY_TOLERANCE = 1e-10f; + +/* + * Accelerometer updates will not be performed near free fall to avoid + * ill-conditioning and div by zeros. + * Threshhold: 10% of g, in m/s^2 + */ +static const float FREE_FALL_THRESHOLD = 0.981f; +static const float FREE_FALL_THRESHOLD_SQ = + FREE_FALL_THRESHOLD*FREE_FALL_THRESHOLD; + +/* + * The geomagnetic-field should be between 30uT and 60uT. + * Fields strengths greater than this likely indicate a local magnetic + * disturbance which we do not want to update into the fused frame. + */ +static const float MAX_VALID_MAGNETIC_FIELD = 100; // uT +static const float MAX_VALID_MAGNETIC_FIELD_SQ = + MAX_VALID_MAGNETIC_FIELD*MAX_VALID_MAGNETIC_FIELD; + +/* + * Values of the field smaller than this should be ignored in fusion to avoid + * ill-conditioning. This state can happen with anomalous local magnetic + * disturbances canceling the Earth field. + */ +static const float MIN_VALID_MAGNETIC_FIELD = 10; // uT +static const float MIN_VALID_MAGNETIC_FIELD_SQ = + MIN_VALID_MAGNETIC_FIELD*MIN_VALID_MAGNETIC_FIELD; + +/* + * If the cross product of two vectors has magnitude squared less than this, + * we reject it as invalid due to alignment of the vectors. + * This threshold is used to check for the case where the magnetic field sample + * is parallel to the gravity field, which can happen in certain places due + * to magnetic field disturbances. + */ +static const float MIN_VALID_CROSS_PRODUCT_MAG = 1.0e-3; +static const float MIN_VALID_CROSS_PRODUCT_MAG_SQ = + MIN_VALID_CROSS_PRODUCT_MAG*MIN_VALID_CROSS_PRODUCT_MAG; + +// ----------------------------------------------------------------------- + +template <typename TYPE, size_t C, size_t R> +static mat<TYPE, R, R> scaleCovariance( + const mat<TYPE, C, R>& A, + const mat<TYPE, C, C>& P) { + // A*P*transpose(A); + mat<TYPE, R, R> APAt; + for (size_t r=0 ; r<R ; r++) { + for (size_t j=r ; j<R ; j++) { + double apat(0); + for (size_t c=0 ; c<C ; c++) { + double v(A[c][r]*P[c][c]*0.5); + for (size_t k=c+1 ; k<C ; k++) + v += A[k][r] * P[c][k]; + apat += 2 * v * A[c][j]; + } + APAt[j][r] = apat; + APAt[r][j] = apat; + } + } + return APAt; +} + +template <typename TYPE, typename OTHER_TYPE> +static mat<TYPE, 3, 3> crossMatrix(const vec<TYPE, 3>& p, OTHER_TYPE diag) { + mat<TYPE, 3, 3> r; + r[0][0] = diag; + r[1][1] = diag; + r[2][2] = diag; + r[0][1] = p.z; + r[1][0] =-p.z; + r[0][2] =-p.y; + r[2][0] = p.y; + r[1][2] = p.x; + r[2][1] =-p.x; + return r; +} + + +template<typename TYPE, size_t SIZE> +class Covariance { + mat<TYPE, SIZE, SIZE> mSumXX; + vec<TYPE, SIZE> mSumX; + size_t mN; +public: + Covariance() : mSumXX(0.0f), mSumX(0.0f), mN(0) { } + void update(const vec<TYPE, SIZE>& x) { + mSumXX += x*transpose(x); + mSumX += x; + mN++; + } + mat<TYPE, SIZE, SIZE> operator()() const { + const float N = 1.0f / mN; + return mSumXX*N - (mSumX*transpose(mSumX))*(N*N); + } + void reset() { + mN = 0; + mSumXX = 0; + mSumX = 0; + } + size_t getCount() const { + return mN; + } +}; + +// ----------------------------------------------------------------------- + +Fusion::Fusion() { + Phi[0][1] = 0; + Phi[1][1] = 1; + + Ba.x = 0; + Ba.y = 0; + Ba.z = 1; + + Bm.x = 0; + Bm.y = 1; + Bm.z = 0; + + x0 = 0; + x1 = 0; + + init(); +} + +void Fusion::init() { + mInitState = 0; + + mGyroRate = 0; + + mCount[0] = 0; + mCount[1] = 0; + mCount[2] = 0; + + mData = 0; +} + +void Fusion::initFusion(const vec4_t& q, float dT) +{ + // initial estimate: E{ x(t0) } + x0 = q; + x1 = 0; + + // process noise covariance matrix: G.Q.Gt, with + // + // G = | -1 0 | Q = | q00 q10 | + // | 0 1 | | q01 q11 | + // + // q00 = sv^2.dt + 1/3.su^2.dt^3 + // q10 = q01 = 1/2.su^2.dt^2 + // q11 = su^2.dt + // + + // variance of integrated output at 1/dT Hz + // (random drift) + const float q00 = gyroVAR * dT; + + // variance of drift rate ramp + const float q11 = biasVAR * dT; + + const float u = q11 / dT; + const float q10 = 0.5f*u*dT*dT; + const float q01 = q10; + + GQGt[0][0] = q00; // rad^2 + GQGt[1][0] = -q10; + GQGt[0][1] = -q01; + GQGt[1][1] = q11; // (rad/s)^2 + + // initial covariance: Var{ x(t0) } + // TODO: initialize P correctly + P = 0; +} + +bool Fusion::hasEstimate() const { + return (mInitState == (MAG|ACC|GYRO)); +} + +bool Fusion::checkInitComplete(int what, const vec3_t& d, float dT) { + if (hasEstimate()) + return true; + + if (what == ACC) { + mData[0] += d * (1/length(d)); + mCount[0]++; + mInitState |= ACC; + } else if (what == MAG) { + mData[1] += d * (1/length(d)); + mCount[1]++; + mInitState |= MAG; + } else if (what == GYRO) { + mGyroRate = dT; + mData[2] += d*dT; + mCount[2]++; + if (mCount[2] == 64) { + // 64 samples is good enough to estimate the gyro drift and + // doesn't take too much time. + mInitState |= GYRO; + } + } + + if (mInitState == (MAG|ACC|GYRO)) { + // Average all the values we collected so far + mData[0] *= 1.0f/mCount[0]; + mData[1] *= 1.0f/mCount[1]; + mData[2] *= 1.0f/mCount[2]; + + // calculate the MRPs from the data collection, this gives us + // a rough estimate of our initial state + mat33_t R; + vec3_t up(mData[0]); + vec3_t east(cross_product(mData[1], up)); + east *= 1/length(east); + vec3_t north(cross_product(up, east)); + R << east << north << up; + const vec4_t q = matrixToQuat(R); + + initFusion(q, mGyroRate); + } + + return false; +} + +void Fusion::handleGyro(const vec3_t& w, float dT) { + if (!checkInitComplete(GYRO, w, dT)) + return; + + predict(w, dT); +} + +status_t Fusion::handleAcc(const vec3_t& a) { + // ignore acceleration data if we're close to free-fall + if (length_squared(a) < FREE_FALL_THRESHOLD_SQ) { + return BAD_VALUE; + } + + if (!checkInitComplete(ACC, a)) + return BAD_VALUE; + + const float l = 1/length(a); + update(a*l, Ba, accSTDEV*l); + return NO_ERROR; +} + +status_t Fusion::handleMag(const vec3_t& m) { + // the geomagnetic-field should be between 30uT and 60uT + // reject if too large to avoid spurious magnetic sources + const float magFieldSq = length_squared(m); + if (magFieldSq > MAX_VALID_MAGNETIC_FIELD_SQ) { + return BAD_VALUE; + } else if (magFieldSq < MIN_VALID_MAGNETIC_FIELD_SQ) { + // Also reject if too small since we will get ill-defined (zero mag) + // cross-products below + return BAD_VALUE; + } + + if (!checkInitComplete(MAG, m)) + return BAD_VALUE; + + // Orthogonalize the magnetic field to the gravity field, mapping it into + // tangent to Earth. + const vec3_t up( getRotationMatrix() * Ba ); + const vec3_t east( cross_product(m, up) ); + + // If the m and up vectors align, the cross product magnitude will + // approach 0. + // Reject this case as well to avoid div by zero problems and + // ill-conditioning below. + if (length_squared(east) < MIN_VALID_CROSS_PRODUCT_MAG_SQ) { + return BAD_VALUE; + } + + // If we have created an orthogonal magnetic field successfully, + // then pass it in as the update. + vec3_t north( cross_product(up, east) ); + + const float l = 1 / length(north); + north *= l; + + update(north, Bm, magSTDEV*l); + return NO_ERROR; +} + +void Fusion::checkState() { + // P needs to stay positive semidefinite or the fusion diverges. When we + // detect divergence, we reset the fusion. + // TODO(braun): Instead, find the reason for the divergence and fix it. + + if (!isPositiveSemidefinite(P[0][0], SYMMETRY_TOLERANCE) || + !isPositiveSemidefinite(P[1][1], SYMMETRY_TOLERANCE)) { + ALOGW("Sensor fusion diverged; resetting state."); + P = 0; + } +} + +vec4_t Fusion::getAttitude() const { + return x0; +} + +vec3_t Fusion::getBias() const { + return x1; +} + +mat33_t Fusion::getRotationMatrix() const { + return quatToMatrix(x0); +} + +mat34_t Fusion::getF(const vec4_t& q) { + mat34_t F; + F[0].x = q.w; F[1].x =-q.z; F[2].x = q.y; + F[0].y = q.z; F[1].y = q.w; F[2].y =-q.x; + F[0].z =-q.y; F[1].z = q.x; F[2].z = q.w; + F[0].w =-q.x; F[1].w =-q.y; F[2].w =-q.z; + return F; +} + +void Fusion::predict(const vec3_t& w, float dT) { + const vec4_t q = x0; + const vec3_t b = x1; + const vec3_t we = w - b; + const vec4_t dq = getF(q)*((0.5f*dT)*we); + x0 = normalize_quat(q + dq); + + // P(k+1) = Phi(k)*P(k)*Phi(k)' + G*Q(k)*G' + // + // G = | -I33 0 | + // | 0 I33 | + // + // Phi = | Phi00 Phi10 | + // | 0 1 | + // + // Phi00 = I33 + // - [w]x * sin(||w||*dt)/||w|| + // + [w]x^2 * (1-cos(||w||*dT))/||w||^2 + // + // Phi10 = [w]x * (1 - cos(||w||*dt))/||w||^2 + // - [w]x^2 * (||w||*dT - sin(||w||*dt))/||w||^3 + // - I33*dT + + const mat33_t I33(1); + const mat33_t I33dT(dT); + const mat33_t wx(crossMatrix(we, 0)); + const mat33_t wx2(wx*wx); + const float lwedT = length(we)*dT; + const float ilwe = 1/length(we); + const float k0 = (1-cosf(lwedT))*(ilwe*ilwe); + const float k1 = sinf(lwedT); + + Phi[0][0] = I33 - wx*(k1*ilwe) + wx2*k0; + Phi[1][0] = wx*k0 - I33dT - wx2*(ilwe*ilwe*ilwe)*(lwedT-k1); + + P = Phi*P*transpose(Phi) + GQGt; + + checkState(); +} + +void Fusion::update(const vec3_t& z, const vec3_t& Bi, float sigma) { + vec4_t q(x0); + // measured vector in body space: h(p) = A(p)*Bi + const mat33_t A(quatToMatrix(q)); + const vec3_t Bb(A*Bi); + + // Sensitivity matrix H = dh(p)/dp + // H = [ L 0 ] + const mat33_t L(crossMatrix(Bb, 0)); + + // gain... + // K = P*Ht / [H*P*Ht + R] + vec<mat33_t, 2> K; + const mat33_t R(sigma*sigma); + const mat33_t S(scaleCovariance(L, P[0][0]) + R); + const mat33_t Si(invert(S)); + const mat33_t LtSi(transpose(L)*Si); + K[0] = P[0][0] * LtSi; + K[1] = transpose(P[1][0])*LtSi; + + // update... + // P -= K*H*P; + const mat33_t K0L(K[0] * L); + const mat33_t K1L(K[1] * L); + P[0][0] -= K0L*P[0][0]; + P[1][1] -= K1L*P[1][0]; + P[1][0] -= K0L*P[1][0]; + P[0][1] = transpose(P[1][0]); + + const vec3_t e(z - Bb); + const vec3_t dq(K[0]*e); + const vec3_t db(K[1]*e); + + q += getF(q)*(0.5f*dq); + x0 = normalize_quat(q); + x1 += db; + + checkState(); +} + +// ----------------------------------------------------------------------- + +}; // namespace android + diff --git a/services/sensorservice/Fusion.h b/services/sensorservice/Fusion.h new file mode 100644 index 0000000..7062999 --- /dev/null +++ b/services/sensorservice/Fusion.h @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_FUSION_H +#define ANDROID_FUSION_H + +#include <utils/Errors.h> + +#include "quat.h" +#include "mat.h" +#include "vec.h" + +namespace android { + +typedef mat<float, 3, 4> mat34_t; + +class Fusion { + /* + * the state vector is made of two sub-vector containing respectively: + * - modified Rodrigues parameters + * - the estimated gyro bias + */ + quat_t x0; + vec3_t x1; + + /* + * the predicated covariance matrix is made of 4 3x3 sub-matrices and it is + * semi-definite positive. + * + * P = | P00 P10 | = | P00 P10 | + * | P01 P11 | | P10t P11 | + * + * Since P01 = transpose(P10), the code below never calculates or + * stores P01. + */ + mat<mat33_t, 2, 2> P; + + /* + * the process noise covariance matrix + */ + mat<mat33_t, 2, 2> GQGt; + +public: + Fusion(); + void init(); + void handleGyro(const vec3_t& w, float dT); + status_t handleAcc(const vec3_t& a); + status_t handleMag(const vec3_t& m); + vec4_t getAttitude() const; + vec3_t getBias() const; + mat33_t getRotationMatrix() const; + bool hasEstimate() const; + +private: + mat<mat33_t, 2, 2> Phi; + vec3_t Ba, Bm; + uint32_t mInitState; + float mGyroRate; + vec<vec3_t, 3> mData; + size_t mCount[3]; + enum { ACC=0x1, MAG=0x2, GYRO=0x4 }; + bool checkInitComplete(int, const vec3_t& w, float d = 0); + void initFusion(const vec4_t& q0, float dT); + void checkState(); + void predict(const vec3_t& w, float dT); + void update(const vec3_t& z, const vec3_t& Bi, float sigma); + static mat34_t getF(const vec4_t& p); +}; + +}; // namespace android + +#endif // ANDROID_FUSION_H diff --git a/services/sensorservice/GravitySensor.cpp b/services/sensorservice/GravitySensor.cpp new file mode 100644 index 0000000..c57715f --- /dev/null +++ b/services/sensorservice/GravitySensor.cpp @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <stdint.h> +#include <math.h> +#include <sys/types.h> + +#include <utils/Errors.h> + +#include <hardware/sensors.h> + +#include "GravitySensor.h" +#include "SensorDevice.h" +#include "SensorFusion.h" + +namespace android { +// --------------------------------------------------------------------------- + +GravitySensor::GravitySensor(sensor_t const* list, size_t count) + : mSensorDevice(SensorDevice::getInstance()), + mSensorFusion(SensorFusion::getInstance()) +{ + for (size_t i=0 ; i<count ; i++) { + if (list[i].type == SENSOR_TYPE_ACCELEROMETER) { + mAccelerometer = Sensor(list + i); + break; + } + } +} + +bool GravitySensor::process(sensors_event_t* outEvent, + const sensors_event_t& event) +{ + const static double NS2S = 1.0 / 1000000000.0; + if (event.type == SENSOR_TYPE_ACCELEROMETER) { + vec3_t g; + if (!mSensorFusion.hasEstimate()) + return false; + const mat33_t R(mSensorFusion.getRotationMatrix()); + // FIXME: we need to estimate the length of gravity because + // the accelerometer may have a small scaling error. This + // translates to an offset in the linear-acceleration sensor. + g = R[2] * GRAVITY_EARTH; + + *outEvent = event; + outEvent->data[0] = g.x; + outEvent->data[1] = g.y; + outEvent->data[2] = g.z; + outEvent->sensor = '_grv'; + outEvent->type = SENSOR_TYPE_GRAVITY; + return true; + } + return false; +} + +status_t GravitySensor::activate(void* ident, bool enabled) { + return mSensorFusion.activate(this, enabled); +} + +status_t GravitySensor::setDelay(void* ident, int handle, int64_t ns) { + return mSensorFusion.setDelay(this, ns); +} + +Sensor GravitySensor::getSensor() const { + sensor_t hwSensor; + hwSensor.name = "Gravity Sensor"; + hwSensor.vendor = "Google Inc."; + hwSensor.version = 3; + hwSensor.handle = '_grv'; + hwSensor.type = SENSOR_TYPE_GRAVITY; + hwSensor.maxRange = GRAVITY_EARTH * 2; + hwSensor.resolution = mAccelerometer.getResolution(); + hwSensor.power = mSensorFusion.getPowerUsage(); + hwSensor.minDelay = mSensorFusion.getMinDelay(); + Sensor sensor(&hwSensor); + return sensor; +} + +// --------------------------------------------------------------------------- +}; // namespace android + diff --git a/services/sensorservice/GravitySensor.h b/services/sensorservice/GravitySensor.h new file mode 100644 index 0000000..ac177c4 --- /dev/null +++ b/services/sensorservice/GravitySensor.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_GRAVITY_SENSOR_H +#define ANDROID_GRAVITY_SENSOR_H + +#include <stdint.h> +#include <sys/types.h> + +#include <gui/Sensor.h> + +#include "SensorInterface.h" + +// --------------------------------------------------------------------------- +namespace android { +// --------------------------------------------------------------------------- + +class SensorDevice; +class SensorFusion; + +class GravitySensor : public SensorInterface { + SensorDevice& mSensorDevice; + SensorFusion& mSensorFusion; + Sensor mAccelerometer; + +public: + GravitySensor(sensor_t const* list, size_t count); + virtual bool process(sensors_event_t* outEvent, + const sensors_event_t& event); + virtual status_t activate(void* ident, bool enabled); + virtual status_t setDelay(void* ident, int handle, int64_t ns); + virtual Sensor getSensor() const; + virtual bool isVirtual() const { return true; } +}; + +// --------------------------------------------------------------------------- +}; // namespace android + +#endif // ANDROID_GRAVITY_SENSOR_H diff --git a/services/sensorservice/LinearAccelerationSensor.cpp b/services/sensorservice/LinearAccelerationSensor.cpp new file mode 100644 index 0000000..f0054f2 --- /dev/null +++ b/services/sensorservice/LinearAccelerationSensor.cpp @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <stdint.h> +#include <math.h> +#include <sys/types.h> + +#include <utils/Errors.h> + +#include <hardware/sensors.h> + +#include "LinearAccelerationSensor.h" +#include "SensorDevice.h" +#include "SensorFusion.h" + +namespace android { +// --------------------------------------------------------------------------- + +LinearAccelerationSensor::LinearAccelerationSensor(sensor_t const* list, size_t count) + : mSensorDevice(SensorDevice::getInstance()), + mGravitySensor(list, count) +{ +} + +bool LinearAccelerationSensor::process(sensors_event_t* outEvent, + const sensors_event_t& event) +{ + bool result = mGravitySensor.process(outEvent, event); + if (result && event.type == SENSOR_TYPE_ACCELEROMETER) { + outEvent->data[0] = event.acceleration.x - outEvent->data[0]; + outEvent->data[1] = event.acceleration.y - outEvent->data[1]; + outEvent->data[2] = event.acceleration.z - outEvent->data[2]; + outEvent->sensor = '_lin'; + outEvent->type = SENSOR_TYPE_LINEAR_ACCELERATION; + return true; + } + return false; +} + +status_t LinearAccelerationSensor::activate(void* ident, bool enabled) { + return mGravitySensor.activate(this, enabled); +} + +status_t LinearAccelerationSensor::setDelay(void* ident, int handle, int64_t ns) { + return mGravitySensor.setDelay(this, handle, ns); +} + +Sensor LinearAccelerationSensor::getSensor() const { + Sensor gsensor(mGravitySensor.getSensor()); + sensor_t hwSensor; + hwSensor.name = "Linear Acceleration Sensor"; + hwSensor.vendor = "Google Inc."; + hwSensor.version = gsensor.getVersion(); + hwSensor.handle = '_lin'; + hwSensor.type = SENSOR_TYPE_LINEAR_ACCELERATION; + hwSensor.maxRange = gsensor.getMaxValue(); + hwSensor.resolution = gsensor.getResolution(); + hwSensor.power = gsensor.getPowerUsage(); + hwSensor.minDelay = gsensor.getMinDelay(); + Sensor sensor(&hwSensor); + return sensor; +} + +// --------------------------------------------------------------------------- +}; // namespace android + diff --git a/services/sensorservice/LinearAccelerationSensor.h b/services/sensorservice/LinearAccelerationSensor.h new file mode 100644 index 0000000..5deb24f --- /dev/null +++ b/services/sensorservice/LinearAccelerationSensor.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_LINEAR_ACCELERATION_SENSOR_H +#define ANDROID_LINEAR_ACCELERATION_SENSOR_H + +#include <stdint.h> +#include <sys/types.h> + +#include <gui/Sensor.h> + +#include "SensorInterface.h" +#include "GravitySensor.h" + +// --------------------------------------------------------------------------- +namespace android { +// --------------------------------------------------------------------------- + +class SensorDevice; +class SensorFusion; + +class LinearAccelerationSensor : public SensorInterface { + SensorDevice& mSensorDevice; + GravitySensor mGravitySensor; + + virtual bool process(sensors_event_t* outEvent, + const sensors_event_t& event); +public: + LinearAccelerationSensor(sensor_t const* list, size_t count); + virtual status_t activate(void* ident, bool enabled); + virtual status_t setDelay(void* ident, int handle, int64_t ns); + virtual Sensor getSensor() const; + virtual bool isVirtual() const { return true; } +}; + +// --------------------------------------------------------------------------- +}; // namespace android + +#endif // ANDROID_LINEAR_ACCELERATION_SENSOR_H diff --git a/services/sensorservice/OrientationSensor.cpp b/services/sensorservice/OrientationSensor.cpp new file mode 100644 index 0000000..037adaa --- /dev/null +++ b/services/sensorservice/OrientationSensor.cpp @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <stdint.h> +#include <math.h> +#include <sys/types.h> + +#include <utils/Errors.h> + +#include <hardware/sensors.h> + +#include "OrientationSensor.h" +#include "SensorDevice.h" +#include "SensorFusion.h" + +namespace android { +// --------------------------------------------------------------------------- + +OrientationSensor::OrientationSensor() + : mSensorDevice(SensorDevice::getInstance()), + mSensorFusion(SensorFusion::getInstance()) +{ +} + +bool OrientationSensor::process(sensors_event_t* outEvent, + const sensors_event_t& event) +{ + if (event.type == SENSOR_TYPE_ACCELEROMETER) { + if (mSensorFusion.hasEstimate()) { + vec3_t g; + const float rad2deg = 180 / M_PI; + const mat33_t R(mSensorFusion.getRotationMatrix()); + g[0] = atan2f(-R[1][0], R[0][0]) * rad2deg; + g[1] = atan2f(-R[2][1], R[2][2]) * rad2deg; + g[2] = asinf ( R[2][0]) * rad2deg; + if (g[0] < 0) + g[0] += 360; + + *outEvent = event; + outEvent->orientation.azimuth = g.x; + outEvent->orientation.pitch = g.y; + outEvent->orientation.roll = g.z; + outEvent->orientation.status = SENSOR_STATUS_ACCURACY_HIGH; + outEvent->sensor = '_ypr'; + outEvent->type = SENSOR_TYPE_ORIENTATION; + return true; + } + } + return false; +} + +status_t OrientationSensor::activate(void* ident, bool enabled) { + return mSensorFusion.activate(this, enabled); +} + +status_t OrientationSensor::setDelay(void* ident, int handle, int64_t ns) { + return mSensorFusion.setDelay(this, ns); +} + +Sensor OrientationSensor::getSensor() const { + sensor_t hwSensor; + hwSensor.name = "Orientation Sensor"; + hwSensor.vendor = "Google Inc."; + hwSensor.version = 1; + hwSensor.handle = '_ypr'; + hwSensor.type = SENSOR_TYPE_ORIENTATION; + hwSensor.maxRange = 360.0f; + hwSensor.resolution = 1.0f/256.0f; // FIXME: real value here + hwSensor.power = mSensorFusion.getPowerUsage(); + hwSensor.minDelay = mSensorFusion.getMinDelay(); + Sensor sensor(&hwSensor); + return sensor; +} + +// --------------------------------------------------------------------------- +}; // namespace android + diff --git a/services/sensorservice/OrientationSensor.h b/services/sensorservice/OrientationSensor.h new file mode 100644 index 0000000..855949d --- /dev/null +++ b/services/sensorservice/OrientationSensor.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_ORIENTATION_SENSOR_H +#define ANDROID_ORIENTATION_SENSOR_H + +#include <stdint.h> +#include <sys/types.h> + +#include <gui/Sensor.h> + +#include "SensorInterface.h" + +// --------------------------------------------------------------------------- +namespace android { +// --------------------------------------------------------------------------- + +class SensorDevice; +class SensorFusion; + +class OrientationSensor : public SensorInterface { + SensorDevice& mSensorDevice; + SensorFusion& mSensorFusion; + +public: + OrientationSensor(); + virtual bool process(sensors_event_t* outEvent, + const sensors_event_t& event); + virtual status_t activate(void* ident, bool enabled); + virtual status_t setDelay(void* ident, int handle, int64_t ns); + virtual Sensor getSensor() const; + virtual bool isVirtual() const { return true; } +}; + +// --------------------------------------------------------------------------- +}; // namespace android + +#endif // ANDROID_ORIENTATION_SENSOR_H diff --git a/services/sensorservice/RotationVectorSensor.cpp b/services/sensorservice/RotationVectorSensor.cpp new file mode 100644 index 0000000..5ea9568 --- /dev/null +++ b/services/sensorservice/RotationVectorSensor.cpp @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <stdint.h> +#include <math.h> +#include <sys/types.h> + +#include <utils/Errors.h> + +#include <hardware/sensors.h> + +#include "RotationVectorSensor.h" + +namespace android { +// --------------------------------------------------------------------------- + +RotationVectorSensor::RotationVectorSensor() + : mSensorDevice(SensorDevice::getInstance()), + mSensorFusion(SensorFusion::getInstance()) +{ +} + +bool RotationVectorSensor::process(sensors_event_t* outEvent, + const sensors_event_t& event) +{ + if (event.type == SENSOR_TYPE_ACCELEROMETER) { + if (mSensorFusion.hasEstimate()) { + const vec4_t q(mSensorFusion.getAttitude()); + *outEvent = event; + outEvent->data[0] = q.x; + outEvent->data[1] = q.y; + outEvent->data[2] = q.z; + outEvent->data[3] = q.w; + outEvent->sensor = '_rov'; + outEvent->type = SENSOR_TYPE_ROTATION_VECTOR; + return true; + } + } + return false; +} + +status_t RotationVectorSensor::activate(void* ident, bool enabled) { + return mSensorFusion.activate(this, enabled); +} + +status_t RotationVectorSensor::setDelay(void* ident, int handle, int64_t ns) { + return mSensorFusion.setDelay(this, ns); +} + +Sensor RotationVectorSensor::getSensor() const { + sensor_t hwSensor; + hwSensor.name = "Rotation Vector Sensor"; + hwSensor.vendor = "Google Inc."; + hwSensor.version = 3; + hwSensor.handle = '_rov'; + hwSensor.type = SENSOR_TYPE_ROTATION_VECTOR; + hwSensor.maxRange = 1; + hwSensor.resolution = 1.0f / (1<<24); + hwSensor.power = mSensorFusion.getPowerUsage(); + hwSensor.minDelay = mSensorFusion.getMinDelay(); + Sensor sensor(&hwSensor); + return sensor; +} + +// --------------------------------------------------------------------------- + +GyroDriftSensor::GyroDriftSensor() + : mSensorDevice(SensorDevice::getInstance()), + mSensorFusion(SensorFusion::getInstance()) +{ +} + +bool GyroDriftSensor::process(sensors_event_t* outEvent, + const sensors_event_t& event) +{ + if (event.type == SENSOR_TYPE_ACCELEROMETER) { + if (mSensorFusion.hasEstimate()) { + const vec3_t b(mSensorFusion.getGyroBias()); + *outEvent = event; + outEvent->data[0] = b.x; + outEvent->data[1] = b.y; + outEvent->data[2] = b.z; + outEvent->sensor = '_gbs'; + outEvent->type = SENSOR_TYPE_ACCELEROMETER; + return true; + } + } + return false; +} + +status_t GyroDriftSensor::activate(void* ident, bool enabled) { + return mSensorFusion.activate(this, enabled); +} + +status_t GyroDriftSensor::setDelay(void* ident, int handle, int64_t ns) { + return mSensorFusion.setDelay(this, ns); +} + +Sensor GyroDriftSensor::getSensor() const { + sensor_t hwSensor; + hwSensor.name = "Gyroscope Bias (debug)"; + hwSensor.vendor = "Google Inc."; + hwSensor.version = 1; + hwSensor.handle = '_gbs'; + hwSensor.type = SENSOR_TYPE_ACCELEROMETER; + hwSensor.maxRange = 1; + hwSensor.resolution = 1.0f / (1<<24); + hwSensor.power = mSensorFusion.getPowerUsage(); + hwSensor.minDelay = mSensorFusion.getMinDelay(); + Sensor sensor(&hwSensor); + return sensor; +} + +// --------------------------------------------------------------------------- +}; // namespace android + diff --git a/services/sensorservice/RotationVectorSensor.h b/services/sensorservice/RotationVectorSensor.h new file mode 100644 index 0000000..bb97fe1 --- /dev/null +++ b/services/sensorservice/RotationVectorSensor.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_ROTATION_VECTOR_SENSOR_H +#define ANDROID_ROTATION_VECTOR_SENSOR_H + +#include <stdint.h> +#include <sys/types.h> + +#include <gui/Sensor.h> + +#include "SensorDevice.h" +#include "SensorInterface.h" + +#include "Fusion.h" +#include "SensorFusion.h" + +// --------------------------------------------------------------------------- +namespace android { +// --------------------------------------------------------------------------- + +class RotationVectorSensor : public SensorInterface { + SensorDevice& mSensorDevice; + SensorFusion& mSensorFusion; + +public: + RotationVectorSensor(); + virtual bool process(sensors_event_t* outEvent, + const sensors_event_t& event); + virtual status_t activate(void* ident, bool enabled); + virtual status_t setDelay(void* ident, int handle, int64_t ns); + virtual Sensor getSensor() const; + virtual bool isVirtual() const { return true; } +}; + +class GyroDriftSensor : public SensorInterface { + SensorDevice& mSensorDevice; + SensorFusion& mSensorFusion; + +public: + GyroDriftSensor(); + virtual bool process(sensors_event_t* outEvent, + const sensors_event_t& event); + virtual status_t activate(void* ident, bool enabled); + virtual status_t setDelay(void* ident, int handle, int64_t ns); + virtual Sensor getSensor() const; + virtual bool isVirtual() const { return true; } +}; + +// --------------------------------------------------------------------------- +}; // namespace android + +#endif // ANDROID_ROTATION_VECTOR_SENSOR_H diff --git a/services/sensorservice/SensorDevice.cpp b/services/sensorservice/SensorDevice.cpp new file mode 100644 index 0000000..a9e3ef4 --- /dev/null +++ b/services/sensorservice/SensorDevice.cpp @@ -0,0 +1,213 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <stdint.h> +#include <math.h> +#include <sys/types.h> + +#include <utils/Atomic.h> +#include <utils/Errors.h> +#include <utils/Singleton.h> + +#include <binder/BinderService.h> +#include <binder/Parcel.h> +#include <binder/IServiceManager.h> + +#include <hardware/sensors.h> + +#include "SensorDevice.h" +#include "SensorService.h" + +namespace android { +// --------------------------------------------------------------------------- + +ANDROID_SINGLETON_STATIC_INSTANCE(SensorDevice) + +SensorDevice::SensorDevice() + : mSensorDevice(0), + mSensorModule(0) +{ + status_t err = hw_get_module(SENSORS_HARDWARE_MODULE_ID, + (hw_module_t const**)&mSensorModule); + + ALOGE_IF(err, "couldn't load %s module (%s)", + SENSORS_HARDWARE_MODULE_ID, strerror(-err)); + + if (mSensorModule) { + err = sensors_open(&mSensorModule->common, &mSensorDevice); + + ALOGE_IF(err, "couldn't open device for module %s (%s)", + SENSORS_HARDWARE_MODULE_ID, strerror(-err)); + + if (mSensorDevice) { + sensor_t const* list; + ssize_t count = mSensorModule->get_sensors_list(mSensorModule, &list); + mActivationCount.setCapacity(count); + Info model; + for (size_t i=0 ; i<size_t(count) ; i++) { + mActivationCount.add(list[i].handle, model); + mSensorDevice->activate(mSensorDevice, list[i].handle, 0); + } + } + } +} + +void SensorDevice::dump(String8& result, char* buffer, size_t SIZE) +{ + if (!mSensorModule) return; + sensor_t const* list; + ssize_t count = mSensorModule->get_sensors_list(mSensorModule, &list); + + snprintf(buffer, SIZE, "%d h/w sensors:\n", int(count)); + result.append(buffer); + + Mutex::Autolock _l(mLock); + for (size_t i=0 ; i<size_t(count) ; i++) { + const Info& info = mActivationCount.valueFor(list[i].handle); + snprintf(buffer, SIZE, "handle=0x%08x, active-count=%d, rates(ms)={ ", + list[i].handle, + info.rates.size()); + result.append(buffer); + for (size_t j=0 ; j<info.rates.size() ; j++) { + snprintf(buffer, SIZE, "%4.1f%s", + info.rates.valueAt(j) / 1e6f, + j<info.rates.size()-1 ? ", " : ""); + result.append(buffer); + } + snprintf(buffer, SIZE, " }, selected=%4.1f ms\n", info.delay / 1e6f); + result.append(buffer); + } +} + +ssize_t SensorDevice::getSensorList(sensor_t const** list) { + if (!mSensorModule) return NO_INIT; + ssize_t count = mSensorModule->get_sensors_list(mSensorModule, list); + return count; +} + +status_t SensorDevice::initCheck() const { + return mSensorDevice && mSensorModule ? NO_ERROR : NO_INIT; +} + +ssize_t SensorDevice::poll(sensors_event_t* buffer, size_t count) { + if (!mSensorDevice) return NO_INIT; + ssize_t c; + do { + c = mSensorDevice->poll(mSensorDevice, buffer, count); + } while (c == -EINTR); + return c; +} + +status_t SensorDevice::activate(void* ident, int handle, int enabled) +{ + if (!mSensorDevice) return NO_INIT; + status_t err(NO_ERROR); + bool actuateHardware = false; + + Info& info( mActivationCount.editValueFor(handle) ); + + + ALOGD_IF(DEBUG_CONNECTIONS, + "SensorDevice::activate: ident=%p, handle=0x%08x, enabled=%d, count=%d", + ident, handle, enabled, info.rates.size()); + + if (enabled) { + Mutex::Autolock _l(mLock); + ALOGD_IF(DEBUG_CONNECTIONS, "... index=%ld", + info.rates.indexOfKey(ident)); + + if (info.rates.indexOfKey(ident) < 0) { + info.rates.add(ident, DEFAULT_EVENTS_PERIOD); + if (info.rates.size() == 1) { + actuateHardware = true; + } + } else { + // sensor was already activated for this ident + } + } else { + Mutex::Autolock _l(mLock); + ALOGD_IF(DEBUG_CONNECTIONS, "... index=%ld", + info.rates.indexOfKey(ident)); + + ssize_t idx = info.rates.removeItem(ident); + if (idx >= 0) { + if (info.rates.size() == 0) { + actuateHardware = true; + } + } else { + // sensor wasn't enabled for this ident + } + } + + if (actuateHardware) { + ALOGD_IF(DEBUG_CONNECTIONS, "\t>>> actuating h/w"); + + err = mSensorDevice->activate(mSensorDevice, handle, enabled); + ALOGE_IF(err, "Error %s sensor %d (%s)", + enabled ? "activating" : "disabling", + handle, strerror(-err)); + } + + { // scope for the lock + Mutex::Autolock _l(mLock); + nsecs_t ns = info.selectDelay(); + mSensorDevice->setDelay(mSensorDevice, handle, ns); + } + + return err; +} + +status_t SensorDevice::setDelay(void* ident, int handle, int64_t ns) +{ + if (!mSensorDevice) return NO_INIT; + Mutex::Autolock _l(mLock); + Info& info( mActivationCount.editValueFor(handle) ); + status_t err = info.setDelayForIdent(ident, ns); + if (err < 0) return err; + ns = info.selectDelay(); + return mSensorDevice->setDelay(mSensorDevice, handle, ns); +} + +// --------------------------------------------------------------------------- + +status_t SensorDevice::Info::setDelayForIdent(void* ident, int64_t ns) +{ + ssize_t index = rates.indexOfKey(ident); + if (index < 0) { + ALOGE("Info::setDelayForIdent(ident=%p, ns=%lld) failed (%s)", + ident, ns, strerror(-index)); + return BAD_INDEX; + } + rates.editValueAt(index) = ns; + return NO_ERROR; +} + +nsecs_t SensorDevice::Info::selectDelay() +{ + nsecs_t ns = rates.valueAt(0); + for (size_t i=1 ; i<rates.size() ; i++) { + nsecs_t cur = rates.valueAt(i); + if (cur < ns) { + ns = cur; + } + } + delay = ns; + return ns; +} + +// --------------------------------------------------------------------------- +}; // namespace android + diff --git a/services/sensorservice/SensorDevice.h b/services/sensorservice/SensorDevice.h new file mode 100644 index 0000000..728b6cb --- /dev/null +++ b/services/sensorservice/SensorDevice.h @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_SENSOR_DEVICE_H +#define ANDROID_SENSOR_DEVICE_H + +#include <stdint.h> +#include <sys/types.h> + +#include <utils/KeyedVector.h> +#include <utils/Singleton.h> +#include <utils/String8.h> + +#include <gui/Sensor.h> + +// --------------------------------------------------------------------------- + +namespace android { +// --------------------------------------------------------------------------- + +static const nsecs_t DEFAULT_EVENTS_PERIOD = 200000000; // 5 Hz + +class SensorDevice : public Singleton<SensorDevice> { + friend class Singleton<SensorDevice>; + struct sensors_poll_device_t* mSensorDevice; + struct sensors_module_t* mSensorModule; + mutable Mutex mLock; // protect mActivationCount[].rates + // fixed-size array after construction + struct Info { + Info() : delay(0) { } + KeyedVector<void*, nsecs_t> rates; + nsecs_t delay; + status_t setDelayForIdent(void* ident, int64_t ns); + nsecs_t selectDelay(); + }; + DefaultKeyedVector<int, Info> mActivationCount; + + SensorDevice(); +public: + ssize_t getSensorList(sensor_t const** list); + status_t initCheck() const; + ssize_t poll(sensors_event_t* buffer, size_t count); + status_t activate(void* ident, int handle, int enabled); + status_t setDelay(void* ident, int handle, int64_t ns); + void dump(String8& result, char* buffer, size_t SIZE); +}; + +// --------------------------------------------------------------------------- +}; // namespace android + +#endif // ANDROID_SENSOR_DEVICE_H diff --git a/services/sensorservice/SensorFusion.cpp b/services/sensorservice/SensorFusion.cpp new file mode 100644 index 0000000..d23906d --- /dev/null +++ b/services/sensorservice/SensorFusion.cpp @@ -0,0 +1,148 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "SensorDevice.h" +#include "SensorFusion.h" +#include "SensorService.h" + +namespace android { +// --------------------------------------------------------------------------- + +ANDROID_SINGLETON_STATIC_INSTANCE(SensorFusion) + +SensorFusion::SensorFusion() + : mSensorDevice(SensorDevice::getInstance()), + mEnabled(false), mGyroTime(0) +{ + sensor_t const* list; + ssize_t count = mSensorDevice.getSensorList(&list); + if (count > 0) { + for (size_t i=0 ; i<size_t(count) ; i++) { + if (list[i].type == SENSOR_TYPE_ACCELEROMETER) { + mAcc = Sensor(list + i); + } + if (list[i].type == SENSOR_TYPE_MAGNETIC_FIELD) { + mMag = Sensor(list + i); + } + if (list[i].type == SENSOR_TYPE_GYROSCOPE) { + mGyro = Sensor(list + i); + // 200 Hz for gyro events is a good compromise between precision + // and power/cpu usage. + mGyroRate = 200; + mTargetDelayNs = 1000000000LL/mGyroRate; + } + } + mFusion.init(); + } +} + +void SensorFusion::process(const sensors_event_t& event) { + if (event.type == SENSOR_TYPE_GYROSCOPE) { + if (mGyroTime != 0) { + const float dT = (event.timestamp - mGyroTime) / 1000000000.0f; + const float freq = 1 / dT; + if (freq >= 100 && freq<1000) { // filter values obviously wrong + const float alpha = 1 / (1 + dT); // 1s time-constant + mGyroRate = freq + (mGyroRate - freq)*alpha; + } + } + mGyroTime = event.timestamp; + mFusion.handleGyro(vec3_t(event.data), 1.0f/mGyroRate); + } else if (event.type == SENSOR_TYPE_MAGNETIC_FIELD) { + const vec3_t mag(event.data); + mFusion.handleMag(mag); + } else if (event.type == SENSOR_TYPE_ACCELEROMETER) { + const vec3_t acc(event.data); + mFusion.handleAcc(acc); + mAttitude = mFusion.getAttitude(); + } +} + +template <typename T> inline T min(T a, T b) { return a<b ? a : b; } +template <typename T> inline T max(T a, T b) { return a>b ? a : b; } + +status_t SensorFusion::activate(void* ident, bool enabled) { + + ALOGD_IF(DEBUG_CONNECTIONS, + "SensorFusion::activate(ident=%p, enabled=%d)", + ident, enabled); + + const ssize_t idx = mClients.indexOf(ident); + if (enabled) { + if (idx < 0) { + mClients.add(ident); + } + } else { + if (idx >= 0) { + mClients.removeItemsAt(idx); + } + } + + mSensorDevice.activate(ident, mAcc.getHandle(), enabled); + mSensorDevice.activate(ident, mMag.getHandle(), enabled); + mSensorDevice.activate(ident, mGyro.getHandle(), enabled); + + const bool newState = mClients.size() != 0; + if (newState != mEnabled) { + mEnabled = newState; + if (newState) { + mFusion.init(); + mGyroTime = 0; + } + } + return NO_ERROR; +} + +status_t SensorFusion::setDelay(void* ident, int64_t ns) { + mSensorDevice.setDelay(ident, mAcc.getHandle(), ns); + mSensorDevice.setDelay(ident, mMag.getHandle(), ms2ns(20)); + mSensorDevice.setDelay(ident, mGyro.getHandle(), mTargetDelayNs); + return NO_ERROR; +} + + +float SensorFusion::getPowerUsage() const { + float power = mAcc.getPowerUsage() + + mMag.getPowerUsage() + + mGyro.getPowerUsage(); + return power; +} + +int32_t SensorFusion::getMinDelay() const { + return mAcc.getMinDelay(); +} + +void SensorFusion::dump(String8& result, char* buffer, size_t SIZE) { + const Fusion& fusion(mFusion); + snprintf(buffer, SIZE, "9-axis fusion %s (%d clients), gyro-rate=%7.2fHz, " + "q=< %g, %g, %g, %g > (%g), " + "b=< %g, %g, %g >\n", + mEnabled ? "enabled" : "disabled", + mClients.size(), + mGyroRate, + fusion.getAttitude().x, + fusion.getAttitude().y, + fusion.getAttitude().z, + fusion.getAttitude().w, + length(fusion.getAttitude()), + fusion.getBias().x, + fusion.getBias().y, + fusion.getBias().z); + result.append(buffer); +} + +// --------------------------------------------------------------------------- +}; // namespace android diff --git a/services/sensorservice/SensorFusion.h b/services/sensorservice/SensorFusion.h new file mode 100644 index 0000000..4c99bcb --- /dev/null +++ b/services/sensorservice/SensorFusion.h @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_SENSOR_FUSION_H +#define ANDROID_SENSOR_FUSION_H + +#include <stdint.h> +#include <sys/types.h> + +#include <utils/SortedVector.h> +#include <utils/Singleton.h> +#include <utils/String8.h> + +#include <gui/Sensor.h> + +#include "Fusion.h" + +// --------------------------------------------------------------------------- + +namespace android { +// --------------------------------------------------------------------------- + +class SensorDevice; + +class SensorFusion : public Singleton<SensorFusion> { + friend class Singleton<SensorFusion>; + + SensorDevice& mSensorDevice; + Sensor mAcc; + Sensor mMag; + Sensor mGyro; + Fusion mFusion; + bool mEnabled; + float mGyroRate; + nsecs_t mTargetDelayNs; + nsecs_t mGyroTime; + vec4_t mAttitude; + SortedVector<void*> mClients; + + SensorFusion(); + +public: + void process(const sensors_event_t& event); + + bool isEnabled() const { return mEnabled; } + bool hasEstimate() const { return mFusion.hasEstimate(); } + mat33_t getRotationMatrix() const { return mFusion.getRotationMatrix(); } + vec4_t getAttitude() const { return mAttitude; } + vec3_t getGyroBias() const { return mFusion.getBias(); } + float getEstimatedRate() const { return mGyroRate; } + + status_t activate(void* ident, bool enabled); + status_t setDelay(void* ident, int64_t ns); + + float getPowerUsage() const; + int32_t getMinDelay() const; + + void dump(String8& result, char* buffer, size_t SIZE); +}; + + +// --------------------------------------------------------------------------- +}; // namespace android + +#endif // ANDROID_SENSOR_FUSION_H diff --git a/services/sensorservice/SensorInterface.cpp b/services/sensorservice/SensorInterface.cpp new file mode 100644 index 0000000..468aa61 --- /dev/null +++ b/services/sensorservice/SensorInterface.cpp @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <stdint.h> +#include <sys/types.h> + +#include <cutils/log.h> + +#include "SensorInterface.h" + +namespace android { +// --------------------------------------------------------------------------- + +SensorInterface::~SensorInterface() +{ +} + +// --------------------------------------------------------------------------- + +HardwareSensor::HardwareSensor(const sensor_t& sensor) + : mSensorDevice(SensorDevice::getInstance()), + mSensor(&sensor) +{ + ALOGI("%s", sensor.name); +} + +HardwareSensor::~HardwareSensor() { +} + +bool HardwareSensor::process(sensors_event_t* outEvent, + const sensors_event_t& event) { + *outEvent = event; + return true; +} + +status_t HardwareSensor::activate(void* ident, bool enabled) { + return mSensorDevice.activate(ident, mSensor.getHandle(), enabled); +} + +status_t HardwareSensor::setDelay(void* ident, int handle, int64_t ns) { + return mSensorDevice.setDelay(ident, handle, ns); +} + +Sensor HardwareSensor::getSensor() const { + return mSensor; +} + + +// --------------------------------------------------------------------------- +}; // namespace android diff --git a/services/sensorservice/SensorInterface.h b/services/sensorservice/SensorInterface.h new file mode 100644 index 0000000..fb357d7 --- /dev/null +++ b/services/sensorservice/SensorInterface.h @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_SENSOR_INTERFACE_H +#define ANDROID_SENSOR_INTERFACE_H + +#include <stdint.h> +#include <sys/types.h> + +#include <gui/Sensor.h> + +#include "SensorDevice.h" + +// --------------------------------------------------------------------------- + +namespace android { +// --------------------------------------------------------------------------- + +class SensorInterface { +public: + virtual ~SensorInterface(); + + virtual bool process(sensors_event_t* outEvent, + const sensors_event_t& event) = 0; + + virtual status_t activate(void* ident, bool enabled) = 0; + virtual status_t setDelay(void* ident, int handle, int64_t ns) = 0; + virtual Sensor getSensor() const = 0; + virtual bool isVirtual() const = 0; +}; + +// --------------------------------------------------------------------------- + +class HardwareSensor : public SensorInterface +{ + SensorDevice& mSensorDevice; + Sensor mSensor; + +public: + HardwareSensor(const sensor_t& sensor); + + virtual ~HardwareSensor(); + + virtual bool process(sensors_event_t* outEvent, + const sensors_event_t& event); + + virtual status_t activate(void* ident, bool enabled); + virtual status_t setDelay(void* ident, int handle, int64_t ns); + virtual Sensor getSensor() const; + virtual bool isVirtual() const { return false; } +}; + + +// --------------------------------------------------------------------------- +}; // namespace android + +#endif // ANDROID_SENSOR_INTERFACE_H diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp new file mode 100644 index 0000000..e3dcd02 --- /dev/null +++ b/services/sensorservice/SensorService.cpp @@ -0,0 +1,666 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <stdint.h> +#include <math.h> +#include <sys/types.h> + +#include <cutils/properties.h> + +#include <utils/SortedVector.h> +#include <utils/KeyedVector.h> +#include <utils/threads.h> +#include <utils/Atomic.h> +#include <utils/Errors.h> +#include <utils/RefBase.h> +#include <utils/Singleton.h> +#include <utils/String16.h> + +#include <binder/BinderService.h> +#include <binder/IServiceManager.h> +#include <binder/PermissionCache.h> + +#include <gui/ISensorServer.h> +#include <gui/ISensorEventConnection.h> +#include <gui/SensorEventQueue.h> + +#include <hardware/sensors.h> + +#include "BatteryService.h" +#include "CorrectedGyroSensor.h" +#include "GravitySensor.h" +#include "LinearAccelerationSensor.h" +#include "OrientationSensor.h" +#include "RotationVectorSensor.h" +#include "SensorFusion.h" +#include "SensorService.h" + +namespace android { +// --------------------------------------------------------------------------- + +/* + * Notes: + * + * - what about a gyro-corrected magnetic-field sensor? + * - run mag sensor from time to time to force calibration + * - gravity sensor length is wrong (=> drift in linear-acc sensor) + * + */ + +SensorService::SensorService() + : mInitCheck(NO_INIT) +{ +} + +void SensorService::onFirstRef() +{ + ALOGD("nuSensorService starting..."); + + SensorDevice& dev(SensorDevice::getInstance()); + + if (dev.initCheck() == NO_ERROR) { + sensor_t const* list; + ssize_t count = dev.getSensorList(&list); + if (count > 0) { + ssize_t orientationIndex = -1; + bool hasGyro = false; + uint32_t virtualSensorsNeeds = + (1<<SENSOR_TYPE_GRAVITY) | + (1<<SENSOR_TYPE_LINEAR_ACCELERATION) | + (1<<SENSOR_TYPE_ROTATION_VECTOR); + + mLastEventSeen.setCapacity(count); + for (ssize_t i=0 ; i<count ; i++) { + registerSensor( new HardwareSensor(list[i]) ); + switch (list[i].type) { + case SENSOR_TYPE_ORIENTATION: + orientationIndex = i; + break; + case SENSOR_TYPE_GYROSCOPE: + hasGyro = true; + break; + case SENSOR_TYPE_GRAVITY: + case SENSOR_TYPE_LINEAR_ACCELERATION: + case SENSOR_TYPE_ROTATION_VECTOR: + virtualSensorsNeeds &= ~(1<<list[i].type); + break; + } + } + + // it's safe to instantiate the SensorFusion object here + // (it wants to be instantiated after h/w sensors have been + // registered) + const SensorFusion& fusion(SensorFusion::getInstance()); + + if (hasGyro) { + // Always instantiate Android's virtual sensors. Since they are + // instantiated behind sensors from the HAL, they won't + // interfere with applications, unless they looks specifically + // for them (by name). + + registerVirtualSensor( new RotationVectorSensor() ); + registerVirtualSensor( new GravitySensor(list, count) ); + registerVirtualSensor( new LinearAccelerationSensor(list, count) ); + + // these are optional + registerVirtualSensor( new OrientationSensor() ); + registerVirtualSensor( new CorrectedGyroSensor(list, count) ); + } + + // build the sensor list returned to users + mUserSensorList = mSensorList; + + if (hasGyro) { + // virtual debugging sensors are not added to mUserSensorList + registerVirtualSensor( new GyroDriftSensor() ); + } + + if (hasGyro && + (virtualSensorsNeeds & (1<<SENSOR_TYPE_ROTATION_VECTOR))) { + // if we have the fancy sensor fusion, and it's not provided by the + // HAL, use our own (fused) orientation sensor by removing the + // HAL supplied one form the user list. + if (orientationIndex >= 0) { + mUserSensorList.removeItemsAt(orientationIndex); + } + } + + // debugging sensor list + for (size_t i=0 ; i<mSensorList.size() ; i++) { + switch (mSensorList[i].getType()) { + case SENSOR_TYPE_GRAVITY: + case SENSOR_TYPE_LINEAR_ACCELERATION: + case SENSOR_TYPE_ROTATION_VECTOR: + if (strstr(mSensorList[i].getVendor().string(), "Google")) { + mUserSensorListDebug.add(mSensorList[i]); + } + break; + default: + mUserSensorListDebug.add(mSensorList[i]); + break; + } + } + + run("SensorService", PRIORITY_URGENT_DISPLAY); + mInitCheck = NO_ERROR; + } + } +} + +void SensorService::registerSensor(SensorInterface* s) +{ + sensors_event_t event; + memset(&event, 0, sizeof(event)); + + const Sensor sensor(s->getSensor()); + // add to the sensor list (returned to clients) + mSensorList.add(sensor); + // add to our handle->SensorInterface mapping + mSensorMap.add(sensor.getHandle(), s); + // create an entry in the mLastEventSeen array + mLastEventSeen.add(sensor.getHandle(), event); +} + +void SensorService::registerVirtualSensor(SensorInterface* s) +{ + registerSensor(s); + mVirtualSensorList.add( s ); +} + +SensorService::~SensorService() +{ + for (size_t i=0 ; i<mSensorMap.size() ; i++) + delete mSensorMap.valueAt(i); +} + +static const String16 sDump("android.permission.DUMP"); + +status_t SensorService::dump(int fd, const Vector<String16>& args) +{ + const size_t SIZE = 1024; + char buffer[SIZE]; + String8 result; + if (!PermissionCache::checkCallingPermission(sDump)) { + snprintf(buffer, SIZE, "Permission Denial: " + "can't dump SurfaceFlinger from pid=%d, uid=%d\n", + IPCThreadState::self()->getCallingPid(), + IPCThreadState::self()->getCallingUid()); + result.append(buffer); + } else { + Mutex::Autolock _l(mLock); + snprintf(buffer, SIZE, "Sensor List:\n"); + result.append(buffer); + for (size_t i=0 ; i<mSensorList.size() ; i++) { + const Sensor& s(mSensorList[i]); + const sensors_event_t& e(mLastEventSeen.valueFor(s.getHandle())); + snprintf(buffer, SIZE, + "%-48s| %-32s | 0x%08x | maxRate=%7.2fHz | " + "last=<%5.1f,%5.1f,%5.1f>\n", + s.getName().string(), + s.getVendor().string(), + s.getHandle(), + s.getMinDelay() ? (1000000.0f / s.getMinDelay()) : 0.0f, + e.data[0], e.data[1], e.data[2]); + result.append(buffer); + } + SensorFusion::getInstance().dump(result, buffer, SIZE); + SensorDevice::getInstance().dump(result, buffer, SIZE); + + snprintf(buffer, SIZE, "%d active connections\n", + mActiveConnections.size()); + result.append(buffer); + snprintf(buffer, SIZE, "Active sensors:\n"); + result.append(buffer); + for (size_t i=0 ; i<mActiveSensors.size() ; i++) { + int handle = mActiveSensors.keyAt(i); + snprintf(buffer, SIZE, "%s (handle=0x%08x, connections=%d)\n", + getSensorName(handle).string(), + handle, + mActiveSensors.valueAt(i)->getNumConnections()); + result.append(buffer); + } + } + write(fd, result.string(), result.size()); + return NO_ERROR; +} + +bool SensorService::threadLoop() +{ + ALOGD("nuSensorService thread starting..."); + + const size_t numEventMax = 16; + const size_t minBufferSize = numEventMax + numEventMax * mVirtualSensorList.size(); + sensors_event_t buffer[minBufferSize]; + sensors_event_t scratch[minBufferSize]; + SensorDevice& device(SensorDevice::getInstance()); + const size_t vcount = mVirtualSensorList.size(); + + ssize_t count; + do { + count = device.poll(buffer, numEventMax); + if (count<0) { + ALOGE("sensor poll failed (%s)", strerror(-count)); + break; + } + + recordLastValue(buffer, count); + + // handle virtual sensors + if (count && vcount) { + sensors_event_t const * const event = buffer; + const DefaultKeyedVector<int, SensorInterface*> virtualSensors( + getActiveVirtualSensors()); + const size_t activeVirtualSensorCount = virtualSensors.size(); + if (activeVirtualSensorCount) { + size_t k = 0; + SensorFusion& fusion(SensorFusion::getInstance()); + if (fusion.isEnabled()) { + for (size_t i=0 ; i<size_t(count) ; i++) { + fusion.process(event[i]); + } + } + for (size_t i=0 ; i<size_t(count) && k<minBufferSize ; i++) { + for (size_t j=0 ; j<activeVirtualSensorCount ; j++) { + if (count + k >= minBufferSize) { + ALOGE("buffer too small to hold all events: " + "count=%u, k=%u, size=%u", + count, k, minBufferSize); + break; + } + sensors_event_t out; + SensorInterface* si = virtualSensors.valueAt(j); + if (si->process(&out, event[i])) { + buffer[count + k] = out; + k++; + } + } + } + if (k) { + // record the last synthesized values + recordLastValue(&buffer[count], k); + count += k; + // sort the buffer by time-stamps + sortEventBuffer(buffer, count); + } + } + } + + // send our events to clients... + const SortedVector< wp<SensorEventConnection> > activeConnections( + getActiveConnections()); + size_t numConnections = activeConnections.size(); + for (size_t i=0 ; i<numConnections ; i++) { + sp<SensorEventConnection> connection( + activeConnections[i].promote()); + if (connection != 0) { + connection->sendEvents(buffer, count, scratch); + } + } + } while (count >= 0 || Thread::exitPending()); + + ALOGW("Exiting SensorService::threadLoop => aborting..."); + abort(); + return false; +} + +void SensorService::recordLastValue( + sensors_event_t const * buffer, size_t count) +{ + Mutex::Autolock _l(mLock); + + // record the last event for each sensor + int32_t prev = buffer[0].sensor; + for (size_t i=1 ; i<count ; i++) { + // record the last event of each sensor type in this buffer + int32_t curr = buffer[i].sensor; + if (curr != prev) { + mLastEventSeen.editValueFor(prev) = buffer[i-1]; + prev = curr; + } + } + mLastEventSeen.editValueFor(prev) = buffer[count-1]; +} + +void SensorService::sortEventBuffer(sensors_event_t* buffer, size_t count) +{ + struct compar { + static int cmp(void const* lhs, void const* rhs) { + sensors_event_t const* l = static_cast<sensors_event_t const*>(lhs); + sensors_event_t const* r = static_cast<sensors_event_t const*>(rhs); + return l->timestamp - r->timestamp; + } + }; + qsort(buffer, count, sizeof(sensors_event_t), compar::cmp); +} + +SortedVector< wp<SensorService::SensorEventConnection> > +SensorService::getActiveConnections() const +{ + Mutex::Autolock _l(mLock); + return mActiveConnections; +} + +DefaultKeyedVector<int, SensorInterface*> +SensorService::getActiveVirtualSensors() const +{ + Mutex::Autolock _l(mLock); + return mActiveVirtualSensors; +} + +String8 SensorService::getSensorName(int handle) const { + size_t count = mUserSensorList.size(); + for (size_t i=0 ; i<count ; i++) { + const Sensor& sensor(mUserSensorList[i]); + if (sensor.getHandle() == handle) { + return sensor.getName(); + } + } + String8 result("unknown"); + return result; +} + +Vector<Sensor> SensorService::getSensorList() +{ + char value[PROPERTY_VALUE_MAX]; + property_get("debug.sensors", value, "0"); + if (atoi(value)) { + return mUserSensorListDebug; + } + return mUserSensorList; +} + +sp<ISensorEventConnection> SensorService::createSensorEventConnection() +{ + uid_t uid = IPCThreadState::self()->getCallingUid(); + sp<SensorEventConnection> result(new SensorEventConnection(this, uid)); + return result; +} + +void SensorService::cleanupConnection(SensorEventConnection* c) +{ + Mutex::Autolock _l(mLock); + const wp<SensorEventConnection> connection(c); + size_t size = mActiveSensors.size(); + ALOGD_IF(DEBUG_CONNECTIONS, "%d active sensors", size); + for (size_t i=0 ; i<size ; ) { + int handle = mActiveSensors.keyAt(i); + if (c->hasSensor(handle)) { + ALOGD_IF(DEBUG_CONNECTIONS, "%i: disabling handle=0x%08x", i, handle); + SensorInterface* sensor = mSensorMap.valueFor( handle ); + ALOGE_IF(!sensor, "mSensorMap[handle=0x%08x] is null!", handle); + if (sensor) { + sensor->activate(c, false); + } + } + SensorRecord* rec = mActiveSensors.valueAt(i); + ALOGE_IF(!rec, "mActiveSensors[%d] is null (handle=0x%08x)!", i, handle); + ALOGD_IF(DEBUG_CONNECTIONS, + "removing connection %p for sensor[%d].handle=0x%08x", + c, i, handle); + + if (rec && rec->removeConnection(connection)) { + ALOGD_IF(DEBUG_CONNECTIONS, "... and it was the last connection"); + mActiveSensors.removeItemsAt(i, 1); + mActiveVirtualSensors.removeItem(handle); + delete rec; + size--; + } else { + i++; + } + } + mActiveConnections.remove(connection); + BatteryService::cleanup(c->getUid()); +} + +status_t SensorService::enable(const sp<SensorEventConnection>& connection, + int handle) +{ + if (mInitCheck != NO_ERROR) + return mInitCheck; + + Mutex::Autolock _l(mLock); + SensorInterface* sensor = mSensorMap.valueFor(handle); + status_t err = sensor ? sensor->activate(connection.get(), true) : status_t(BAD_VALUE); + if (err == NO_ERROR) { + SensorRecord* rec = mActiveSensors.valueFor(handle); + if (rec == 0) { + rec = new SensorRecord(connection); + mActiveSensors.add(handle, rec); + if (sensor->isVirtual()) { + mActiveVirtualSensors.add(handle, sensor); + } + } else { + if (rec->addConnection(connection)) { + // this sensor is already activated, but we are adding a + // connection that uses it. Immediately send down the last + // known value of the requested sensor if it's not a + // "continuous" sensor. + if (sensor->getSensor().getMinDelay() == 0) { + sensors_event_t scratch; + sensors_event_t& event(mLastEventSeen.editValueFor(handle)); + if (event.version == sizeof(sensors_event_t)) { + connection->sendEvents(&event, 1); + } + } + } + } + if (err == NO_ERROR) { + // connection now active + if (connection->addSensor(handle)) { + BatteryService::enableSensor(connection->getUid(), handle); + // the sensor was added (which means it wasn't already there) + // so, see if this connection becomes active + if (mActiveConnections.indexOf(connection) < 0) { + mActiveConnections.add(connection); + } + } else { + ALOGW("sensor %08x already enabled in connection %p (ignoring)", + handle, connection.get()); + } + } + } + return err; +} + +status_t SensorService::disable(const sp<SensorEventConnection>& connection, + int handle) +{ + if (mInitCheck != NO_ERROR) + return mInitCheck; + + status_t err = NO_ERROR; + Mutex::Autolock _l(mLock); + SensorRecord* rec = mActiveSensors.valueFor(handle); + if (rec) { + // see if this connection becomes inactive + if (connection->removeSensor(handle)) { + BatteryService::disableSensor(connection->getUid(), handle); + } + if (connection->hasAnySensor() == false) { + mActiveConnections.remove(connection); + } + // see if this sensor becomes inactive + if (rec->removeConnection(connection)) { + mActiveSensors.removeItem(handle); + mActiveVirtualSensors.removeItem(handle); + delete rec; + } + SensorInterface* sensor = mSensorMap.valueFor(handle); + err = sensor ? sensor->activate(connection.get(), false) : status_t(BAD_VALUE); + } + return err; +} + +status_t SensorService::setEventRate(const sp<SensorEventConnection>& connection, + int handle, nsecs_t ns) +{ + if (mInitCheck != NO_ERROR) + return mInitCheck; + + SensorInterface* sensor = mSensorMap.valueFor(handle); + if (!sensor) + return BAD_VALUE; + + if (ns < 0) + return BAD_VALUE; + + nsecs_t minDelayNs = sensor->getSensor().getMinDelayNs(); + if (ns < minDelayNs) { + ns = minDelayNs; + } + + if (ns < MINIMUM_EVENTS_PERIOD) + ns = MINIMUM_EVENTS_PERIOD; + + return sensor->setDelay(connection.get(), handle, ns); +} + +// --------------------------------------------------------------------------- + +SensorService::SensorRecord::SensorRecord( + const sp<SensorEventConnection>& connection) +{ + mConnections.add(connection); +} + +bool SensorService::SensorRecord::addConnection( + const sp<SensorEventConnection>& connection) +{ + if (mConnections.indexOf(connection) < 0) { + mConnections.add(connection); + return true; + } + return false; +} + +bool SensorService::SensorRecord::removeConnection( + const wp<SensorEventConnection>& connection) +{ + ssize_t index = mConnections.indexOf(connection); + if (index >= 0) { + mConnections.removeItemsAt(index, 1); + } + return mConnections.size() ? false : true; +} + +// --------------------------------------------------------------------------- + +SensorService::SensorEventConnection::SensorEventConnection( + const sp<SensorService>& service, uid_t uid) + : mService(service), mChannel(new BitTube()), mUid(uid) +{ +} + +SensorService::SensorEventConnection::~SensorEventConnection() +{ + ALOGD_IF(DEBUG_CONNECTIONS, "~SensorEventConnection(%p)", this); + mService->cleanupConnection(this); +} + +void SensorService::SensorEventConnection::onFirstRef() +{ +} + +bool SensorService::SensorEventConnection::addSensor(int32_t handle) { + Mutex::Autolock _l(mConnectionLock); + if (mSensorInfo.indexOf(handle) < 0) { + mSensorInfo.add(handle); + return true; + } + return false; +} + +bool SensorService::SensorEventConnection::removeSensor(int32_t handle) { + Mutex::Autolock _l(mConnectionLock); + if (mSensorInfo.remove(handle) >= 0) { + return true; + } + return false; +} + +bool SensorService::SensorEventConnection::hasSensor(int32_t handle) const { + Mutex::Autolock _l(mConnectionLock); + return mSensorInfo.indexOf(handle) >= 0; +} + +bool SensorService::SensorEventConnection::hasAnySensor() const { + Mutex::Autolock _l(mConnectionLock); + return mSensorInfo.size() ? true : false; +} + +status_t SensorService::SensorEventConnection::sendEvents( + sensors_event_t const* buffer, size_t numEvents, + sensors_event_t* scratch) +{ + // filter out events not for this connection + size_t count = 0; + if (scratch) { + Mutex::Autolock _l(mConnectionLock); + size_t i=0; + while (i<numEvents) { + const int32_t curr = buffer[i].sensor; + if (mSensorInfo.indexOf(curr) >= 0) { + do { + scratch[count++] = buffer[i++]; + } while ((i<numEvents) && (buffer[i].sensor == curr)); + } else { + i++; + } + } + } else { + scratch = const_cast<sensors_event_t *>(buffer); + count = numEvents; + } + + // NOTE: ASensorEvent and sensors_event_t are the same type + ssize_t size = SensorEventQueue::write(mChannel, + reinterpret_cast<ASensorEvent const*>(scratch), count); + if (size == -EAGAIN) { + // the destination doesn't accept events anymore, it's probably + // full. For now, we just drop the events on the floor. + //ALOGW("dropping %d events on the floor", count); + return size; + } + + return size < 0 ? status_t(size) : status_t(NO_ERROR); +} + +sp<BitTube> SensorService::SensorEventConnection::getSensorChannel() const +{ + return mChannel; +} + +status_t SensorService::SensorEventConnection::enableDisable( + int handle, bool enabled) +{ + status_t err; + if (enabled) { + err = mService->enable(this, handle); + } else { + err = mService->disable(this, handle); + } + return err; +} + +status_t SensorService::SensorEventConnection::setEventRate( + int handle, nsecs_t ns) +{ + return mService->setEventRate(this, handle, ns); +} + +// --------------------------------------------------------------------------- +}; // namespace android + diff --git a/services/sensorservice/SensorService.h b/services/sensorservice/SensorService.h new file mode 100644 index 0000000..18591bf --- /dev/null +++ b/services/sensorservice/SensorService.h @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_SENSOR_SERVICE_H +#define ANDROID_SENSOR_SERVICE_H + +#include <stdint.h> +#include <sys/types.h> + +#include <utils/Vector.h> +#include <utils/SortedVector.h> +#include <utils/KeyedVector.h> +#include <utils/threads.h> +#include <utils/RefBase.h> + +#include <binder/BinderService.h> + +#include <gui/Sensor.h> +#include <gui/BitTube.h> +#include <gui/ISensorServer.h> +#include <gui/ISensorEventConnection.h> + +#include "SensorInterface.h" + +// --------------------------------------------------------------------------- + +#define DEBUG_CONNECTIONS false + +struct sensors_poll_device_t; +struct sensors_module_t; + +namespace android { +// --------------------------------------------------------------------------- + +class SensorService : + public BinderService<SensorService>, + public BnSensorServer, + protected Thread +{ + friend class BinderService<SensorService>; + + static const nsecs_t MINIMUM_EVENTS_PERIOD = 1000000; // 1000 Hz + + SensorService(); + virtual ~SensorService(); + + virtual void onFirstRef(); + + // Thread interface + virtual bool threadLoop(); + + // ISensorServer interface + virtual Vector<Sensor> getSensorList(); + virtual sp<ISensorEventConnection> createSensorEventConnection(); + virtual status_t dump(int fd, const Vector<String16>& args); + + + class SensorEventConnection : public BnSensorEventConnection { + virtual ~SensorEventConnection(); + virtual void onFirstRef(); + virtual sp<BitTube> getSensorChannel() const; + virtual status_t enableDisable(int handle, bool enabled); + virtual status_t setEventRate(int handle, nsecs_t ns); + + sp<SensorService> const mService; + sp<BitTube> const mChannel; + uid_t mUid; + mutable Mutex mConnectionLock; + + // protected by SensorService::mLock + SortedVector<int> mSensorInfo; + + public: + SensorEventConnection(const sp<SensorService>& service, uid_t uid); + + status_t sendEvents(sensors_event_t const* buffer, size_t count, + sensors_event_t* scratch = NULL); + bool hasSensor(int32_t handle) const; + bool hasAnySensor() const; + bool addSensor(int32_t handle); + bool removeSensor(int32_t handle); + + uid_t getUid() const { return mUid; } + }; + + class SensorRecord { + SortedVector< wp<SensorEventConnection> > mConnections; + public: + SensorRecord(const sp<SensorEventConnection>& connection); + bool addConnection(const sp<SensorEventConnection>& connection); + bool removeConnection(const wp<SensorEventConnection>& connection); + size_t getNumConnections() const { return mConnections.size(); } + }; + + SortedVector< wp<SensorEventConnection> > getActiveConnections() const; + DefaultKeyedVector<int, SensorInterface*> getActiveVirtualSensors() const; + + String8 getSensorName(int handle) const; + void recordLastValue(sensors_event_t const * buffer, size_t count); + static void sortEventBuffer(sensors_event_t* buffer, size_t count); + void registerSensor(SensorInterface* sensor); + void registerVirtualSensor(SensorInterface* sensor); + + // constants + Vector<Sensor> mSensorList; + Vector<Sensor> mUserSensorListDebug; + Vector<Sensor> mUserSensorList; + DefaultKeyedVector<int, SensorInterface*> mSensorMap; + Vector<SensorInterface *> mVirtualSensorList; + status_t mInitCheck; + + // protected by mLock + mutable Mutex mLock; + DefaultKeyedVector<int, SensorRecord*> mActiveSensors; + DefaultKeyedVector<int, SensorInterface*> mActiveVirtualSensors; + SortedVector< wp<SensorEventConnection> > mActiveConnections; + + // The size of this vector is constant, only the items are mutable + KeyedVector<int32_t, sensors_event_t> mLastEventSeen; + +public: + static char const* getServiceName() { return "sensorservice"; } + + void cleanupConnection(SensorEventConnection* connection); + status_t enable(const sp<SensorEventConnection>& connection, int handle); + status_t disable(const sp<SensorEventConnection>& connection, int handle); + status_t setEventRate(const sp<SensorEventConnection>& connection, int handle, nsecs_t ns); +}; + +// --------------------------------------------------------------------------- +}; // namespace android + +#endif // ANDROID_SENSOR_SERVICE_H diff --git a/services/sensorservice/mat.h b/services/sensorservice/mat.h new file mode 100644 index 0000000..a76fc91 --- /dev/null +++ b/services/sensorservice/mat.h @@ -0,0 +1,393 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_MAT_H +#define ANDROID_MAT_H + +#include "vec.h" +#include "traits.h" + +// ----------------------------------------------------------------------- + +namespace android { + +template <typename TYPE, size_t C, size_t R> +class mat; + +namespace helpers { + +template <typename TYPE, size_t C, size_t R> +mat<TYPE, C, R>& doAssign( + mat<TYPE, C, R>& lhs, + typename TypeTraits<TYPE>::ParameterType rhs) { + for (size_t i=0 ; i<C ; i++) + for (size_t j=0 ; j<R ; j++) + lhs[i][j] = (i==j) ? rhs : 0; + return lhs; +} + +template <typename TYPE, size_t C, size_t R, size_t D> +mat<TYPE, C, R> PURE doMul( + const mat<TYPE, D, R>& lhs, + const mat<TYPE, C, D>& rhs) +{ + mat<TYPE, C, R> res; + for (size_t c=0 ; c<C ; c++) { + for (size_t r=0 ; r<R ; r++) { + TYPE v(0); + for (size_t k=0 ; k<D ; k++) { + v += lhs[k][r] * rhs[c][k]; + } + res[c][r] = v; + } + } + return res; +} + +template <typename TYPE, size_t R, size_t D> +vec<TYPE, R> PURE doMul( + const mat<TYPE, D, R>& lhs, + const vec<TYPE, D>& rhs) +{ + vec<TYPE, R> res; + for (size_t r=0 ; r<R ; r++) { + TYPE v(0); + for (size_t k=0 ; k<D ; k++) { + v += lhs[k][r] * rhs[k]; + } + res[r] = v; + } + return res; +} + +template <typename TYPE, size_t C, size_t R> +mat<TYPE, C, R> PURE doMul( + const vec<TYPE, R>& lhs, + const mat<TYPE, C, 1>& rhs) +{ + mat<TYPE, C, R> res; + for (size_t c=0 ; c<C ; c++) { + for (size_t r=0 ; r<R ; r++) { + res[c][r] = lhs[r] * rhs[c][0]; + } + } + return res; +} + +template <typename TYPE, size_t C, size_t R> +mat<TYPE, C, R> PURE doMul( + const mat<TYPE, C, R>& rhs, + typename TypeTraits<TYPE>::ParameterType v) +{ + mat<TYPE, C, R> res; + for (size_t c=0 ; c<C ; c++) { + for (size_t r=0 ; r<R ; r++) { + res[c][r] = rhs[c][r] * v; + } + } + return res; +} + +template <typename TYPE, size_t C, size_t R> +mat<TYPE, C, R> PURE doMul( + typename TypeTraits<TYPE>::ParameterType v, + const mat<TYPE, C, R>& rhs) +{ + mat<TYPE, C, R> res; + for (size_t c=0 ; c<C ; c++) { + for (size_t r=0 ; r<R ; r++) { + res[c][r] = v * rhs[c][r]; + } + } + return res; +} + + +}; // namespace helpers + +// ----------------------------------------------------------------------- + +template <typename TYPE, size_t C, size_t R> +class mat : public vec< vec<TYPE, R>, C > { + typedef typename TypeTraits<TYPE>::ParameterType pTYPE; + typedef vec< vec<TYPE, R>, C > base; +public: + // STL-like interface. + typedef TYPE value_type; + typedef TYPE& reference; + typedef TYPE const& const_reference; + typedef size_t size_type; + size_type size() const { return R*C; } + enum { ROWS = R, COLS = C }; + + + // ----------------------------------------------------------------------- + // default constructors + + mat() { } + mat(const mat& rhs) : base(rhs) { } + mat(const base& rhs) : base(rhs) { } + + // ----------------------------------------------------------------------- + // conversion constructors + + // sets the diagonal to the value, off-diagonal to zero + mat(pTYPE rhs) { + helpers::doAssign(*this, rhs); + } + + // ----------------------------------------------------------------------- + // Assignment + + mat& operator=(const mat& rhs) { + base::operator=(rhs); + return *this; + } + + mat& operator=(const base& rhs) { + base::operator=(rhs); + return *this; + } + + mat& operator=(pTYPE rhs) { + return helpers::doAssign(*this, rhs); + } + + // ----------------------------------------------------------------------- + // non-member function declaration and definition + + friend inline mat PURE operator + (const mat& lhs, const mat& rhs) { + return helpers::doAdd( + static_cast<const base&>(lhs), + static_cast<const base&>(rhs)); + } + friend inline mat PURE operator - (const mat& lhs, const mat& rhs) { + return helpers::doSub( + static_cast<const base&>(lhs), + static_cast<const base&>(rhs)); + } + + // matrix*matrix + template <size_t D> + friend mat PURE operator * ( + const mat<TYPE, D, R>& lhs, + const mat<TYPE, C, D>& rhs) { + return helpers::doMul(lhs, rhs); + } + + // matrix*vector + friend vec<TYPE, R> PURE operator * ( + const mat& lhs, const vec<TYPE, C>& rhs) { + return helpers::doMul(lhs, rhs); + } + + // vector*matrix + friend mat PURE operator * ( + const vec<TYPE, R>& lhs, const mat<TYPE, C, 1>& rhs) { + return helpers::doMul(lhs, rhs); + } + + // matrix*scalar + friend inline mat PURE operator * (const mat& lhs, pTYPE v) { + return helpers::doMul(lhs, v); + } + + // scalar*matrix + friend inline mat PURE operator * (pTYPE v, const mat& rhs) { + return helpers::doMul(v, rhs); + } + + // ----------------------------------------------------------------------- + // streaming operator to set the columns of the matrix: + // example: + // mat33_t m; + // m << v0 << v1 << v2; + + // column_builder<> stores the matrix and knows which column to set + template<size_t PREV_COLUMN> + struct column_builder { + mat& matrix; + column_builder(mat& matrix) : matrix(matrix) { } + }; + + // operator << is not a method of column_builder<> so we can + // overload it for unauthorized values (partial specialization + // not allowed in class-scope). + // we just set the column and return the next column_builder<> + template<size_t PREV_COLUMN> + friend column_builder<PREV_COLUMN+1> operator << ( + const column_builder<PREV_COLUMN>& lhs, + const vec<TYPE, R>& rhs) { + lhs.matrix[PREV_COLUMN+1] = rhs; + return column_builder<PREV_COLUMN+1>(lhs.matrix); + } + + // we return void here so we get a compile-time error if the + // user tries to set too many columns + friend void operator << ( + const column_builder<C-2>& lhs, + const vec<TYPE, R>& rhs) { + lhs.matrix[C-1] = rhs; + } + + // this is where the process starts. we set the first columns and + // return the next column_builder<> + column_builder<0> operator << (const vec<TYPE, R>& rhs) { + (*this)[0] = rhs; + return column_builder<0>(*this); + } +}; + +// Specialize column matrix so they're exactly equivalent to a vector +template <typename TYPE, size_t R> +class mat<TYPE, 1, R> : public vec<TYPE, R> { + typedef vec<TYPE, R> base; +public: + // STL-like interface. + typedef TYPE value_type; + typedef TYPE& reference; + typedef TYPE const& const_reference; + typedef size_t size_type; + size_type size() const { return R; } + enum { ROWS = R, COLS = 1 }; + + mat() { } + mat(const base& rhs) : base(rhs) { } + mat(const mat& rhs) : base(rhs) { } + mat(const TYPE& rhs) { helpers::doAssign(*this, rhs); } + mat& operator=(const mat& rhs) { base::operator=(rhs); return *this; } + mat& operator=(const base& rhs) { base::operator=(rhs); return *this; } + mat& operator=(const TYPE& rhs) { return helpers::doAssign(*this, rhs); } + // we only have one column, so ignore the index + const base& operator[](size_t) const { return *this; } + base& operator[](size_t) { return *this; } + void operator << (const vec<TYPE, R>& rhs) { base::operator[](0) = rhs; } +}; + +// ----------------------------------------------------------------------- +// matrix functions + +// transpose. this handles matrices of matrices +inline int PURE transpose(int v) { return v; } +inline float PURE transpose(float v) { return v; } +inline double PURE transpose(double v) { return v; } + +// Transpose a matrix +template <typename TYPE, size_t C, size_t R> +mat<TYPE, R, C> PURE transpose(const mat<TYPE, C, R>& m) { + mat<TYPE, R, C> r; + for (size_t i=0 ; i<R ; i++) + for (size_t j=0 ; j<C ; j++) + r[i][j] = transpose(m[j][i]); + return r; +} + +// Calculate the trace of a matrix +template <typename TYPE, size_t C> static TYPE trace(const mat<TYPE, C, C>& m) { + TYPE t; + for (size_t i=0 ; i<C ; i++) + t += m[i][i]; + return t; +} + +// Test positive-semidefiniteness of a matrix +template <typename TYPE, size_t C> +static bool isPositiveSemidefinite(const mat<TYPE, C, C>& m, TYPE tolerance) { + for (size_t i=0 ; i<C ; i++) + if (m[i][i] < 0) + return false; + + for (size_t i=0 ; i<C ; i++) + for (size_t j=i+1 ; j<C ; j++) + if (fabs(m[i][j] - m[j][i]) > tolerance) + return false; + + return true; +} + +// Transpose a vector +template < + template<typename T, size_t S> class VEC, + typename TYPE, + size_t SIZE +> +mat<TYPE, SIZE, 1> PURE transpose(const VEC<TYPE, SIZE>& v) { + mat<TYPE, SIZE, 1> r; + for (size_t i=0 ; i<SIZE ; i++) + r[i][0] = transpose(v[i]); + return r; +} + +// ----------------------------------------------------------------------- +// "dumb" matrix inversion +template<typename T, size_t N> +mat<T, N, N> PURE invert(const mat<T, N, N>& src) { + T t; + size_t swap; + mat<T, N, N> tmp(src); + mat<T, N, N> inverse(1); + + for (size_t i=0 ; i<N ; i++) { + // look for largest element in column + swap = i; + for (size_t j=i+1 ; j<N ; j++) { + if (fabs(tmp[j][i]) > fabs(tmp[i][i])) { + swap = j; + } + } + + if (swap != i) { + /* swap rows. */ + for (size_t k=0 ; k<N ; k++) { + t = tmp[i][k]; + tmp[i][k] = tmp[swap][k]; + tmp[swap][k] = t; + + t = inverse[i][k]; + inverse[i][k] = inverse[swap][k]; + inverse[swap][k] = t; + } + } + + t = 1 / tmp[i][i]; + for (size_t k=0 ; k<N ; k++) { + tmp[i][k] *= t; + inverse[i][k] *= t; + } + for (size_t j=0 ; j<N ; j++) { + if (j != i) { + t = tmp[j][i]; + for (size_t k=0 ; k<N ; k++) { + tmp[j][k] -= tmp[i][k] * t; + inverse[j][k] -= inverse[i][k] * t; + } + } + } + } + return inverse; +} + +// ----------------------------------------------------------------------- + +typedef mat<float, 2, 2> mat22_t; +typedef mat<float, 3, 3> mat33_t; +typedef mat<float, 4, 4> mat44_t; + +// ----------------------------------------------------------------------- + +}; // namespace android + +#endif /* ANDROID_MAT_H */ diff --git a/services/sensorservice/quat.h b/services/sensorservice/quat.h new file mode 100644 index 0000000..fea1afe --- /dev/null +++ b/services/sensorservice/quat.h @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_QUAT_H +#define ANDROID_QUAT_H + +#include <math.h> + +#include "vec.h" +#include "mat.h" + +// ----------------------------------------------------------------------- +namespace android { +// ----------------------------------------------------------------------- + +template <typename TYPE> +mat<TYPE, 3, 3> quatToMatrix(const vec<TYPE, 4>& q) { + mat<TYPE, 3, 3> R; + TYPE q0(q.w); + TYPE q1(q.x); + TYPE q2(q.y); + TYPE q3(q.z); + TYPE sq_q1 = 2 * q1 * q1; + TYPE sq_q2 = 2 * q2 * q2; + TYPE sq_q3 = 2 * q3 * q3; + TYPE q1_q2 = 2 * q1 * q2; + TYPE q3_q0 = 2 * q3 * q0; + TYPE q1_q3 = 2 * q1 * q3; + TYPE q2_q0 = 2 * q2 * q0; + TYPE q2_q3 = 2 * q2 * q3; + TYPE q1_q0 = 2 * q1 * q0; + R[0][0] = 1 - sq_q2 - sq_q3; + R[0][1] = q1_q2 - q3_q0; + R[0][2] = q1_q3 + q2_q0; + R[1][0] = q1_q2 + q3_q0; + R[1][1] = 1 - sq_q1 - sq_q3; + R[1][2] = q2_q3 - q1_q0; + R[2][0] = q1_q3 - q2_q0; + R[2][1] = q2_q3 + q1_q0; + R[2][2] = 1 - sq_q1 - sq_q2; + return R; +} + +template <typename TYPE> +vec<TYPE, 4> matrixToQuat(const mat<TYPE, 3, 3>& R) { + // matrix to quaternion + + struct { + inline TYPE operator()(TYPE v) { + return v < 0 ? 0 : v; + } + } clamp; + + vec<TYPE, 4> q; + const float Hx = R[0].x; + const float My = R[1].y; + const float Az = R[2].z; + q.x = sqrtf( clamp( Hx - My - Az + 1) * 0.25f ); + q.y = sqrtf( clamp(-Hx + My - Az + 1) * 0.25f ); + q.z = sqrtf( clamp(-Hx - My + Az + 1) * 0.25f ); + q.w = sqrtf( clamp( Hx + My + Az + 1) * 0.25f ); + q.x = copysignf(q.x, R[2].y - R[1].z); + q.y = copysignf(q.y, R[0].z - R[2].x); + q.z = copysignf(q.z, R[1].x - R[0].y); + // guaranteed to be unit-quaternion + return q; +} + +template <typename TYPE> +vec<TYPE, 4> normalize_quat(const vec<TYPE, 4>& q) { + vec<TYPE, 4> r(q); + if (r.w < 0) { + r = -r; + } + return normalize(r); +} + +// ----------------------------------------------------------------------- + +typedef vec4_t quat_t; + +// ----------------------------------------------------------------------- +}; // namespace android + +#endif /* ANDROID_QUAT_H */ diff --git a/services/sensorservice/tests/Android.mk b/services/sensorservice/tests/Android.mk new file mode 100644 index 0000000..45296dd --- /dev/null +++ b/services/sensorservice/tests/Android.mk @@ -0,0 +1,14 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES:= \ + sensorservicetest.cpp + +LOCAL_SHARED_LIBRARIES := \ + libcutils libutils libui libgui + +LOCAL_MODULE:= test-sensorservice + +LOCAL_MODULE_TAGS := optional + +include $(BUILD_EXECUTABLE) diff --git a/services/sensorservice/tests/sensorservicetest.cpp b/services/sensorservice/tests/sensorservicetest.cpp new file mode 100644 index 0000000..1025fa8 --- /dev/null +++ b/services/sensorservice/tests/sensorservicetest.cpp @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <android/sensor.h> +#include <gui/Sensor.h> +#include <gui/SensorManager.h> +#include <gui/SensorEventQueue.h> +#include <utils/Looper.h> + +using namespace android; + +static nsecs_t sStartTime = 0; + + +int receiver(int fd, int events, void* data) +{ + sp<SensorEventQueue> q((SensorEventQueue*)data); + ssize_t n; + ASensorEvent buffer[8]; + + static nsecs_t oldTimeStamp = 0; + + while ((n = q->read(buffer, 8)) > 0) { + for (int i=0 ; i<n ; i++) { + float t; + if (oldTimeStamp) { + t = float(buffer[i].timestamp - oldTimeStamp) / s2ns(1); + } else { + t = float(buffer[i].timestamp - sStartTime) / s2ns(1); + } + oldTimeStamp = buffer[i].timestamp; + + if (buffer[i].type == Sensor::TYPE_ACCELEROMETER) { + printf("%lld\t%8f\t%8f\t%8f\t%f\n", + buffer[i].timestamp, + buffer[i].data[0], buffer[i].data[1], buffer[i].data[2], + 1.0/t); + } + + } + } + if (n<0 && n != -EAGAIN) { + printf("error reading events (%s)\n", strerror(-n)); + } + return 1; +} + + +int main(int argc, char** argv) +{ + SensorManager& mgr(SensorManager::getInstance()); + + Sensor const* const* list; + ssize_t count = mgr.getSensorList(&list); + printf("numSensors=%d\n", int(count)); + + sp<SensorEventQueue> q = mgr.createEventQueue(); + printf("queue=%p\n", q.get()); + + Sensor const* accelerometer = mgr.getDefaultSensor(Sensor::TYPE_ACCELEROMETER); + printf("accelerometer=%p (%s)\n", + accelerometer, accelerometer->getName().string()); + + sStartTime = systemTime(); + + q->enableSensor(accelerometer); + + q->setEventRate(accelerometer, ms2ns(10)); + + sp<Looper> loop = new Looper(false); + loop->addFd(q->getFd(), 0, ALOOPER_EVENT_INPUT, receiver, q.get()); + + do { + //printf("about to poll...\n"); + int32_t ret = loop->pollOnce(-1); + switch (ret) { + case ALOOPER_POLL_WAKE: + //("ALOOPER_POLL_WAKE\n"); + break; + case ALOOPER_POLL_CALLBACK: + //("ALOOPER_POLL_CALLBACK\n"); + break; + case ALOOPER_POLL_TIMEOUT: + printf("ALOOPER_POLL_TIMEOUT\n"); + break; + case ALOOPER_POLL_ERROR: + printf("ALOOPER_POLL_TIMEOUT\n"); + break; + default: + printf("ugh? poll returned %d\n", ret); + break; + } + } while (1); + + + return 0; +} diff --git a/services/sensorservice/traits.h b/services/sensorservice/traits.h new file mode 100644 index 0000000..da4c599 --- /dev/null +++ b/services/sensorservice/traits.h @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_TRAITS_H +#define ANDROID_TRAITS_H + +// ----------------------------------------------------------------------- +// Typelists + +namespace android { + +// end-of-list marker +class NullType {}; + +// type-list node +template <typename T, typename U> +struct TypeList { + typedef T Head; + typedef U Tail; +}; + +// helpers to build typelists +#define TYPELIST_1(T1) TypeList<T1, NullType> +#define TYPELIST_2(T1, T2) TypeList<T1, TYPELIST_1(T2)> +#define TYPELIST_3(T1, T2, T3) TypeList<T1, TYPELIST_2(T2, T3)> +#define TYPELIST_4(T1, T2, T3, T4) TypeList<T1, TYPELIST_3(T2, T3, T4)> + +// typelists algorithms +namespace TL { +template <typename TList, typename T> struct IndexOf; + +template <typename T> +struct IndexOf<NullType, T> { + enum { value = -1 }; +}; + +template <typename T, typename Tail> +struct IndexOf<TypeList<T, Tail>, T> { + enum { value = 0 }; +}; + +template <typename Head, typename Tail, typename T> +struct IndexOf<TypeList<Head, Tail>, T> { +private: + enum { temp = IndexOf<Tail, T>::value }; +public: + enum { value = temp == -1 ? -1 : 1 + temp }; +}; + +}; // namespace TL + +// type selection based on a boolean +template <bool flag, typename T, typename U> +struct Select { + typedef T Result; +}; +template <typename T, typename U> +struct Select<false, T, U> { + typedef U Result; +}; + +// ----------------------------------------------------------------------- +// Type traits + +template <typename T> +class TypeTraits { + typedef TYPELIST_4( + unsigned char, unsigned short, + unsigned int, unsigned long int) UnsignedInts; + + typedef TYPELIST_4( + signed char, signed short, + signed int, signed long int) SignedInts; + + typedef TYPELIST_1( + bool) OtherInts; + + typedef TYPELIST_3( + float, double, long double) Floats; + + template<typename U> struct PointerTraits { + enum { result = false }; + typedef NullType PointeeType; + }; + template<typename U> struct PointerTraits<U*> { + enum { result = true }; + typedef U PointeeType; + }; + +public: + enum { isStdUnsignedInt = TL::IndexOf<UnsignedInts, T>::value >= 0 }; + enum { isStdSignedInt = TL::IndexOf<SignedInts, T>::value >= 0 }; + enum { isStdIntegral = TL::IndexOf<OtherInts, T>::value >= 0 || isStdUnsignedInt || isStdSignedInt }; + enum { isStdFloat = TL::IndexOf<Floats, T>::value >= 0 }; + enum { isPointer = PointerTraits<T>::result }; + enum { isStdArith = isStdIntegral || isStdFloat }; + + // best parameter type for given type + typedef typename Select<isStdArith || isPointer, T, const T&>::Result ParameterType; +}; + +// ----------------------------------------------------------------------- +}; // namespace android + +#endif /* ANDROID_TRAITS_H */ diff --git a/services/sensorservice/vec.h b/services/sensorservice/vec.h new file mode 100644 index 0000000..24f30ff --- /dev/null +++ b/services/sensorservice/vec.h @@ -0,0 +1,438 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_VEC_H +#define ANDROID_VEC_H + +#include <math.h> + +#include <stdint.h> +#include <stddef.h> + +#include "traits.h" + +// ----------------------------------------------------------------------- + +#define PURE __attribute__((pure)) + +namespace android { + +// ----------------------------------------------------------------------- +// non-inline helpers + +template <typename TYPE, size_t SIZE> +class vec; + +template <typename TYPE, size_t SIZE> +class vbase; + +namespace helpers { + +template <typename T> inline T min(T a, T b) { return a<b ? a : b; } +template <typename T> inline T max(T a, T b) { return a>b ? a : b; } + +template < template<typename T, size_t S> class VEC, + typename TYPE, size_t SIZE, size_t S> +vec<TYPE, SIZE>& doAssign( + vec<TYPE, SIZE>& lhs, const VEC<TYPE, S>& rhs) { + const size_t minSize = min(SIZE, S); + const size_t maxSize = max(SIZE, S); + for (size_t i=0 ; i<minSize ; i++) + lhs[i] = rhs[i]; + for (size_t i=minSize ; i<maxSize ; i++) + lhs[i] = 0; + return lhs; +} + + +template < + template<typename T, size_t S> class VLHS, + template<typename T, size_t S> class VRHS, + typename TYPE, + size_t SIZE +> +VLHS<TYPE, SIZE> PURE doAdd( + const VLHS<TYPE, SIZE>& lhs, + const VRHS<TYPE, SIZE>& rhs) { + VLHS<TYPE, SIZE> r; + for (size_t i=0 ; i<SIZE ; i++) + r[i] = lhs[i] + rhs[i]; + return r; +} + +template < + template<typename T, size_t S> class VLHS, + template<typename T, size_t S> class VRHS, + typename TYPE, + size_t SIZE +> +VLHS<TYPE, SIZE> PURE doSub( + const VLHS<TYPE, SIZE>& lhs, + const VRHS<TYPE, SIZE>& rhs) { + VLHS<TYPE, SIZE> r; + for (size_t i=0 ; i<SIZE ; i++) + r[i] = lhs[i] - rhs[i]; + return r; +} + +template < + template<typename T, size_t S> class VEC, + typename TYPE, + size_t SIZE +> +VEC<TYPE, SIZE> PURE doMulScalar( + const VEC<TYPE, SIZE>& lhs, + typename TypeTraits<TYPE>::ParameterType rhs) { + VEC<TYPE, SIZE> r; + for (size_t i=0 ; i<SIZE ; i++) + r[i] = lhs[i] * rhs; + return r; +} + +template < + template<typename T, size_t S> class VEC, + typename TYPE, + size_t SIZE +> +VEC<TYPE, SIZE> PURE doScalarMul( + typename TypeTraits<TYPE>::ParameterType lhs, + const VEC<TYPE, SIZE>& rhs) { + VEC<TYPE, SIZE> r; + for (size_t i=0 ; i<SIZE ; i++) + r[i] = lhs * rhs[i]; + return r; +} + +}; // namespace helpers + +// ----------------------------------------------------------------------- +// Below we define the mathematical operators for vectors. +// We use template template arguments so we can generically +// handle the case where the right-hand-size and left-hand-side are +// different vector types (but with same value_type and size). +// This is needed for performance when using ".xy{z}" element access +// on vec<>. Without this, an extra conversion to vec<> would be needed. +// +// example: +// vec4_t a; +// vec3_t b; +// vec3_t c = a.xyz + b; +// +// "a.xyz + b" is a mixed-operation between a vbase<> and a vec<>, requiring +// a conversion of vbase<> to vec<>. The template gunk below avoids this, +// by allowing the addition on these different vector types directly +// + +template < + template<typename T, size_t S> class VLHS, + template<typename T, size_t S> class VRHS, + typename TYPE, + size_t SIZE +> +inline VLHS<TYPE, SIZE> PURE operator + ( + const VLHS<TYPE, SIZE>& lhs, + const VRHS<TYPE, SIZE>& rhs) { + return helpers::doAdd(lhs, rhs); +} + +template < + template<typename T, size_t S> class VLHS, + template<typename T, size_t S> class VRHS, + typename TYPE, + size_t SIZE +> +inline VLHS<TYPE, SIZE> PURE operator - ( + const VLHS<TYPE, SIZE>& lhs, + const VRHS<TYPE, SIZE>& rhs) { + return helpers::doSub(lhs, rhs); +} + +template < + template<typename T, size_t S> class VEC, + typename TYPE, + size_t SIZE +> +inline VEC<TYPE, SIZE> PURE operator * ( + const VEC<TYPE, SIZE>& lhs, + typename TypeTraits<TYPE>::ParameterType rhs) { + return helpers::doMulScalar(lhs, rhs); +} + +template < + template<typename T, size_t S> class VEC, + typename TYPE, + size_t SIZE +> +inline VEC<TYPE, SIZE> PURE operator * ( + typename TypeTraits<TYPE>::ParameterType lhs, + const VEC<TYPE, SIZE>& rhs) { + return helpers::doScalarMul(lhs, rhs); +} + + +template < + template<typename T, size_t S> class VLHS, + template<typename T, size_t S> class VRHS, + typename TYPE, + size_t SIZE +> +TYPE PURE dot_product( + const VLHS<TYPE, SIZE>& lhs, + const VRHS<TYPE, SIZE>& rhs) { + TYPE r(0); + for (size_t i=0 ; i<SIZE ; i++) + r += lhs[i] * rhs[i]; + return r; +} + +template < + template<typename T, size_t S> class V, + typename TYPE, + size_t SIZE +> +TYPE PURE length(const V<TYPE, SIZE>& v) { + return sqrt(dot_product(v, v)); +} + +template < + template<typename T, size_t S> class V, + typename TYPE, + size_t SIZE +> +TYPE PURE length_squared(const V<TYPE, SIZE>& v) { + return dot_product(v, v); +} + +template < + template<typename T, size_t S> class V, + typename TYPE, + size_t SIZE +> +V<TYPE, SIZE> PURE normalize(const V<TYPE, SIZE>& v) { + return v * (1/length(v)); +} + +template < + template<typename T, size_t S> class VLHS, + template<typename T, size_t S> class VRHS, + typename TYPE +> +VLHS<TYPE, 3> PURE cross_product( + const VLHS<TYPE, 3>& u, + const VRHS<TYPE, 3>& v) { + VLHS<TYPE, 3> r; + r.x = u.y*v.z - u.z*v.y; + r.y = u.z*v.x - u.x*v.z; + r.z = u.x*v.y - u.y*v.x; + return r; +} + + +template <typename TYPE, size_t SIZE> +vec<TYPE, SIZE> PURE operator - (const vec<TYPE, SIZE>& lhs) { + vec<TYPE, SIZE> r; + for (size_t i=0 ; i<SIZE ; i++) + r[i] = -lhs[i]; + return r; +} + +// ----------------------------------------------------------------------- + +// This our basic vector type, it just implements the data storage +// and accessors. + +template <typename TYPE, size_t SIZE> +struct vbase { + TYPE v[SIZE]; + inline const TYPE& operator[](size_t i) const { return v[i]; } + inline TYPE& operator[](size_t i) { return v[i]; } +}; +template<> struct vbase<float, 2> { + union { + float v[2]; + struct { float x, y; }; + struct { float s, t; }; + }; + inline const float& operator[](size_t i) const { return v[i]; } + inline float& operator[](size_t i) { return v[i]; } +}; +template<> struct vbase<float, 3> { + union { + float v[3]; + struct { float x, y, z; }; + struct { float s, t, r; }; + vbase<float, 2> xy; + vbase<float, 2> st; + }; + inline const float& operator[](size_t i) const { return v[i]; } + inline float& operator[](size_t i) { return v[i]; } +}; +template<> struct vbase<float, 4> { + union { + float v[4]; + struct { float x, y, z, w; }; + struct { float s, t, r, q; }; + vbase<float, 3> xyz; + vbase<float, 3> str; + vbase<float, 2> xy; + vbase<float, 2> st; + }; + inline const float& operator[](size_t i) const { return v[i]; } + inline float& operator[](size_t i) { return v[i]; } +}; + +// ----------------------------------------------------------------------- + +template <typename TYPE, size_t SIZE> +class vec : public vbase<TYPE, SIZE> +{ + typedef typename TypeTraits<TYPE>::ParameterType pTYPE; + typedef vbase<TYPE, SIZE> base; + +public: + // STL-like interface. + typedef TYPE value_type; + typedef TYPE& reference; + typedef TYPE const& const_reference; + typedef size_t size_type; + + typedef TYPE* iterator; + typedef TYPE const* const_iterator; + iterator begin() { return base::v; } + iterator end() { return base::v + SIZE; } + const_iterator begin() const { return base::v; } + const_iterator end() const { return base::v + SIZE; } + size_type size() const { return SIZE; } + + // ----------------------------------------------------------------------- + // default constructors + + vec() { } + vec(const vec& rhs) : base(rhs) { } + vec(const base& rhs) : base(rhs) { } + + // ----------------------------------------------------------------------- + // conversion constructors + + vec(pTYPE rhs) { + for (size_t i=0 ; i<SIZE ; i++) + base::operator[](i) = rhs; + } + + template < template<typename T, size_t S> class VEC, size_t S> + explicit vec(const VEC<TYPE, S>& rhs) { + helpers::doAssign(*this, rhs); + } + + explicit vec(TYPE const* array) { + for (size_t i=0 ; i<SIZE ; i++) + base::operator[](i) = array[i]; + } + + // ----------------------------------------------------------------------- + // Assignment + + vec& operator = (const vec& rhs) { + base::operator=(rhs); + return *this; + } + + vec& operator = (const base& rhs) { + base::operator=(rhs); + return *this; + } + + vec& operator = (pTYPE rhs) { + for (size_t i=0 ; i<SIZE ; i++) + base::operator[](i) = rhs; + return *this; + } + + template < template<typename T, size_t S> class VEC, size_t S> + vec& operator = (const VEC<TYPE, S>& rhs) { + return helpers::doAssign(*this, rhs); + } + + // ----------------------------------------------------------------------- + // operation-assignment + + vec& operator += (const vec& rhs); + vec& operator -= (const vec& rhs); + vec& operator *= (pTYPE rhs); + + // ----------------------------------------------------------------------- + // non-member function declaration and definition + // NOTE: we declare the non-member function as friend inside the class + // so that they are known to the compiler when the class is instantiated. + // This helps the compiler doing template argument deduction when the + // passed types are not identical. Essentially this helps with + // type conversion so that you can multiply a vec<float> by an scalar int + // (for instance). + + friend inline vec PURE operator + (const vec& lhs, const vec& rhs) { + return helpers::doAdd(lhs, rhs); + } + friend inline vec PURE operator - (const vec& lhs, const vec& rhs) { + return helpers::doSub(lhs, rhs); + } + friend inline vec PURE operator * (const vec& lhs, pTYPE v) { + return helpers::doMulScalar(lhs, v); + } + friend inline vec PURE operator * (pTYPE v, const vec& rhs) { + return helpers::doScalarMul(v, rhs); + } + friend inline TYPE PURE dot_product(const vec& lhs, const vec& rhs) { + return android::dot_product(lhs, rhs); + } +}; + +// ----------------------------------------------------------------------- + +template <typename TYPE, size_t SIZE> +vec<TYPE, SIZE>& vec<TYPE, SIZE>::operator += (const vec<TYPE, SIZE>& rhs) { + vec<TYPE, SIZE>& lhs(*this); + for (size_t i=0 ; i<SIZE ; i++) + lhs[i] += rhs[i]; + return lhs; +} + +template <typename TYPE, size_t SIZE> +vec<TYPE, SIZE>& vec<TYPE, SIZE>::operator -= (const vec<TYPE, SIZE>& rhs) { + vec<TYPE, SIZE>& lhs(*this); + for (size_t i=0 ; i<SIZE ; i++) + lhs[i] -= rhs[i]; + return lhs; +} + +template <typename TYPE, size_t SIZE> +vec<TYPE, SIZE>& vec<TYPE, SIZE>::operator *= (vec<TYPE, SIZE>::pTYPE rhs) { + vec<TYPE, SIZE>& lhs(*this); + for (size_t i=0 ; i<SIZE ; i++) + lhs[i] *= rhs; + return lhs; +} + +// ----------------------------------------------------------------------- + +typedef vec<float, 2> vec2_t; +typedef vec<float, 3> vec3_t; +typedef vec<float, 4> vec4_t; + +// ----------------------------------------------------------------------- + +}; // namespace android + +#endif /* ANDROID_VEC_H */ diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk index 6f7a7e1..5a57697 100644 --- a/services/surfaceflinger/Android.mk +++ b/services/surfaceflinger/Android.mk @@ -2,13 +2,15 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ + Client.cpp \ + DisplayDevice.cpp \ EventThread.cpp \ Layer.cpp \ LayerBase.cpp \ LayerDim.cpp \ LayerScreenshot.cpp \ - DisplayHardware/DisplayHardware.cpp \ - DisplayHardware/DisplayHardwareBase.cpp \ + DisplayHardware/FramebufferSurface.cpp \ + DisplayHardware/GraphicBufferAlloc.cpp \ DisplayHardware/HWComposer.cpp \ DisplayHardware/PowerHAL.cpp \ GLExtensions.cpp \ @@ -21,23 +23,28 @@ LOCAL_SRC_FILES:= \ LOCAL_CFLAGS:= -DLOG_TAG=\"SurfaceFlinger\" LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES -ifeq ($(TARGET_BOARD_PLATFORM), omap3) +ifeq ($(TARGET_BOARD_PLATFORM),omap3) LOCAL_CFLAGS += -DNO_RGBX_8888 endif -ifeq ($(TARGET_BOARD_PLATFORM), omap4) +ifeq ($(TARGET_BOARD_PLATFORM),omap4) LOCAL_CFLAGS += -DHAS_CONTEXT_PRIORITY endif -ifeq ($(TARGET_BOARD_PLATFORM), s5pc110) +ifeq ($(TARGET_BOARD_PLATFORM),s5pc110) LOCAL_CFLAGS += -DHAS_CONTEXT_PRIORITY LOCAL_CFLAGS += -DNEVER_DEFAULT_TO_ASYNC_MODE endif -ifeq ($(TARGET_DISABLE_TRIPLE_BUFFERING), true) +ifeq ($(TARGET_DISABLE_TRIPLE_BUFFERING),true) LOCAL_CFLAGS += -DTARGET_DISABLE_TRIPLE_BUFFERING endif +ifneq ($(NUM_FRAMEBUFFER_SURFACE_BUFFERS),) + LOCAL_CFLAGS += -DNUM_FRAMEBUFFER_SURFACE_BUFFERS=$(NUM_FRAMEBUFFER_SURFACE_BUFFERS) +endif + LOCAL_SHARED_LIBRARIES := \ libcutils \ + libdl \ libhardware \ libutils \ libEGL \ @@ -46,13 +53,24 @@ LOCAL_SHARED_LIBRARIES := \ libui \ libgui -# this is only needed for DDMS debugging -ifneq ($(TARGET_BUILD_PDK), true) - LOCAL_SHARED_LIBRARIES += libdvm libandroid_runtime - LOCAL_CLFAGS += -DDDMS_DEBUGGING - LOCAL_SRC_FILES += DdmConnection.cpp -endif - LOCAL_MODULE:= libsurfaceflinger include $(BUILD_SHARED_LIBRARY) + +############################################################### +# uses jni which may not be available in PDK +ifneq ($(wildcard libnativehelper/include),) +include $(CLEAR_VARS) +LOCAL_CFLAGS:= -DLOG_TAG=\"SurfaceFlinger\" + +LOCAL_SRC_FILES:= \ + DdmConnection.cpp + +LOCAL_SHARED_LIBRARIES := \ + libcutils \ + libdl + +LOCAL_MODULE:= libsurfaceflinger_ddmconnection + +include $(BUILD_SHARED_LIBRARY) +endif # libnativehelper diff --git a/services/surfaceflinger/Client.cpp b/services/surfaceflinger/Client.cpp new file mode 100644 index 0000000..c28254f --- /dev/null +++ b/services/surfaceflinger/Client.cpp @@ -0,0 +1,159 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <stdint.h> +#include <sys/types.h> + +#include <binder/PermissionCache.h> + +#include <private/android_filesystem_config.h> + +#include "Client.h" +#include "Layer.h" +#include "LayerBase.h" +#include "SurfaceFlinger.h" + +namespace android { + +// --------------------------------------------------------------------------- + +const String16 sAccessSurfaceFlinger("android.permission.ACCESS_SURFACE_FLINGER"); + +// --------------------------------------------------------------------------- + +Client::Client(const sp<SurfaceFlinger>& flinger) + : mFlinger(flinger), mNameGenerator(1) +{ +} + +Client::~Client() +{ + const size_t count = mLayers.size(); + for (size_t i=0 ; i<count ; i++) { + sp<LayerBaseClient> layer(mLayers.valueAt(i).promote()); + if (layer != 0) { + mFlinger->removeLayer(layer); + } + } +} + +status_t Client::initCheck() const { + return NO_ERROR; +} + +size_t Client::attachLayer(const sp<LayerBaseClient>& layer) +{ + Mutex::Autolock _l(mLock); + size_t name = mNameGenerator++; + mLayers.add(name, layer); + return name; +} + +void Client::detachLayer(const LayerBaseClient* layer) +{ + Mutex::Autolock _l(mLock); + // we do a linear search here, because this doesn't happen often + const size_t count = mLayers.size(); + for (size_t i=0 ; i<count ; i++) { + if (mLayers.valueAt(i) == layer) { + mLayers.removeItemsAt(i, 1); + break; + } + } +} +sp<LayerBaseClient> Client::getLayerUser(int32_t i) const +{ + Mutex::Autolock _l(mLock); + sp<LayerBaseClient> lbc; + wp<LayerBaseClient> layer(mLayers.valueFor(i)); + if (layer != 0) { + lbc = layer.promote(); + ALOGE_IF(lbc==0, "getLayerUser(name=%d) is dead", int(i)); + } + return lbc; +} + + +status_t Client::onTransact( + uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) +{ + // these must be checked + IPCThreadState* ipc = IPCThreadState::self(); + const int pid = ipc->getCallingPid(); + const int uid = ipc->getCallingUid(); + const int self_pid = getpid(); + if (CC_UNLIKELY(pid != self_pid && uid != AID_GRAPHICS && uid != 0)) { + // we're called from a different process, do the real check + if (!PermissionCache::checkCallingPermission(sAccessSurfaceFlinger)) + { + ALOGE("Permission Denial: " + "can't openGlobalTransaction pid=%d, uid=%d", pid, uid); + return PERMISSION_DENIED; + } + } + return BnSurfaceComposerClient::onTransact(code, data, reply, flags); +} + + +sp<ISurface> Client::createSurface( + ISurfaceComposerClient::surface_data_t* params, + const String8& name, + uint32_t w, uint32_t h, PixelFormat format, + uint32_t flags) +{ + /* + * createSurface must be called from the GL thread so that it can + * have access to the GL context. + */ + + class MessageCreateLayer : public MessageBase { + sp<ISurface> result; + SurfaceFlinger* flinger; + ISurfaceComposerClient::surface_data_t* params; + Client* client; + const String8& name; + uint32_t w, h; + PixelFormat format; + uint32_t flags; + public: + MessageCreateLayer(SurfaceFlinger* flinger, + ISurfaceComposerClient::surface_data_t* params, + const String8& name, Client* client, + uint32_t w, uint32_t h, PixelFormat format, + uint32_t flags) + : flinger(flinger), params(params), client(client), name(name), + w(w), h(h), format(format), flags(flags) + { + } + sp<ISurface> getResult() const { return result; } + virtual bool handler() { + result = flinger->createLayer(params, name, client, + w, h, format, flags); + return true; + } + }; + + sp<MessageBase> msg = new MessageCreateLayer(mFlinger.get(), + params, name, this, w, h, format, flags); + mFlinger->postMessageSync(msg); + return static_cast<MessageCreateLayer*>( msg.get() )->getResult(); +} +status_t Client::destroySurface(SurfaceID sid) { + return mFlinger->onLayerRemoved(this, sid); +} + +// --------------------------------------------------------------------------- +}; // namespace android diff --git a/services/surfaceflinger/Client.h b/services/surfaceflinger/Client.h new file mode 100644 index 0000000..d6c6931 --- /dev/null +++ b/services/surfaceflinger/Client.h @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_SF_CLIENT_H +#define ANDROID_SF_CLIENT_H + +#include <stdint.h> +#include <sys/types.h> + +#include <utils/Errors.h> +#include <utils/KeyedVector.h> +#include <utils/Mutex.h> + +#include <gui/ISurfaceComposerClient.h> + +namespace android { + +// --------------------------------------------------------------------------- + +class LayerBaseClient; +class SurfaceFlinger; + +// --------------------------------------------------------------------------- + +class Client : public BnSurfaceComposerClient +{ +public: + Client(const sp<SurfaceFlinger>& flinger); + ~Client(); + + status_t initCheck() const; + + // protected by SurfaceFlinger::mStateLock + size_t attachLayer(const sp<LayerBaseClient>& layer); + + void detachLayer(const LayerBaseClient* layer); + + sp<LayerBaseClient> getLayerUser(int32_t i) const; + +private: + // ISurfaceComposerClient interface + virtual sp<ISurface> createSurface( + surface_data_t* params, const String8& name, + uint32_t w, uint32_t h,PixelFormat format, + uint32_t flags); + + virtual status_t destroySurface(SurfaceID surfaceId); + + virtual status_t onTransact( + uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags); + + // constant + sp<SurfaceFlinger> mFlinger; + + // protected by mLock + DefaultKeyedVector< size_t, wp<LayerBaseClient> > mLayers; + size_t mNameGenerator; + + // thread-safe + mutable Mutex mLock; +}; + +// --------------------------------------------------------------------------- +}; // namespace android + +#endif // ANDROID_SF_CLIENT_H diff --git a/services/surfaceflinger/DdmConnection.cpp b/services/surfaceflinger/DdmConnection.cpp index 467a915..d2c977d 100644 --- a/services/surfaceflinger/DdmConnection.cpp +++ b/services/surfaceflinger/DdmConnection.cpp @@ -14,16 +14,20 @@ * limitations under the License. */ -#include <android_runtime/AndroidRuntime.h> +#include <dlfcn.h> + +#include <cutils/log.h> #include "jni.h" #include "DdmConnection.h" -extern "C" jint Java_com_android_internal_util_WithFramework_registerNatives( - JNIEnv* env, jclass clazz); - namespace android { +void DdmConnection_start(const char* name) { + ALOGI("DdmConnection_start"); + DdmConnection::start(name); +} + void DdmConnection::start(const char* name) { JavaVM* vm; JNIEnv* env; @@ -40,20 +44,44 @@ void DdmConnection::start(const char* name) { args.nOptions = 1; args.ignoreUnrecognized = JNI_FALSE; + + void* libdvm_dso = dlopen("libdvm.so", RTLD_NOW); + ALOGE_IF(!libdvm_dso, "DdmConnection: %s", dlerror()); + + void* libandroid_runtime_dso = dlopen("libandroid_runtime.so", RTLD_NOW); + ALOGE_IF(!libandroid_runtime_dso, "DdmConnection: %s", dlerror()); + + if (!libdvm_dso || !libandroid_runtime_dso) { + goto error; + } + + jint (*JNI_CreateJavaVM)(JavaVM** p_vm, JNIEnv** p_env, void* vm_args); + JNI_CreateJavaVM = (typeof JNI_CreateJavaVM)dlsym(libdvm_dso, "JNI_CreateJavaVM"); + ALOGE_IF(!JNI_CreateJavaVM, "DdmConnection: %s", dlerror()); + + jint (*registerNatives)(JNIEnv* env, jclass clazz); + registerNatives = (typeof registerNatives)dlsym(libandroid_runtime_dso, + "Java_com_android_internal_util_WithFramework_registerNatives"); + ALOGE_IF(!registerNatives, "DdmConnection: %s", dlerror()); + + if (!JNI_CreateJavaVM || !registerNatives) { + goto error; + } + if (JNI_CreateJavaVM(&vm, &env, &args) == 0) { jclass startClass; jmethodID startMeth; // register native code - if (Java_com_android_internal_util_WithFramework_registerNatives(env, 0) == 0) { + if (registerNatives(env, 0) == 0) { // set our name by calling DdmHandleAppName.setAppName() startClass = env->FindClass("android/ddm/DdmHandleAppName"); if (startClass) { startMeth = env->GetStaticMethodID(startClass, - "setAppName", "(Ljava/lang/String;)V"); + "setAppName", "(Ljava/lang/String;I)V"); if (startMeth) { jstring str = env->NewStringUTF(name); - env->CallStaticVoidMethod(startClass, startMeth, str); + env->CallStaticVoidMethod(startClass, startMeth, str, getuid()); env->DeleteLocalRef(str); } } @@ -70,6 +98,15 @@ void DdmConnection::start(const char* name) { } } } + return; + +error: + if (libandroid_runtime_dso) { + dlclose(libandroid_runtime_dso); + } + if (libdvm_dso) { + dlclose(libdvm_dso); + } } }; // namespace android diff --git a/services/surfaceflinger/DdmConnection.h b/services/surfaceflinger/DdmConnection.h index 91b737c..b6b088b 100644 --- a/services/surfaceflinger/DdmConnection.h +++ b/services/surfaceflinger/DdmConnection.h @@ -19,6 +19,9 @@ namespace android { +// wrapper for dlsym +extern "C" void DdmConnection_start(const char* name); + class DdmConnection { public: static void start(const char* name); diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp new file mode 100644 index 0000000..69b9c34 --- /dev/null +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -0,0 +1,458 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <math.h> + +#include <cutils/properties.h> + +#include <utils/RefBase.h> +#include <utils/Log.h> + +#include <ui/DisplayInfo.h> +#include <ui/PixelFormat.h> + +#include <gui/SurfaceTextureClient.h> + +#include <GLES/gl.h> +#include <EGL/egl.h> +#include <EGL/eglext.h> + +#include <hardware/gralloc.h> + +#include "DisplayHardware/FramebufferSurface.h" +#include "DisplayHardware/HWComposer.h" + +#include "clz.h" +#include "DisplayDevice.h" +#include "GLExtensions.h" +#include "SurfaceFlinger.h" +#include "LayerBase.h" + +// ---------------------------------------------------------------------------- +using namespace android; +// ---------------------------------------------------------------------------- + +static __attribute__((noinline)) +void checkGLErrors() +{ + do { + // there could be more than one error flag + GLenum error = glGetError(); + if (error == GL_NO_ERROR) + break; + ALOGE("GL error 0x%04x", int(error)); + } while(true); +} + +// ---------------------------------------------------------------------------- + +/* + * Initialize the display to the specified values. + * + */ + +DisplayDevice::DisplayDevice( + const sp<SurfaceFlinger>& flinger, + DisplayType type, + bool isSecure, + const wp<IBinder>& displayToken, + const sp<ANativeWindow>& nativeWindow, + const sp<FramebufferSurface>& framebufferSurface, + EGLConfig config) + : mFlinger(flinger), + mType(type), mHwcDisplayId(-1), + mDisplayToken(displayToken), + mNativeWindow(nativeWindow), + mFramebufferSurface(framebufferSurface), + mDisplay(EGL_NO_DISPLAY), + mSurface(EGL_NO_SURFACE), + mContext(EGL_NO_CONTEXT), + mDisplayWidth(), mDisplayHeight(), mFormat(), + mFlags(), + mPageFlipCount(), + mIsSecure(isSecure), + mSecureLayerVisible(false), + mScreenAcquired(false), + mLayerStack(0), + mOrientation() +{ + init(config); +} + +DisplayDevice::~DisplayDevice() { + if (mSurface != EGL_NO_SURFACE) { + eglDestroySurface(mDisplay, mSurface); + mSurface = EGL_NO_SURFACE; + } +} + +bool DisplayDevice::isValid() const { + return mFlinger != NULL; +} + +int DisplayDevice::getWidth() const { + return mDisplayWidth; +} + +int DisplayDevice::getHeight() const { + return mDisplayHeight; +} + +PixelFormat DisplayDevice::getFormat() const { + return mFormat; +} + +EGLSurface DisplayDevice::getEGLSurface() const { + return mSurface; +} + +void DisplayDevice::init(EGLConfig config) +{ + ANativeWindow* const window = mNativeWindow.get(); + + int format; + window->query(window, NATIVE_WINDOW_FORMAT, &format); + + /* + * Create our display's surface + */ + + EGLSurface surface; + EGLint w, h; + EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY); + surface = eglCreateWindowSurface(display, config, window, NULL); + eglQuerySurface(display, surface, EGL_WIDTH, &mDisplayWidth); + eglQuerySurface(display, surface, EGL_HEIGHT, &mDisplayHeight); + + mDisplay = display; + mSurface = surface; + mFormat = format; + mPageFlipCount = 0; + mViewport.makeInvalid(); + mFrame.makeInvalid(); + + // external displays are always considered enabled + mScreenAcquired = (mType >= DisplayDevice::NUM_DISPLAY_TYPES); + + // get an h/w composer ID + mHwcDisplayId = mFlinger->allocateHwcDisplayId(mType); + + // Name the display. The name will be replaced shortly if the display + // was created with createDisplay(). + switch (mType) { + case DISPLAY_PRIMARY: + mDisplayName = "Built-in Screen"; + break; + case DISPLAY_EXTERNAL: + mDisplayName = "HDMI Screen"; + break; + default: + mDisplayName = "Virtual Screen"; // e.g. Overlay #n + break; + } + + // initialize the display orientation transform. + setProjection(DisplayState::eOrientationDefault, mViewport, mFrame); +} + +void DisplayDevice::setDisplayName(const String8& displayName) { + if (!displayName.isEmpty()) { + // never override the name with an empty name + mDisplayName = displayName; + } +} + +uint32_t DisplayDevice::getPageFlipCount() const { + return mPageFlipCount; +} + +status_t DisplayDevice::compositionComplete() const { + if (mFramebufferSurface == NULL) { + return NO_ERROR; + } + return mFramebufferSurface->compositionComplete(); +} + +void DisplayDevice::flip(const Region& dirty) const +{ + checkGLErrors(); + + EGLDisplay dpy = mDisplay; + EGLSurface surface = mSurface; + +#ifdef EGL_ANDROID_swap_rectangle + if (mFlags & SWAP_RECTANGLE) { + const Region newDirty(dirty.intersect(bounds())); + const Rect b(newDirty.getBounds()); + eglSetSwapRectangleANDROID(dpy, surface, + b.left, b.top, b.width(), b.height()); + } +#endif + + mPageFlipCount++; +} + +void DisplayDevice::swapBuffers(HWComposer& hwc) const { + EGLBoolean success = EGL_TRUE; + if (hwc.initCheck() != NO_ERROR) { + // no HWC, we call eglSwapBuffers() + success = eglSwapBuffers(mDisplay, mSurface); + } else { + // We have a valid HWC, but not all displays can use it, in particular + // the virtual displays are on their own. + // TODO: HWC 1.2 will allow virtual displays + if (mType >= DisplayDevice::DISPLAY_VIRTUAL) { + // always call eglSwapBuffers() for virtual displays + success = eglSwapBuffers(mDisplay, mSurface); + } else if (hwc.supportsFramebufferTarget()) { + // as of hwc 1.1 we always call eglSwapBuffers if we have some + // GLES layers + if (hwc.hasGlesComposition(mType)) { + success = eglSwapBuffers(mDisplay, mSurface); + } + } else { + // HWC doesn't have the framebuffer target, we don't call + // eglSwapBuffers(), since this is handled by HWComposer::commit(). + } + } + + if (!success) { + EGLint error = eglGetError(); + if (error == EGL_CONTEXT_LOST || + mType == DisplayDevice::DISPLAY_PRIMARY) { + LOG_ALWAYS_FATAL("eglSwapBuffers(%p, %p) failed with 0x%08x", + mDisplay, mSurface, error); + } + } +} + +void DisplayDevice::onSwapBuffersCompleted(HWComposer& hwc) const { + if (hwc.initCheck() == NO_ERROR) { + if (hwc.supportsFramebufferTarget()) { + int fd = hwc.getAndResetReleaseFenceFd(mType); + mFramebufferSurface->setReleaseFenceFd(fd); + } + } +} + +uint32_t DisplayDevice::getFlags() const +{ + return mFlags; +} + +EGLBoolean DisplayDevice::makeCurrent(EGLDisplay dpy, + const sp<const DisplayDevice>& hw, EGLContext ctx) { + EGLBoolean result = EGL_TRUE; + EGLSurface sur = eglGetCurrentSurface(EGL_DRAW); + if (sur != hw->mSurface) { + result = eglMakeCurrent(dpy, hw->mSurface, hw->mSurface, ctx); + if (result == EGL_TRUE) { + setViewportAndProjection(hw); + } + } + return result; +} + +void DisplayDevice::setViewportAndProjection(const sp<const DisplayDevice>& hw) { + GLsizei w = hw->mDisplayWidth; + GLsizei h = hw->mDisplayHeight; + glViewport(0, 0, w, h); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + // put the origin in the left-bottom corner + glOrthof(0, w, 0, h, 0, 1); // l=0, r=w ; b=0, t=h + glMatrixMode(GL_MODELVIEW); +} + +// ---------------------------------------------------------------------------- + +void DisplayDevice::setVisibleLayersSortedByZ(const Vector< sp<LayerBase> >& layers) { + mVisibleLayersSortedByZ = layers; + mSecureLayerVisible = false; + size_t count = layers.size(); + for (size_t i=0 ; i<count ; i++) { + if (layers[i]->isSecure()) { + mSecureLayerVisible = true; + } + } +} + +const Vector< sp<LayerBase> >& DisplayDevice::getVisibleLayersSortedByZ() const { + return mVisibleLayersSortedByZ; +} + +bool DisplayDevice::getSecureLayerVisible() const { + return mSecureLayerVisible; +} + +Region DisplayDevice::getDirtyRegion(bool repaintEverything) const { + Region dirty; + if (repaintEverything) { + dirty.set(getBounds()); + } else { + const Transform& planeTransform(mGlobalTransform); + dirty = planeTransform.transform(this->dirtyRegion); + dirty.andSelf(getBounds()); + } + return dirty; +} + +// ---------------------------------------------------------------------------- + +bool DisplayDevice::canDraw() const { + return mScreenAcquired; +} + +void DisplayDevice::releaseScreen() const { + mScreenAcquired = false; +} + +void DisplayDevice::acquireScreen() const { + mScreenAcquired = true; +} + +bool DisplayDevice::isScreenAcquired() const { + return mScreenAcquired; +} + +// ---------------------------------------------------------------------------- + +void DisplayDevice::setLayerStack(uint32_t stack) { + mLayerStack = stack; + dirtyRegion.set(bounds()); +} + +// ---------------------------------------------------------------------------- + +status_t DisplayDevice::orientationToTransfrom( + int orientation, int w, int h, Transform* tr) +{ + uint32_t flags = 0; + switch (orientation) { + case DisplayState::eOrientationDefault: + flags = Transform::ROT_0; + break; + case DisplayState::eOrientation90: + flags = Transform::ROT_90; + break; + case DisplayState::eOrientation180: + flags = Transform::ROT_180; + break; + case DisplayState::eOrientation270: + flags = Transform::ROT_270; + break; + default: + return BAD_VALUE; + } + tr->set(flags, w, h); + return NO_ERROR; +} + +void DisplayDevice::setProjection(int orientation, + const Rect& viewport, const Rect& frame) { + mOrientation = orientation; + mViewport = viewport; + mFrame = frame; + updateGeometryTransform(); +} + +void DisplayDevice::updateGeometryTransform() { + int w = mDisplayWidth; + int h = mDisplayHeight; + Transform TL, TP, R, S; + if (DisplayDevice::orientationToTransfrom( + mOrientation, w, h, &R) == NO_ERROR) { + dirtyRegion.set(bounds()); + + Rect viewport(mViewport); + Rect frame(mFrame); + + if (!frame.isValid()) { + // the destination frame can be invalid if it has never been set, + // in that case we assume the whole display frame. + frame = Rect(w, h); + } + + if (viewport.isEmpty()) { + // viewport can be invalid if it has never been set, in that case + // we assume the whole display size. + // it's also invalid to have an empty viewport, so we handle that + // case in the same way. + viewport = Rect(w, h); + if (R.getOrientation() & Transform::ROT_90) { + // viewport is always specified in the logical orientation + // of the display (ie: post-rotation). + swap(viewport.right, viewport.bottom); + } + } + + float src_width = viewport.width(); + float src_height = viewport.height(); + float dst_width = frame.width(); + float dst_height = frame.height(); + if (src_width != dst_width || src_height != dst_height) { + float sx = dst_width / src_width; + float sy = dst_height / src_height; + S.set(sx, 0, 0, sy); + } + + float src_x = viewport.left; + float src_y = viewport.top; + float dst_x = frame.left; + float dst_y = frame.top; + TL.set(-src_x, -src_y); + TP.set(dst_x, dst_y); + + // The viewport and frame are both in the logical orientation. + // Apply the logical translation, scale to physical size, apply the + // physical translation and finally rotate to the physical orientation. + mGlobalTransform = R * TP * S * TL; + + const uint8_t type = mGlobalTransform.getType(); + mNeedsFiltering = (!mGlobalTransform.preserveRects() || + (type >= Transform::SCALE)); + } +} + +void DisplayDevice::dump(String8& result, char* buffer, size_t SIZE) const { + const Transform& tr(mGlobalTransform); + snprintf(buffer, SIZE, + "+ DisplayDevice: %s\n" + " type=%x, layerStack=%u, (%4dx%4d), ANativeWindow=%p, orient=%2d (type=%08x), " + "flips=%u, isSecure=%d, secureVis=%d, acquired=%d, numLayers=%u\n" + " v:[%d,%d,%d,%d], f:[%d,%d,%d,%d], " + "transform:[[%0.3f,%0.3f,%0.3f][%0.3f,%0.3f,%0.3f][%0.3f,%0.3f,%0.3f]]\n", + mDisplayName.string(), mType, + mLayerStack, mDisplayWidth, mDisplayHeight, mNativeWindow.get(), + mOrientation, tr.getType(), getPageFlipCount(), + mIsSecure, mSecureLayerVisible, mScreenAcquired, mVisibleLayersSortedByZ.size(), + mViewport.left, mViewport.top, mViewport.right, mViewport.bottom, + mFrame.left, mFrame.top, mFrame.right, mFrame.bottom, + tr[0][0], tr[1][0], tr[2][0], + tr[0][1], tr[1][1], tr[2][1], + tr[0][2], tr[1][2], tr[2][2]); + + result.append(buffer); + + String8 fbtargetDump; + if (mFramebufferSurface != NULL) { + mFramebufferSurface->dump(fbtargetDump); + result.append(fbtargetDump); + } +} diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h new file mode 100644 index 0000000..d6da422 --- /dev/null +++ b/services/surfaceflinger/DisplayDevice.h @@ -0,0 +1,211 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_DISPLAY_DEVICE_H +#define ANDROID_DISPLAY_DEVICE_H + +#include <stdlib.h> + +#include <ui/PixelFormat.h> +#include <ui/Region.h> + +#include <EGL/egl.h> +#include <EGL/eglext.h> + +#include <utils/Mutex.h> +#include <utils/Timers.h> + +#include <hardware/hwcomposer_defs.h> + +#include "Transform.h" + +struct ANativeWindow; + +namespace android { + +class DisplayInfo; +class FramebufferSurface; +class LayerBase; +class SurfaceFlinger; +class HWComposer; + +class DisplayDevice : public LightRefBase<DisplayDevice> +{ +public: + // region in layer-stack space + mutable Region dirtyRegion; + // region in screen space + mutable Region swapRegion; + // region in screen space + Region undefinedRegion; + + enum DisplayType { + DISPLAY_ID_INVALID = -1, + DISPLAY_PRIMARY = HWC_DISPLAY_PRIMARY, + DISPLAY_EXTERNAL = HWC_DISPLAY_EXTERNAL, + NUM_DISPLAY_TYPES = HWC_NUM_DISPLAY_TYPES, + DISPLAY_VIRTUAL = HWC_NUM_DISPLAY_TYPES + }; + + enum { + PARTIAL_UPDATES = 0x00020000, // video driver feature + SWAP_RECTANGLE = 0x00080000, + }; + + DisplayDevice( + const sp<SurfaceFlinger>& flinger, + DisplayType type, + bool isSecure, + const wp<IBinder>& displayToken, + const sp<ANativeWindow>& nativeWindow, + const sp<FramebufferSurface>& framebufferSurface, + EGLConfig config); + + ~DisplayDevice(); + + // whether this is a valid object. An invalid DisplayDevice is returned + // when an non existing id is requested + bool isValid() const; + + // isSecure indicates whether this display can be trusted to display + // secure surfaces. + bool isSecure() const { return mIsSecure; } + + // Flip the front and back buffers if the back buffer is "dirty". Might + // be instantaneous, might involve copying the frame buffer around. + void flip(const Region& dirty) const; + + int getWidth() const; + int getHeight() const; + PixelFormat getFormat() const; + uint32_t getFlags() const; + + EGLSurface getEGLSurface() const; + + void setVisibleLayersSortedByZ(const Vector< sp<LayerBase> >& layers); + const Vector< sp<LayerBase> >& getVisibleLayersSortedByZ() const; + bool getSecureLayerVisible() const; + Region getDirtyRegion(bool repaintEverything) const; + + void setLayerStack(uint32_t stack); + void setProjection(int orientation, const Rect& viewport, const Rect& frame); + + int getOrientation() const { return mOrientation; } + const Transform& getTransform() const { return mGlobalTransform; } + const Rect& getViewport() const { return mViewport; } + const Rect& getFrame() const { return mFrame; } + bool needsFiltering() const { return mNeedsFiltering; } + + uint32_t getLayerStack() const { return mLayerStack; } + int32_t getDisplayType() const { return mType; } + int32_t getHwcDisplayId() const { return mHwcDisplayId; } + const wp<IBinder>& getDisplayToken() const { return mDisplayToken; } + + void swapBuffers(HWComposer& hwc) const; + status_t compositionComplete() const; + + // called after h/w composer has completed its set() call + void onSwapBuffersCompleted(HWComposer& hwc) const; + + Rect getBounds() const { + return Rect(mDisplayWidth, mDisplayHeight); + } + inline Rect bounds() const { return getBounds(); } + + void setDisplayName(const String8& displayName); + const String8& getDisplayName() const { return mDisplayName; } + + static EGLBoolean makeCurrent(EGLDisplay dpy, + const sp<const DisplayDevice>& hw, EGLContext ctx); + + static void setViewportAndProjection(const sp<const DisplayDevice>& hw); + + /* ------------------------------------------------------------------------ + * blank / unblank management + */ + void releaseScreen() const; + void acquireScreen() const; + bool isScreenAcquired() const; + bool canDraw() const; + + /* ------------------------------------------------------------------------ + * Debugging + */ + uint32_t getPageFlipCount() const; + void dump(String8& result, char* buffer, size_t SIZE) const; + +private: + void init(EGLConfig config); + + /* + * Constants, set during initialization + */ + sp<SurfaceFlinger> mFlinger; + DisplayType mType; + int32_t mHwcDisplayId; + wp<IBinder> mDisplayToken; + + // ANativeWindow this display is rendering into + sp<ANativeWindow> mNativeWindow; + + // set if mNativeWindow is a FramebufferSurface + sp<FramebufferSurface> mFramebufferSurface; + + EGLDisplay mDisplay; + EGLSurface mSurface; + EGLContext mContext; + int mDisplayWidth; + int mDisplayHeight; + PixelFormat mFormat; + uint32_t mFlags; + mutable uint32_t mPageFlipCount; + String8 mDisplayName; + bool mIsSecure; + + /* + * Can only accessed from the main thread, these members + * don't need synchronization. + */ + + // list of visible layers on that display + Vector< sp<LayerBase> > mVisibleLayersSortedByZ; + + // Whether we have a visible secure layer on this display + bool mSecureLayerVisible; + + // Whether the screen is blanked; + mutable int mScreenAcquired; + + + /* + * Transaction state + */ + static status_t orientationToTransfrom(int orientation, + int w, int h, Transform* tr); + + void updateGeometryTransform(); + + uint32_t mLayerStack; + int mOrientation; + Rect mViewport; + Rect mFrame; + Transform mGlobalTransform; + bool mNeedsFiltering; +}; + +}; // namespace android + +#endif // ANDROID_DISPLAY_DEVICE_H diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp b/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp deleted file mode 100644 index bb93215..0000000 --- a/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp +++ /dev/null @@ -1,481 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <math.h> - -#include <cutils/properties.h> - -#include <utils/RefBase.h> -#include <utils/Log.h> - -#include <ui/PixelFormat.h> -#include <ui/FramebufferNativeWindow.h> - -#include <GLES/gl.h> -#include <EGL/egl.h> -#include <EGL/eglext.h> - -#include "DisplayHardware/DisplayHardware.h" - -#include <hardware/gralloc.h> - -#include "DisplayHardwareBase.h" -#include "GLExtensions.h" -#include "HWComposer.h" -#include "SurfaceFlinger.h" - -using namespace android; - - -static __attribute__((noinline)) -void checkGLErrors() -{ - do { - // there could be more than one error flag - GLenum error = glGetError(); - if (error == GL_NO_ERROR) - break; - ALOGE("GL error 0x%04x", int(error)); - } while(true); -} - -static __attribute__((noinline)) -void checkEGLErrors(const char* token) -{ - struct EGLUtils { - static const char *strerror(EGLint err) { - switch (err){ - case EGL_SUCCESS: return "EGL_SUCCESS"; - case EGL_NOT_INITIALIZED: return "EGL_NOT_INITIALIZED"; - case EGL_BAD_ACCESS: return "EGL_BAD_ACCESS"; - case EGL_BAD_ALLOC: return "EGL_BAD_ALLOC"; - case EGL_BAD_ATTRIBUTE: return "EGL_BAD_ATTRIBUTE"; - case EGL_BAD_CONFIG: return "EGL_BAD_CONFIG"; - case EGL_BAD_CONTEXT: return "EGL_BAD_CONTEXT"; - case EGL_BAD_CURRENT_SURFACE: return "EGL_BAD_CURRENT_SURFACE"; - case EGL_BAD_DISPLAY: return "EGL_BAD_DISPLAY"; - case EGL_BAD_MATCH: return "EGL_BAD_MATCH"; - case EGL_BAD_NATIVE_PIXMAP: return "EGL_BAD_NATIVE_PIXMAP"; - case EGL_BAD_NATIVE_WINDOW: return "EGL_BAD_NATIVE_WINDOW"; - case EGL_BAD_PARAMETER: return "EGL_BAD_PARAMETER"; - case EGL_BAD_SURFACE: return "EGL_BAD_SURFACE"; - case EGL_CONTEXT_LOST: return "EGL_CONTEXT_LOST"; - default: return "UNKNOWN"; - } - } - }; - - EGLint error = eglGetError(); - if (error && error != EGL_SUCCESS) { - ALOGE("%s: EGL error 0x%04x (%s)", - token, int(error), EGLUtils::strerror(error)); - } -} - -/* - * Initialize the display to the specified values. - * - */ - -DisplayHardware::DisplayHardware( - const sp<SurfaceFlinger>& flinger, - uint32_t dpy) - : DisplayHardwareBase(flinger, dpy), - mFlinger(flinger), mFlags(0), mHwc(0) -{ - init(dpy); -} - -DisplayHardware::~DisplayHardware() -{ - fini(); -} - -float DisplayHardware::getDpiX() const { return mDpiX; } -float DisplayHardware::getDpiY() const { return mDpiY; } -float DisplayHardware::getDensity() const { return mDensity; } -float DisplayHardware::getRefreshRate() const { return mRefreshRate; } -int DisplayHardware::getWidth() const { return mWidth; } -int DisplayHardware::getHeight() const { return mHeight; } -PixelFormat DisplayHardware::getFormat() const { return mFormat; } -uint32_t DisplayHardware::getMaxTextureSize() const { return mMaxTextureSize; } - -uint32_t DisplayHardware::getMaxViewportDims() const { - return mMaxViewportDims[0] < mMaxViewportDims[1] ? - mMaxViewportDims[0] : mMaxViewportDims[1]; -} - -static status_t selectConfigForPixelFormat( - EGLDisplay dpy, - EGLint const* attrs, - PixelFormat format, - EGLConfig* outConfig) -{ - EGLConfig config = NULL; - EGLint numConfigs = -1, n=0; - eglGetConfigs(dpy, NULL, 0, &numConfigs); - EGLConfig* const configs = new EGLConfig[numConfigs]; - eglChooseConfig(dpy, attrs, configs, numConfigs, &n); - for (int i=0 ; i<n ; i++) { - EGLint nativeVisualId = 0; - eglGetConfigAttrib(dpy, configs[i], EGL_NATIVE_VISUAL_ID, &nativeVisualId); - if (nativeVisualId>0 && format == nativeVisualId) { - *outConfig = configs[i]; - delete [] configs; - return NO_ERROR; - } - } - delete [] configs; - return NAME_NOT_FOUND; -} - - -void DisplayHardware::init(uint32_t dpy) -{ - mNativeWindow = new FramebufferNativeWindow(); - framebuffer_device_t const * fbDev = mNativeWindow->getDevice(); - if (!fbDev) { - ALOGE("Display subsystem failed to initialize. check logs. exiting..."); - exit(0); - } - - int format; - ANativeWindow const * const window = mNativeWindow.get(); - window->query(window, NATIVE_WINDOW_FORMAT, &format); - mDpiX = mNativeWindow->xdpi; - mDpiY = mNativeWindow->ydpi; - mRefreshRate = fbDev->fps; - - if (mDpiX == 0 || mDpiY == 0) { - ALOGE("invalid screen resolution from fb HAL (xdpi=%f, ydpi=%f), " - "defaulting to 160 dpi", mDpiX, mDpiY); - mDpiX = mDpiY = 160; - } - - class Density { - static int getDensityFromProperty(char const* propName) { - char property[PROPERTY_VALUE_MAX]; - int density = 0; - if (property_get(propName, property, NULL) > 0) { - density = atoi(property); - } - return density; - } - public: - static int getEmuDensity() { - return getDensityFromProperty("qemu.sf.lcd_density"); } - static int getBuildDensity() { - return getDensityFromProperty("ro.sf.lcd_density"); } - }; - - - // The density of the device is provided by a build property - mDensity = Density::getBuildDensity() / 160.0f; - - if (mDensity == 0) { - // the build doesn't provide a density -- this is wrong! - // use xdpi instead - ALOGE("ro.sf.lcd_density must be defined as a build property"); - mDensity = mDpiX / 160.0f; - } - - if (Density::getEmuDensity()) { - // if "qemu.sf.lcd_density" is specified, it overrides everything - mDpiX = mDpiY = mDensity = Density::getEmuDensity(); - mDensity /= 160.0f; - } - - - - /* FIXME: this is a temporary HACK until we are able to report the refresh rate - * properly from the HAL. The WindowManagerService now relies on this value. - */ -#ifndef REFRESH_RATE - mRefreshRate = fbDev->fps; -#else - mRefreshRate = REFRESH_RATE; -#warning "refresh rate set via makefile to REFRESH_RATE" -#endif - - mRefreshPeriod = nsecs_t(1e9 / mRefreshRate); - - EGLint w, h, dummy; - EGLint numConfigs=0; - EGLSurface surface; - EGLContext context; - EGLBoolean result; - status_t err; - - // initialize EGL - EGLint attribs[] = { - EGL_SURFACE_TYPE, EGL_WINDOW_BIT, - EGL_NONE, 0, - EGL_NONE - }; - - // debug: disable h/w rendering - char property[PROPERTY_VALUE_MAX]; - if (property_get("debug.sf.hw", property, NULL) > 0) { - if (atoi(property) == 0) { - ALOGW("H/W composition disabled"); - attribs[2] = EGL_CONFIG_CAVEAT; - attribs[3] = EGL_SLOW_CONFIG; - } - } - - // TODO: all the extensions below should be queried through - // eglGetProcAddress(). - - EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY); - eglInitialize(display, NULL, NULL); - eglGetConfigs(display, NULL, 0, &numConfigs); - - EGLConfig config = NULL; - err = selectConfigForPixelFormat(display, attribs, format, &config); - ALOGE_IF(err, "couldn't find an EGLConfig matching the screen format"); - - EGLint r,g,b,a; - eglGetConfigAttrib(display, config, EGL_RED_SIZE, &r); - eglGetConfigAttrib(display, config, EGL_GREEN_SIZE, &g); - eglGetConfigAttrib(display, config, EGL_BLUE_SIZE, &b); - eglGetConfigAttrib(display, config, EGL_ALPHA_SIZE, &a); - - if (mNativeWindow->isUpdateOnDemand()) { - mFlags |= PARTIAL_UPDATES; - } - - if (eglGetConfigAttrib(display, config, EGL_CONFIG_CAVEAT, &dummy) == EGL_TRUE) { - if (dummy == EGL_SLOW_CONFIG) - mFlags |= SLOW_CONFIG; - } - - /* - * Create our main surface - */ - - surface = eglCreateWindowSurface(display, config, mNativeWindow.get(), NULL); - eglQuerySurface(display, surface, EGL_WIDTH, &mWidth); - eglQuerySurface(display, surface, EGL_HEIGHT, &mHeight); - - if (mFlags & PARTIAL_UPDATES) { - // if we have partial updates, we definitely don't need to - // preserve the backbuffer, which may be costly. - eglSurfaceAttrib(display, surface, - EGL_SWAP_BEHAVIOR, EGL_BUFFER_DESTROYED); - } - - /* - * Create our OpenGL ES context - */ - - EGLint contextAttributes[] = { -#ifdef EGL_IMG_context_priority -#ifdef HAS_CONTEXT_PRIORITY -#warning "using EGL_IMG_context_priority" - EGL_CONTEXT_PRIORITY_LEVEL_IMG, EGL_CONTEXT_PRIORITY_HIGH_IMG, -#endif -#endif - EGL_NONE, EGL_NONE - }; - context = eglCreateContext(display, config, NULL, contextAttributes); - - mDisplay = display; - mConfig = config; - mSurface = surface; - mContext = context; - mFormat = fbDev->format; - mPageFlipCount = 0; - - /* - * Gather OpenGL ES extensions - */ - - result = eglMakeCurrent(display, surface, surface, context); - if (!result) { - ALOGE("Couldn't create a working GLES context. check logs. exiting..."); - exit(0); - } - - GLExtensions& extensions(GLExtensions::getInstance()); - extensions.initWithGLStrings( - glGetString(GL_VENDOR), - glGetString(GL_RENDERER), - glGetString(GL_VERSION), - glGetString(GL_EXTENSIONS), - eglQueryString(display, EGL_VENDOR), - eglQueryString(display, EGL_VERSION), - eglQueryString(display, EGL_EXTENSIONS)); - - glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize); - glGetIntegerv(GL_MAX_VIEWPORT_DIMS, mMaxViewportDims); - - ALOGI("EGL informations:"); - ALOGI("# of configs : %d", numConfigs); - ALOGI("vendor : %s", extensions.getEglVendor()); - ALOGI("version : %s", extensions.getEglVersion()); - ALOGI("extensions: %s", extensions.getEglExtension()); - ALOGI("Client API: %s", eglQueryString(display, EGL_CLIENT_APIS)?:"Not Supported"); - ALOGI("EGLSurface: %d-%d-%d-%d, config=%p", r, g, b, a, config); - - ALOGI("OpenGL informations:"); - ALOGI("vendor : %s", extensions.getVendor()); - ALOGI("renderer : %s", extensions.getRenderer()); - ALOGI("version : %s", extensions.getVersion()); - ALOGI("extensions: %s", extensions.getExtension()); - ALOGI("GL_MAX_TEXTURE_SIZE = %d", mMaxTextureSize); - ALOGI("GL_MAX_VIEWPORT_DIMS = %d x %d", mMaxViewportDims[0], mMaxViewportDims[1]); - ALOGI("flags = %08x", mFlags); - - // Unbind the context from this thread - eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); - - - // initialize the H/W composer - mHwc = new HWComposer(mFlinger, *this, mRefreshPeriod); - if (mHwc->initCheck() == NO_ERROR) { - mHwc->setFrameBuffer(mDisplay, mSurface); - } -} - -void DisplayHardware::setVSyncHandler(const sp<VSyncHandler>& handler) { - Mutex::Autolock _l(mLock); - mVSyncHandler = handler; -} - -void DisplayHardware::eventControl(int event, int enabled) { - if (event == EVENT_VSYNC) { - mPowerHAL.vsyncHint(enabled); - } - mHwc->eventControl(event, enabled); -} - -void DisplayHardware::onVSyncReceived(int dpy, nsecs_t timestamp) { - sp<VSyncHandler> handler; - { // scope for the lock - Mutex::Autolock _l(mLock); - mLastHwVSync = timestamp; - if (mVSyncHandler != NULL) { - handler = mVSyncHandler.promote(); - } - } - - if (handler != NULL) { - handler->onVSyncReceived(dpy, timestamp); - } -} - -HWComposer& DisplayHardware::getHwComposer() const { - return *mHwc; -} - -/* - * Clean up. Throw out our local state. - * - * (It's entirely possible we'll never get here, since this is meant - * for real hardware, which doesn't restart.) - */ - -void DisplayHardware::fini() -{ - eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); - eglTerminate(mDisplay); -} - -void DisplayHardware::releaseScreen() const -{ - DisplayHardwareBase::releaseScreen(); - if (mHwc->initCheck() == NO_ERROR) { - mHwc->release(); - } -} - -void DisplayHardware::acquireScreen() const -{ - DisplayHardwareBase::acquireScreen(); -} - -uint32_t DisplayHardware::getPageFlipCount() const { - return mPageFlipCount; -} - -nsecs_t DisplayHardware::getRefreshTimestamp() const { - // this returns the last refresh timestamp. - // if the last one is not available, we estimate it based on - // the refresh period and whatever closest timestamp we have. - Mutex::Autolock _l(mLock); - nsecs_t now = systemTime(CLOCK_MONOTONIC); - return now - ((now - mLastHwVSync) % mRefreshPeriod); -} - -nsecs_t DisplayHardware::getRefreshPeriod() const { - return mRefreshPeriod; -} - -status_t DisplayHardware::compositionComplete() const { - return mNativeWindow->compositionComplete(); -} - -void DisplayHardware::flip(const Region& dirty) const -{ - checkGLErrors(); - - EGLDisplay dpy = mDisplay; - EGLSurface surface = mSurface; - -#ifdef EGL_ANDROID_swap_rectangle - if (mFlags & SWAP_RECTANGLE) { - const Region newDirty(dirty.intersect(bounds())); - const Rect b(newDirty.getBounds()); - eglSetSwapRectangleANDROID(dpy, surface, - b.left, b.top, b.width(), b.height()); - } -#endif - - if (mFlags & PARTIAL_UPDATES) { - mNativeWindow->setUpdateRectangle(dirty.getBounds()); - } - - mPageFlipCount++; - - if (mHwc->initCheck() == NO_ERROR) { - mHwc->commit(); - } else { - eglSwapBuffers(dpy, surface); - } - checkEGLErrors("eglSwapBuffers"); - - // for debugging - //glClearColor(1,0,0,0); - //glClear(GL_COLOR_BUFFER_BIT); -} - -uint32_t DisplayHardware::getFlags() const -{ - return mFlags; -} - -void DisplayHardware::makeCurrent() const -{ - eglMakeCurrent(mDisplay, mSurface, mSurface, mContext); -} - -void DisplayHardware::dump(String8& res) const -{ - mNativeWindow->dump(res); -} diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardware.h b/services/surfaceflinger/DisplayHardware/DisplayHardware.h deleted file mode 100644 index 0604031..0000000 --- a/services/surfaceflinger/DisplayHardware/DisplayHardware.h +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ANDROID_DISPLAY_HARDWARE_H -#define ANDROID_DISPLAY_HARDWARE_H - -#include <stdlib.h> - -#include <ui/PixelFormat.h> -#include <ui/Region.h> - -#include <GLES/gl.h> -#include <GLES/glext.h> -#include <EGL/egl.h> -#include <EGL/eglext.h> - -#include "GLExtensions.h" - -#include "DisplayHardware/DisplayHardwareBase.h" -#include "HWComposer.h" -#include "PowerHAL.h" - -namespace android { - -class FramebufferNativeWindow; - -class DisplayHardware : - public DisplayHardwareBase, - public HWComposer::EventHandler -{ -public: - - class VSyncHandler : virtual public RefBase { - friend class DisplayHardware; - virtual void onVSyncReceived(int dpy, nsecs_t timestamp) = 0; - protected: - virtual ~VSyncHandler() {} - }; - - enum { - COPY_BITS_EXTENSION = 0x00000008, - PARTIAL_UPDATES = 0x00020000, // video driver feature - SLOW_CONFIG = 0x00040000, // software - SWAP_RECTANGLE = 0x00080000, - }; - - DisplayHardware( - const sp<SurfaceFlinger>& flinger, - uint32_t displayIndex); - - virtual ~DisplayHardware(); - - void releaseScreen() const; - void acquireScreen() const; - - // Flip the front and back buffers if the back buffer is "dirty". Might - // be instantaneous, might involve copying the frame buffer around. - void flip(const Region& dirty) const; - - float getDpiX() const; - float getDpiY() const; - float getRefreshRate() const; - float getDensity() const; - int getWidth() const; - int getHeight() const; - PixelFormat getFormat() const; - uint32_t getFlags() const; - uint32_t getMaxTextureSize() const; - uint32_t getMaxViewportDims() const; - nsecs_t getRefreshPeriod() const; - nsecs_t getRefreshTimestamp() const; - void makeCurrent() const; - - - void setVSyncHandler(const sp<VSyncHandler>& handler); - - enum { - EVENT_VSYNC = HWC_EVENT_VSYNC - }; - - void eventControl(int event, int enabled); - - - uint32_t getPageFlipCount() const; - EGLDisplay getEGLDisplay() const { return mDisplay; } - - void dump(String8& res) const; - - // Hardware Composer - HWComposer& getHwComposer() const; - - status_t compositionComplete() const; - - Rect getBounds() const { - return Rect(mWidth, mHeight); - } - inline Rect bounds() const { return getBounds(); } - -private: - virtual void onVSyncReceived(int dpy, nsecs_t timestamp); - void init(uint32_t displayIndex) __attribute__((noinline)); - void fini() __attribute__((noinline)); - - sp<SurfaceFlinger> mFlinger; - EGLDisplay mDisplay; - EGLSurface mSurface; - EGLContext mContext; - EGLConfig mConfig; - float mDpiX; - float mDpiY; - float mRefreshRate; - float mDensity; - int mWidth; - int mHeight; - PixelFormat mFormat; - uint32_t mFlags; - mutable uint32_t mPageFlipCount; - GLint mMaxViewportDims[2]; - GLint mMaxTextureSize; - - nsecs_t mRefreshPeriod; - mutable nsecs_t mLastHwVSync; - - // constant once set - HWComposer* mHwc; - PowerHAL mPowerHAL; - - - mutable Mutex mLock; - - // protected by mLock - wp<VSyncHandler> mVSyncHandler; - - sp<FramebufferNativeWindow> mNativeWindow; -}; - -}; // namespace android - -#endif // ANDROID_DISPLAY_HARDWARE_H diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp b/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp deleted file mode 100644 index d3a8bde..0000000 --- a/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <errno.h> -#include <stdlib.h> -#include <stdio.h> -#include <string.h> - -#include <unistd.h> -#include <fcntl.h> - -#include <utils/Log.h> - -#include "DisplayHardware/DisplayHardwareBase.h" -#include "SurfaceFlinger.h" - -// ---------------------------------------------------------------------------- -namespace android { - -static char const * const kSleepFileName = "/sys/power/wait_for_fb_sleep"; -static char const * const kWakeFileName = "/sys/power/wait_for_fb_wake"; - -// ---------------------------------------------------------------------------- - -DisplayHardwareBase::DisplayEventThread::DisplayEventThread( - const sp<SurfaceFlinger>& flinger) - : Thread(false), mFlinger(flinger) { -} - -DisplayHardwareBase::DisplayEventThread::~DisplayEventThread() { -} - -status_t DisplayHardwareBase::DisplayEventThread::initCheck() const { - return ((access(kSleepFileName, R_OK) == 0 && - access(kWakeFileName, R_OK) == 0)) ? NO_ERROR : NO_INIT; -} - -bool DisplayHardwareBase::DisplayEventThread::threadLoop() { - - if (waitForFbSleep() == NO_ERROR) { - sp<SurfaceFlinger> flinger = mFlinger.promote(); - ALOGD("About to give-up screen, flinger = %p", flinger.get()); - if (flinger != 0) { - flinger->screenReleased(); - } - if (waitForFbWake() == NO_ERROR) { - ALOGD("Screen about to return, flinger = %p", flinger.get()); - if (flinger != 0) { - flinger->screenAcquired(); - } - return true; - } - } - - // error, exit the thread - return false; -} - -status_t DisplayHardwareBase::DisplayEventThread::waitForFbSleep() { - int err = 0; - char buf; - int fd = open(kSleepFileName, O_RDONLY, 0); - // if the file doesn't exist, the error will be caught in read() below - do { - err = read(fd, &buf, 1); - } while (err < 0 && errno == EINTR); - close(fd); - ALOGE_IF(err<0, "*** ANDROID_WAIT_FOR_FB_SLEEP failed (%s)", strerror(errno)); - return err < 0 ? -errno : int(NO_ERROR); -} - -status_t DisplayHardwareBase::DisplayEventThread::waitForFbWake() { - int err = 0; - char buf; - int fd = open(kWakeFileName, O_RDONLY, 0); - // if the file doesn't exist, the error will be caught in read() below - do { - err = read(fd, &buf, 1); - } while (err < 0 && errno == EINTR); - close(fd); - ALOGE_IF(err<0, "*** ANDROID_WAIT_FOR_FB_WAKE failed (%s)", strerror(errno)); - return err < 0 ? -errno : int(NO_ERROR); -} - -// ---------------------------------------------------------------------------- - -DisplayHardwareBase::DisplayHardwareBase(const sp<SurfaceFlinger>& flinger, - uint32_t displayIndex) -{ - mScreenAcquired = true; - mDisplayEventThread = new DisplayEventThread(flinger); -} - -void DisplayHardwareBase::startSleepManagement() const { - if (mDisplayEventThread->initCheck() == NO_ERROR) { - mDisplayEventThread->run("DisplayEventThread", PRIORITY_URGENT_DISPLAY); - } else { - ALOGW("/sys/power/wait_for_fb_{wake|sleep} don't exist"); - } -} - -DisplayHardwareBase::~DisplayHardwareBase() { - // request exit - mDisplayEventThread->requestExitAndWait(); -} - -bool DisplayHardwareBase::canDraw() const { - return mScreenAcquired; -} - -void DisplayHardwareBase::releaseScreen() const { - mScreenAcquired = false; -} - -void DisplayHardwareBase::acquireScreen() const { - mScreenAcquired = true; -} - -bool DisplayHardwareBase::isScreenAcquired() const { - return mScreenAcquired; -} - -}; // namespace android diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.h b/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.h deleted file mode 100644 index 6857481..0000000 --- a/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ANDROID_DISPLAY_HARDWARE_BASE_H -#define ANDROID_DISPLAY_HARDWARE_BASE_H - -#include <stdint.h> -#include <utils/RefBase.h> -#include <utils/StrongPointer.h> -#include <utils/threads.h> - -namespace android { - -class SurfaceFlinger; - -class DisplayHardwareBase -{ -public: - DisplayHardwareBase( - const sp<SurfaceFlinger>& flinger, - uint32_t displayIndex); - - ~DisplayHardwareBase(); - - void startSleepManagement() const; - - // console management - void releaseScreen() const; - void acquireScreen() const; - bool isScreenAcquired() const; - - bool canDraw() const; - - -private: - class DisplayEventThread : public Thread { - wp<SurfaceFlinger> mFlinger; - status_t waitForFbSleep(); - status_t waitForFbWake(); - public: - DisplayEventThread(const sp<SurfaceFlinger>& flinger); - virtual ~DisplayEventThread(); - virtual bool threadLoop(); - status_t initCheck() const; - }; - - sp<DisplayEventThread> mDisplayEventThread; - mutable int mScreenAcquired; -}; - -}; // namespace android - -#endif // ANDROID_DISPLAY_HARDWARE_BASE_H diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp new file mode 100644 index 0000000..6c86a53 --- /dev/null +++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp @@ -0,0 +1,162 @@ +/* + ** + ** Copyright 2012 The Android Open Source Project + ** + ** Licensed under the Apache License Version 2.0(the "License"); + ** you may not use this file except in compliance with the License. + ** You may obtain a copy of the License at + ** + ** http://www.apache.org/licenses/LICENSE-2.0 + ** + ** Unless required by applicable law or agreed to in writing software + ** distributed under the License is distributed on an "AS IS" BASIS + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND either express or implied. + ** See the License for the specific language governing permissions and + ** limitations under the License. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <errno.h> + +#include <cutils/log.h> + +#include <utils/String8.h> + +#include <ui/Rect.h> + +#include <EGL/egl.h> + +#include <hardware/hardware.h> +#include <gui/SurfaceTextureClient.h> +#include <ui/GraphicBuffer.h> + +#include "DisplayHardware/FramebufferSurface.h" +#include "DisplayHardware/GraphicBufferAlloc.h" +#include "DisplayHardware/HWComposer.h" + +#ifndef NUM_FRAMEBUFFER_SURFACE_BUFFERS +#define NUM_FRAMEBUFFER_SURFACE_BUFFERS (2) +#endif + +// ---------------------------------------------------------------------------- +namespace android { +// ---------------------------------------------------------------------------- + +/* + * This implements the (main) framebuffer management. This class is used + * mostly by SurfaceFlinger, but also by command line GL application. + * + */ + +FramebufferSurface::FramebufferSurface(HWComposer& hwc, int disp) : + ConsumerBase(new BufferQueue(true, new GraphicBufferAlloc())), + mDisplayType(disp), + mCurrentBufferSlot(-1), + mCurrentBuffer(0), + mHwc(hwc) +{ + mName = "FramebufferSurface"; + mBufferQueue->setConsumerName(mName); + mBufferQueue->setConsumerUsageBits(GRALLOC_USAGE_HW_FB | + GRALLOC_USAGE_HW_RENDER | + GRALLOC_USAGE_HW_COMPOSER); + mBufferQueue->setDefaultBufferFormat(mHwc.getFormat(disp)); + mBufferQueue->setDefaultBufferSize(mHwc.getWidth(disp), mHwc.getHeight(disp)); + mBufferQueue->setSynchronousMode(true); + mBufferQueue->setDefaultMaxBufferCount(NUM_FRAMEBUFFER_SURFACE_BUFFERS); +} + +status_t FramebufferSurface::nextBuffer(sp<GraphicBuffer>& outBuffer, sp<Fence>& outFence) { + Mutex::Autolock lock(mMutex); + + BufferQueue::BufferItem item; + status_t err = acquireBufferLocked(&item); + if (err == BufferQueue::NO_BUFFER_AVAILABLE) { + outBuffer = mCurrentBuffer; + return NO_ERROR; + } else if (err != NO_ERROR) { + ALOGE("error acquiring buffer: %s (%d)", strerror(-err), err); + return err; + } + + // If the BufferQueue has freed and reallocated a buffer in mCurrentSlot + // then we may have acquired the slot we already own. If we had released + // our current buffer before we call acquireBuffer then that release call + // would have returned STALE_BUFFER_SLOT, and we would have called + // freeBufferLocked on that slot. Because the buffer slot has already + // been overwritten with the new buffer all we have to do is skip the + // releaseBuffer call and we should be in the same state we'd be in if we + // had released the old buffer first. + if (mCurrentBufferSlot != BufferQueue::INVALID_BUFFER_SLOT && + item.mBuf != mCurrentBufferSlot) { + // Release the previous buffer. + err = releaseBufferLocked(mCurrentBufferSlot, EGL_NO_DISPLAY, + EGL_NO_SYNC_KHR); + if (err != NO_ERROR && err != BufferQueue::STALE_BUFFER_SLOT) { + ALOGE("error releasing buffer: %s (%d)", strerror(-err), err); + return err; + } + } + mCurrentBufferSlot = item.mBuf; + mCurrentBuffer = mSlots[mCurrentBufferSlot].mGraphicBuffer; + outFence = item.mFence; + outBuffer = mCurrentBuffer; + return NO_ERROR; +} + +// Overrides ConsumerBase::onFrameAvailable(), does not call base class impl. +void FramebufferSurface::onFrameAvailable() { + sp<GraphicBuffer> buf; + sp<Fence> acquireFence; + status_t err = nextBuffer(buf, acquireFence); + if (err != NO_ERROR) { + ALOGE("error latching nnext FramebufferSurface buffer: %s (%d)", + strerror(-err), err); + return; + } + err = mHwc.fbPost(mDisplayType, acquireFence, buf); + if (err != NO_ERROR) { + ALOGE("error posting framebuffer: %d", err); + } +} + +void FramebufferSurface::freeBufferLocked(int slotIndex) { + ConsumerBase::freeBufferLocked(slotIndex); + if (slotIndex == mCurrentBufferSlot) { + mCurrentBufferSlot = BufferQueue::INVALID_BUFFER_SLOT; + } +} + +status_t FramebufferSurface::setReleaseFenceFd(int fenceFd) { + status_t err = NO_ERROR; + if (fenceFd >= 0) { + sp<Fence> fence(new Fence(fenceFd)); + if (mCurrentBufferSlot != BufferQueue::INVALID_BUFFER_SLOT) { + status_t err = addReleaseFence(mCurrentBufferSlot, fence); + ALOGE_IF(err, "setReleaseFenceFd: failed to add the fence: %s (%d)", + strerror(-err), err); + } + } + return err; +} + +status_t FramebufferSurface::setUpdateRectangle(const Rect& r) +{ + return INVALID_OPERATION; +} + +status_t FramebufferSurface::compositionComplete() +{ + return mHwc.fbCompositionComplete(); +} + +void FramebufferSurface::dump(String8& result) { + mHwc.fbDump(result); + ConsumerBase::dump(result); +} + +// ---------------------------------------------------------------------------- +}; // namespace android +// ---------------------------------------------------------------------------- diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h new file mode 100644 index 0000000..6336345 --- /dev/null +++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_SF_FRAMEBUFFER_SURFACE_H +#define ANDROID_SF_FRAMEBUFFER_SURFACE_H + +#include <stdint.h> +#include <sys/types.h> + +#include <gui/ConsumerBase.h> + +// --------------------------------------------------------------------------- +namespace android { +// --------------------------------------------------------------------------- + +class Rect; +class String8; +class HWComposer; + +// --------------------------------------------------------------------------- + +class FramebufferSurface : public ConsumerBase { +public: + FramebufferSurface(HWComposer& hwc, int disp); + + bool isUpdateOnDemand() const { return false; } + status_t setUpdateRectangle(const Rect& updateRect); + status_t compositionComplete(); + + virtual void dump(String8& result); + + // setReleaseFenceFd stores a fence file descriptor that will signal when the + // current buffer is no longer being read. This fence will be returned to + // the producer when the current buffer is released by updateTexImage(). + // Multiple fences can be set for a given buffer; they will be merged into + // a single union fence. The SurfaceTexture will close the file descriptor + // when finished with it. + status_t setReleaseFenceFd(int fenceFd); + +private: + virtual ~FramebufferSurface() { }; // this class cannot be overloaded + + virtual void onFrameAvailable(); + virtual void freeBufferLocked(int slotIndex); + + // nextBuffer waits for and then latches the next buffer from the + // BufferQueue and releases the previously latched buffer to the + // BufferQueue. The new buffer is returned in the 'buffer' argument. + status_t nextBuffer(sp<GraphicBuffer>& outBuffer, sp<Fence>& outFence); + + // mDisplayType must match one of the HWC display types + int mDisplayType; + + // mCurrentBufferIndex is the slot index of the current buffer or + // INVALID_BUFFER_SLOT to indicate that either there is no current buffer + // or the buffer is not associated with a slot. + int mCurrentBufferSlot; + + // mCurrentBuffer is the current buffer or NULL to indicate that there is + // no current buffer. + sp<GraphicBuffer> mCurrentBuffer; + + // Hardware composer, owned by SurfaceFlinger. + HWComposer& mHwc; +}; + +// --------------------------------------------------------------------------- +}; // namespace android +// --------------------------------------------------------------------------- + +#endif // ANDROID_SF_FRAMEBUFFER_SURFACE_H + diff --git a/services/surfaceflinger/DisplayHardware/GraphicBufferAlloc.cpp b/services/surfaceflinger/DisplayHardware/GraphicBufferAlloc.cpp new file mode 100644 index 0000000..965ff01 --- /dev/null +++ b/services/surfaceflinger/DisplayHardware/GraphicBufferAlloc.cpp @@ -0,0 +1,53 @@ +/* + ** + ** Copyright 2012 The Android Open Source Project + ** + ** Licensed under the Apache License Version 2.0(the "License"); + ** you may not use this file except in compliance with the License. + ** You may obtain a copy of the License at + ** + ** http://www.apache.org/licenses/LICENSE-2.0 + ** + ** Unless required by applicable law or agreed to in writing software + ** distributed under the License is distributed on an "AS IS" BASIS + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND either express or implied. + ** See the License for the specific language governing permissions and + ** limitations under the License. + */ + +#include <cutils/log.h> + +#include <ui/GraphicBuffer.h> + +#include "DisplayHardware/GraphicBufferAlloc.h" + +// ---------------------------------------------------------------------------- +namespace android { +// ---------------------------------------------------------------------------- + +GraphicBufferAlloc::GraphicBufferAlloc() { +} + +GraphicBufferAlloc::~GraphicBufferAlloc() { +} + +sp<GraphicBuffer> GraphicBufferAlloc::createGraphicBuffer(uint32_t w, uint32_t h, + PixelFormat format, uint32_t usage, status_t* error) { + sp<GraphicBuffer> graphicBuffer(new GraphicBuffer(w, h, format, usage)); + status_t err = graphicBuffer->initCheck(); + *error = err; + if (err != 0 || graphicBuffer->handle == 0) { + if (err == NO_MEMORY) { + GraphicBuffer::dumpAllocationsToSystemLog(); + } + ALOGE("GraphicBufferAlloc::createGraphicBuffer(w=%d, h=%d) " + "failed (%s), handle=%p", + w, h, strerror(-err), graphicBuffer->handle); + return 0; + } + return graphicBuffer; +} + +// ---------------------------------------------------------------------------- +}; // namespace android +// ---------------------------------------------------------------------------- diff --git a/services/surfaceflinger/DisplayHardware/GraphicBufferAlloc.h b/services/surfaceflinger/DisplayHardware/GraphicBufferAlloc.h new file mode 100644 index 0000000..b08750c --- /dev/null +++ b/services/surfaceflinger/DisplayHardware/GraphicBufferAlloc.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_SF_GRAPHIC_BUFFER_ALLOC_H +#define ANDROID_SF_GRAPHIC_BUFFER_ALLOC_H + +#include <stdint.h> +#include <sys/types.h> + +#include <gui/IGraphicBufferAlloc.h> +#include <ui/PixelFormat.h> +#include <utils/Errors.h> + +namespace android { +// --------------------------------------------------------------------------- + +class GraphicBuffer; + +class GraphicBufferAlloc : public BnGraphicBufferAlloc { +public: + GraphicBufferAlloc(); + virtual ~GraphicBufferAlloc(); + virtual sp<GraphicBuffer> createGraphicBuffer(uint32_t w, uint32_t h, + PixelFormat format, uint32_t usage, status_t* error); +}; + + +// --------------------------------------------------------------------------- +}; // namespace android + +#endif // ANDROID_SF_GRAPHIC_BUFFER_ALLOC_H diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp index 65763db..068fdcd 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp +++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp @@ -16,6 +16,9 @@ #define ATRACE_TAG ATRACE_TAG_GRAPHICS +// Uncomment this to remove support for HWC_DEVICE_API_VERSION_0_3 and older +#define HWC_REMOVE_DEPRECATED_VERSIONS 1 + #include <stdint.h> #include <stdio.h> #include <stdlib.h> @@ -23,68 +26,162 @@ #include <sys/types.h> #include <utils/Errors.h> +#include <utils/misc.h> #include <utils/String8.h> #include <utils/Thread.h> #include <utils/Trace.h> #include <utils/Vector.h> +#include <ui/GraphicBuffer.h> + #include <hardware/hardware.h> #include <hardware/hwcomposer.h> #include <cutils/log.h> #include <cutils/properties.h> -#include <EGL/egl.h> - +#include "Layer.h" // needed only for debugging #include "LayerBase.h" #include "HWComposer.h" #include "SurfaceFlinger.h" +#include <utils/CallStack.h> namespace android { + +#define MIN_HWC_HEADER_VERSION HWC_HEADER_VERSION + +static uint32_t hwcApiVersion(const hwc_composer_device_1_t* hwc) { + uint32_t hwcVersion = hwc->common.version; + return hwcVersion & HARDWARE_API_VERSION_2_MAJ_MIN_MASK; +} + +static uint32_t hwcHeaderVersion(const hwc_composer_device_1_t* hwc) { + uint32_t hwcVersion = hwc->common.version; + return hwcVersion & HARDWARE_API_VERSION_2_HEADER_MASK; +} + +static bool hwcHasApiVersion(const hwc_composer_device_1_t* hwc, + uint32_t version) { + return hwcApiVersion(hwc) >= (version & HARDWARE_API_VERSION_2_MAJ_MIN_MASK); +} + +// --------------------------------------------------------------------------- + +struct HWComposer::cb_context { + struct callbacks : public hwc_procs_t { + // these are here to facilitate the transition when adding + // new callbacks (an implementation can check for NULL before + // calling a new callback). + void (*zero[4])(void); + }; + callbacks procs; + HWComposer* hwc; +}; + // --------------------------------------------------------------------------- HWComposer::HWComposer( const sp<SurfaceFlinger>& flinger, - EventHandler& handler, - nsecs_t refreshPeriod) + EventHandler& handler) : mFlinger(flinger), - mModule(0), mHwc(0), mList(0), mCapacity(0), - mNumOVLayers(0), mNumFBLayers(0), - mDpy(EGL_NO_DISPLAY), mSur(EGL_NO_SURFACE), + mFbDev(0), mHwc(0), mNumDisplays(1), + mCBContext(new cb_context), mEventHandler(handler), - mRefreshPeriod(refreshPeriod), mVSyncCount(0), mDebugForceFakeVSync(false) { + for (size_t i =0 ; i<MAX_DISPLAYS ; i++) { + mLists[i] = 0; + } + char value[PROPERTY_VALUE_MAX]; property_get("debug.sf.no_hw_vsync", value, "0"); mDebugForceFakeVSync = atoi(value); - bool needVSyncThread = false; - int err = hw_get_module(HWC_HARDWARE_MODULE_ID, &mModule); - ALOGW_IF(err, "%s module not found", HWC_HARDWARE_MODULE_ID); - if (err == 0) { - err = hwc_open(mModule, &mHwc); - ALOGE_IF(err, "%s device failed to initialize (%s)", - HWC_HARDWARE_COMPOSER, strerror(-err)); - if (err == 0) { - if (mHwc->registerProcs) { - mCBContext.hwc = this; - mCBContext.procs.invalidate = &hook_invalidate; - mCBContext.procs.vsync = &hook_vsync; - mHwc->registerProcs(mHwc, &mCBContext.procs); - memset(mCBContext.procs.zero, 0, sizeof(mCBContext.procs.zero)); - } - if (mHwc->common.version >= HWC_DEVICE_API_VERSION_0_3) { - if (mDebugForceFakeVSync) { - // make sure to turn h/w vsync off in "fake vsync" mode - mHwc->methods->eventControl(mHwc, HWC_EVENT_VSYNC, 0); - } - } else { - needVSyncThread = true; - } + bool needVSyncThread = true; + + // Note: some devices may insist that the FB HAL be opened before HWC. + loadFbHalModule(); + loadHwcModule(); + + if (mFbDev && mHwc && hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) { + // close FB HAL if we don't needed it. + // FIXME: this is temporary until we're not forced to open FB HAL + // before HWC. + framebuffer_close(mFbDev); + mFbDev = NULL; + } + + // If we have no HWC, or a pre-1.1 HWC, an FB dev is mandatory. + if ((!mHwc || !hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) + && !mFbDev) { + ALOGE("ERROR: failed to open framebuffer, aborting"); + abort(); + } + + // these display IDs are always reserved + for (size_t i=0 ; i<HWC_NUM_DISPLAY_TYPES ; i++) { + mAllocatedDisplayIDs.markBit(i); + } + + if (mHwc) { + ALOGI("Using %s version %u.%u", HWC_HARDWARE_COMPOSER, + (hwcApiVersion(mHwc) >> 24) & 0xff, + (hwcApiVersion(mHwc) >> 16) & 0xff); + if (mHwc->registerProcs) { + mCBContext->hwc = this; + mCBContext->procs.invalidate = &hook_invalidate; + mCBContext->procs.vsync = &hook_vsync; + if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) + mCBContext->procs.hotplug = &hook_hotplug; + else + mCBContext->procs.hotplug = NULL; + memset(mCBContext->procs.zero, 0, sizeof(mCBContext->procs.zero)); + mHwc->registerProcs(mHwc, &mCBContext->procs); + } + + // don't need a vsync thread if we have a hardware composer + needVSyncThread = false; + // always turn vsync off when we start + eventControl(HWC_DISPLAY_PRIMARY, HWC_EVENT_VSYNC, 0); + + // the number of displays we actually have depends on the + // hw composer version + if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_2)) { + // 1.2 adds support for virtual displays + mNumDisplays = MAX_DISPLAYS; + } else if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) { + // 1.1 adds support for multiple displays + mNumDisplays = HWC_NUM_DISPLAY_TYPES; + } else { + mNumDisplays = 1; + } + } + + if (mFbDev) { + ALOG_ASSERT(!(mHwc && hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)), + "should only have fbdev if no hwc or hwc is 1.0"); + + DisplayData& disp(mDisplayData[HWC_DISPLAY_PRIMARY]); + disp.connected = true; + disp.width = mFbDev->width; + disp.height = mFbDev->height; + disp.format = mFbDev->format; + disp.xdpi = mFbDev->xdpi; + disp.ydpi = mFbDev->ydpi; + if (disp.refresh == 0) { + disp.refresh = nsecs_t(1e9 / mFbDev->fps); + ALOGW("getting VSYNC period from fb HAL: %lld", disp.refresh); + } + if (disp.refresh == 0) { + disp.refresh = nsecs_t(1e9 / 60.0); + ALOGW("getting VSYNC period from thin air: %lld", + mDisplayData[HWC_DISPLAY_PRIMARY].refresh); + } + } else if (mHwc) { + // here we're guaranteed to have at least HWC 1.1 + for (size_t i =0 ; i<HWC_NUM_DISPLAY_TYPES ; i++) { + queryDisplayProperties(i); } - } else { - needVSyncThread = true; } if (needVSyncThread) { @@ -94,13 +191,63 @@ HWComposer::HWComposer( } HWComposer::~HWComposer() { - eventControl(EVENT_VSYNC, 0); - free(mList); + if (mHwc) { + eventControl(HWC_DISPLAY_PRIMARY, HWC_EVENT_VSYNC, 0); + } if (mVSyncThread != NULL) { mVSyncThread->requestExitAndWait(); } if (mHwc) { - hwc_close(mHwc); + hwc_close_1(mHwc); + } + if (mFbDev) { + framebuffer_close(mFbDev); + } + delete mCBContext; +} + +// Load and prepare the hardware composer module. Sets mHwc. +void HWComposer::loadHwcModule() +{ + hw_module_t const* module; + + if (hw_get_module(HWC_HARDWARE_MODULE_ID, &module) != 0) { + ALOGE("%s module not found", HWC_HARDWARE_MODULE_ID); + return; + } + + int err = hwc_open_1(module, &mHwc); + if (err) { + ALOGE("%s device failed to initialize (%s)", + HWC_HARDWARE_COMPOSER, strerror(-err)); + return; + } + + if (!hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_0) || + hwcHeaderVersion(mHwc) < MIN_HWC_HEADER_VERSION || + hwcHeaderVersion(mHwc) > HWC_HEADER_VERSION) { + ALOGE("%s device version %#x unsupported, will not be used", + HWC_HARDWARE_COMPOSER, mHwc->common.version); + hwc_close_1(mHwc); + mHwc = NULL; + return; + } +} + +// Load and prepare the FB HAL, which uses the gralloc module. Sets mFbDev. +void HWComposer::loadFbHalModule() +{ + hw_module_t const* module; + + if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module) != 0) { + ALOGE("%s module not found", GRALLOC_HARDWARE_MODULE_ID); + return; + } + + int err = framebuffer_open(module, &mFbDev); + if (err) { + ALOGE("framebuffer_open failed (%s)", strerror(-err)); + return; } } @@ -108,33 +255,217 @@ status_t HWComposer::initCheck() const { return mHwc ? NO_ERROR : NO_INIT; } -void HWComposer::hook_invalidate(struct hwc_procs* procs) { - reinterpret_cast<cb_context *>(procs)->hwc->invalidate(); +void HWComposer::hook_invalidate(const struct hwc_procs* procs) { + cb_context* ctx = reinterpret_cast<cb_context*>( + const_cast<hwc_procs_t*>(procs)); + ctx->hwc->invalidate(); +} + +void HWComposer::hook_vsync(const struct hwc_procs* procs, int disp, + int64_t timestamp) { + cb_context* ctx = reinterpret_cast<cb_context*>( + const_cast<hwc_procs_t*>(procs)); + ctx->hwc->vsync(disp, timestamp); } -void HWComposer::hook_vsync(struct hwc_procs* procs, int dpy, int64_t timestamp) { - reinterpret_cast<cb_context *>(procs)->hwc->vsync(dpy, timestamp); +void HWComposer::hook_hotplug(const struct hwc_procs* procs, int disp, + int connected) { + cb_context* ctx = reinterpret_cast<cb_context*>( + const_cast<hwc_procs_t*>(procs)); + ctx->hwc->hotplug(disp, connected); } void HWComposer::invalidate() { mFlinger->repaintEverything(); } -void HWComposer::vsync(int dpy, int64_t timestamp) { +void HWComposer::vsync(int disp, int64_t timestamp) { ATRACE_INT("VSYNC", ++mVSyncCount&1); - mEventHandler.onVSyncReceived(dpy, timestamp); + mEventHandler.onVSyncReceived(disp, timestamp); + Mutex::Autolock _l(mLock); + mLastHwVSync = timestamp; } -void HWComposer::eventControl(int event, int enabled) { +void HWComposer::hotplug(int disp, int connected) { + if (disp == HWC_DISPLAY_PRIMARY || disp >= HWC_NUM_DISPLAY_TYPES) { + ALOGE("hotplug event received for invalid display: disp=%d connected=%d", + disp, connected); + return; + } + queryDisplayProperties(disp); + mEventHandler.onHotplugReceived(disp, bool(connected)); +} + +static const uint32_t DISPLAY_ATTRIBUTES[] = { + HWC_DISPLAY_VSYNC_PERIOD, + HWC_DISPLAY_WIDTH, + HWC_DISPLAY_HEIGHT, + HWC_DISPLAY_DPI_X, + HWC_DISPLAY_DPI_Y, + HWC_DISPLAY_NO_ATTRIBUTE, +}; +#define NUM_DISPLAY_ATTRIBUTES (sizeof(DISPLAY_ATTRIBUTES) / sizeof(DISPLAY_ATTRIBUTES)[0]) + +// http://developer.android.com/reference/android/util/DisplayMetrics.html +#define ANDROID_DENSITY_TV 213 +#define ANDROID_DENSITY_XHIGH 320 + +status_t HWComposer::queryDisplayProperties(int disp) { + + LOG_ALWAYS_FATAL_IF(!mHwc || !hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)); + + // use zero as default value for unspecified attributes + int32_t values[NUM_DISPLAY_ATTRIBUTES - 1]; + memset(values, 0, sizeof(values)); + + uint32_t config; + size_t numConfigs = 1; + status_t err = mHwc->getDisplayConfigs(mHwc, disp, &config, &numConfigs); + if (err != NO_ERROR) { + // this can happen if an unpluggable display is not connected + mDisplayData[disp].connected = false; + return err; + } + + err = mHwc->getDisplayAttributes(mHwc, disp, config, DISPLAY_ATTRIBUTES, values); + if (err != NO_ERROR) { + // we can't get this display's info. turn it off. + mDisplayData[disp].connected = false; + return err; + } + + int32_t w = 0, h = 0; + for (size_t i = 0; i < NUM_DISPLAY_ATTRIBUTES - 1; i++) { + switch (DISPLAY_ATTRIBUTES[i]) { + case HWC_DISPLAY_VSYNC_PERIOD: + mDisplayData[disp].refresh = nsecs_t(values[i]); + break; + case HWC_DISPLAY_WIDTH: + mDisplayData[disp].width = values[i]; + break; + case HWC_DISPLAY_HEIGHT: + mDisplayData[disp].height = values[i]; + break; + case HWC_DISPLAY_DPI_X: + mDisplayData[disp].xdpi = values[i] / 1000.0f; + break; + case HWC_DISPLAY_DPI_Y: + mDisplayData[disp].ydpi = values[i] / 1000.0f; + break; + default: + ALOG_ASSERT(false, "unknown display attribute[%d] %#x", + i, DISPLAY_ATTRIBUTES[i]); + break; + } + } + + // FIXME: what should we set the format to? + mDisplayData[disp].format = HAL_PIXEL_FORMAT_RGBA_8888; + mDisplayData[disp].connected = true; + if (mDisplayData[disp].xdpi == 0.0f || mDisplayData[disp].ydpi == 0.0f) { + // is there anything smarter we can do? + if (h >= 1080) { + mDisplayData[disp].xdpi = ANDROID_DENSITY_XHIGH; + mDisplayData[disp].ydpi = ANDROID_DENSITY_XHIGH; + } else { + mDisplayData[disp].xdpi = ANDROID_DENSITY_TV; + mDisplayData[disp].ydpi = ANDROID_DENSITY_TV; + } + } + return NO_ERROR; +} + +int32_t HWComposer::allocateDisplayId() { + if (mAllocatedDisplayIDs.count() >= mNumDisplays) { + return NO_MEMORY; + } + int32_t id = mAllocatedDisplayIDs.firstUnmarkedBit(); + mAllocatedDisplayIDs.markBit(id); + return id; +} + +status_t HWComposer::freeDisplayId(int32_t id) { + if (id < HWC_NUM_DISPLAY_TYPES) { + // cannot free the reserved IDs + return BAD_VALUE; + } + if (uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id)) { + return BAD_INDEX; + } + mAllocatedDisplayIDs.clearBit(id); + return NO_ERROR; +} + +nsecs_t HWComposer::getRefreshPeriod(int disp) const { + return mDisplayData[disp].refresh; +} + +nsecs_t HWComposer::getRefreshTimestamp(int disp) const { + // this returns the last refresh timestamp. + // if the last one is not available, we estimate it based on + // the refresh period and whatever closest timestamp we have. + Mutex::Autolock _l(mLock); + nsecs_t now = systemTime(CLOCK_MONOTONIC); + return now - ((now - mLastHwVSync) % mDisplayData[disp].refresh); +} + +uint32_t HWComposer::getWidth(int disp) const { + return mDisplayData[disp].width; +} + +uint32_t HWComposer::getHeight(int disp) const { + return mDisplayData[disp].height; +} + +uint32_t HWComposer::getFormat(int disp) const { + return mDisplayData[disp].format; +} + +float HWComposer::getDpiX(int disp) const { + return mDisplayData[disp].xdpi; +} + +float HWComposer::getDpiY(int disp) const { + return mDisplayData[disp].ydpi; +} + +bool HWComposer::isConnected(int disp) const { + return mDisplayData[disp].connected; +} + +void HWComposer::eventControl(int disp, int event, int enabled) { + if (uint32_t(disp)>31 || !mAllocatedDisplayIDs.hasBit(disp)) { + ALOGD("eventControl ignoring event %d on unallocated disp %d (en=%d)", + event, disp, enabled); + return; + } + if (event != EVENT_VSYNC) { + ALOGW("eventControl got unexpected event %d (disp=%d en=%d)", + event, disp, enabled); + return; + } status_t err = NO_ERROR; - if (mHwc && mHwc->common.version >= HWC_DEVICE_API_VERSION_0_3) { - if (!mDebugForceFakeVSync) { - err = mHwc->methods->eventControl(mHwc, event, enabled); - // error here should not happen -- not sure what we should - // do if it does. - ALOGE_IF(err, "eventControl(%d, %d) failed %s", - event, enabled, strerror(-err)); + if (mHwc && !mDebugForceFakeVSync) { + // NOTE: we use our own internal lock here because we have to call + // into the HWC with the lock held, and we want to make sure + // that even if HWC blocks (which it shouldn't), it won't + // affect other threads. + Mutex::Autolock _l(mEventControlLock); + const int32_t eventBit = 1UL << event; + const int32_t newValue = enabled ? eventBit : 0; + const int32_t oldValue = mDisplayData[disp].events & eventBit; + if (newValue != oldValue) { + ATRACE_CALL(); + err = mHwc->eventControl(mHwc, disp, event, enabled); + if (!err) { + int32_t& events(mDisplayData[disp].events); + events = (events & ~eventBit) | newValue; + } } + // error here should not happen -- not sure what we should + // do if it does. + ALOGE_IF(err, "eventControl(%d, %d) failed %s", + event, enabled, strerror(-err)); } if (err == NO_ERROR && mVSyncThread != NULL) { @@ -142,130 +473,504 @@ void HWComposer::eventControl(int event, int enabled) { } } -void HWComposer::setFrameBuffer(EGLDisplay dpy, EGLSurface sur) { - mDpy = (hwc_display_t)dpy; - mSur = (hwc_surface_t)sur; -} +status_t HWComposer::createWorkList(int32_t id, size_t numLayers) { + if (uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id)) { + return BAD_INDEX; + } -status_t HWComposer::createWorkList(size_t numLayers) { if (mHwc) { - if (!mList || mCapacity < numLayers) { - free(mList); - size_t size = sizeof(hwc_layer_list) + numLayers*sizeof(hwc_layer_t); - mList = (hwc_layer_list_t*)malloc(size); - mCapacity = numLayers; + DisplayData& disp(mDisplayData[id]); + if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) { + // we need space for the HWC_FRAMEBUFFER_TARGET + numLayers++; } - mList->flags = HWC_GEOMETRY_CHANGED; - mList->numHwLayers = numLayers; + if (disp.capacity < numLayers || disp.list == NULL) { + size_t size = sizeof(hwc_display_contents_1_t) + + numLayers * sizeof(hwc_layer_1_t); + free(disp.list); + disp.list = (hwc_display_contents_1_t*)malloc(size); + disp.capacity = numLayers; + } + if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) { + disp.framebufferTarget = &disp.list->hwLayers[numLayers - 1]; + memset(disp.framebufferTarget, 0, sizeof(hwc_layer_1_t)); + const hwc_rect_t r = { 0, 0, disp.width, disp.height }; + disp.framebufferTarget->compositionType = HWC_FRAMEBUFFER_TARGET; + disp.framebufferTarget->hints = 0; + disp.framebufferTarget->flags = 0; + disp.framebufferTarget->handle = disp.fbTargetHandle; + disp.framebufferTarget->transform = 0; + disp.framebufferTarget->blending = HWC_BLENDING_PREMULT; + disp.framebufferTarget->sourceCrop = r; + disp.framebufferTarget->displayFrame = r; + disp.framebufferTarget->visibleRegionScreen.numRects = 1; + disp.framebufferTarget->visibleRegionScreen.rects = + &disp.framebufferTarget->displayFrame; + disp.framebufferTarget->acquireFenceFd = -1; + disp.framebufferTarget->releaseFenceFd = -1; + } + disp.list->retireFenceFd = -1; + disp.list->flags = HWC_GEOMETRY_CHANGED; + disp.list->numHwLayers = numLayers; } return NO_ERROR; } -status_t HWComposer::prepare() const { - int err = mHwc->prepare(mHwc, mList); - if (err == NO_ERROR) { - size_t numOVLayers = 0; - size_t numFBLayers = 0; - size_t count = mList->numHwLayers; - for (size_t i=0 ; i<count ; i++) { - hwc_layer& l(mList->hwLayers[i]); - if (l.flags & HWC_SKIP_LAYER) { - l.compositionType = HWC_FRAMEBUFFER; +status_t HWComposer::setFramebufferTarget(int32_t id, + const sp<Fence>& acquireFence, const sp<GraphicBuffer>& buf) { + if (uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id)) { + return BAD_INDEX; + } + DisplayData& disp(mDisplayData[id]); + if (!disp.framebufferTarget) { + // this should never happen, but apparently eglCreateWindowSurface() + // triggers a SurfaceTextureClient::queueBuffer() on some + // devices (!?) -- log and ignore. + ALOGE("HWComposer: framebufferTarget is null"); +// CallStack stack; +// stack.update(); +// stack.dump(""); + return NO_ERROR; + } + + int acquireFenceFd = -1; + if (acquireFence != NULL) { + acquireFenceFd = acquireFence->dup(); + } + + // ALOGD("fbPost: handle=%p, fence=%d", buf->handle, acquireFenceFd); + disp.fbTargetHandle = buf->handle; + disp.framebufferTarget->handle = disp.fbTargetHandle; + disp.framebufferTarget->acquireFenceFd = acquireFenceFd; + return NO_ERROR; +} + +status_t HWComposer::prepare() { + for (size_t i=0 ; i<mNumDisplays ; i++) { + DisplayData& disp(mDisplayData[i]); + if (disp.framebufferTarget) { + // make sure to reset the type to HWC_FRAMEBUFFER_TARGET + // DO NOT reset the handle field to NULL, because it's possible + // that we have nothing to redraw (eg: eglSwapBuffers() not called) + // in which case, we should continue to use the same buffer. + LOG_FATAL_IF(disp.list == NULL); + disp.framebufferTarget->compositionType = HWC_FRAMEBUFFER_TARGET; + } + if (!disp.connected && disp.list != NULL) { + ALOGW("WARNING: disp %d: connected, non-null list, layers=%d", + i, disp.list->numHwLayers); + } + mLists[i] = disp.list; + if (mLists[i]) { + if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_2)) { + mLists[i]->outbuf = NULL; + mLists[i]->outbufAcquireFenceFd = -1; + } else if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) { + // garbage data to catch improper use + mLists[i]->dpy = (hwc_display_t)0xDEADBEEF; + mLists[i]->sur = (hwc_surface_t)0xDEADBEEF; + } else { + mLists[i]->dpy = EGL_NO_DISPLAY; + mLists[i]->sur = EGL_NO_SURFACE; } - switch (l.compositionType) { - case HWC_OVERLAY: - numOVLayers++; - break; - case HWC_FRAMEBUFFER: - numFBLayers++; - break; + } + } + + int err = mHwc->prepare(mHwc, mNumDisplays, mLists); + ALOGE_IF(err, "HWComposer: prepare failed (%s)", strerror(-err)); + + if (err == NO_ERROR) { + // here we're just making sure that "skip" layers are set + // to HWC_FRAMEBUFFER and we're also counting how many layers + // we have of each type. + for (size_t i=0 ; i<mNumDisplays ; i++) { + DisplayData& disp(mDisplayData[i]); + disp.hasFbComp = false; + disp.hasOvComp = false; + if (disp.list) { + for (size_t i=0 ; i<disp.list->numHwLayers ; i++) { + hwc_layer_1_t& l = disp.list->hwLayers[i]; + + //ALOGD("prepare: %d, type=%d, handle=%p", + // i, l.compositionType, l.handle); + + if (l.flags & HWC_SKIP_LAYER) { + l.compositionType = HWC_FRAMEBUFFER; + } + if (l.compositionType == HWC_FRAMEBUFFER) { + disp.hasFbComp = true; + } + if (l.compositionType == HWC_OVERLAY) { + disp.hasOvComp = true; + } + } } } - mNumOVLayers = numOVLayers; - mNumFBLayers = numFBLayers; } return (status_t)err; } -size_t HWComposer::getLayerCount(int type) const { - switch (type) { - case HWC_OVERLAY: - return mNumOVLayers; - case HWC_FRAMEBUFFER: - return mNumFBLayers; +bool HWComposer::hasHwcComposition(int32_t id) const { + if (uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id)) + return false; + return mDisplayData[id].hasOvComp; +} + +bool HWComposer::hasGlesComposition(int32_t id) const { + if (uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id)) + return false; + return mDisplayData[id].hasFbComp; +} + +int HWComposer::getAndResetReleaseFenceFd(int32_t id) { + if (uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id)) + return BAD_INDEX; + + int fd = INVALID_OPERATION; + if (mHwc && hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) { + const DisplayData& disp(mDisplayData[id]); + if (disp.framebufferTarget) { + fd = disp.framebufferTarget->releaseFenceFd; + disp.framebufferTarget->acquireFenceFd = -1; + disp.framebufferTarget->releaseFenceFd = -1; + } } - return 0; + return fd; } -status_t HWComposer::commit() const { - int err = mHwc->set(mHwc, mDpy, mSur, mList); - if (mList) { - mList->flags &= ~HWC_GEOMETRY_CHANGED; +status_t HWComposer::commit() { + int err = NO_ERROR; + if (mHwc) { + if (!hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) { + // On version 1.0, the OpenGL ES target surface is communicated + // by the (dpy, sur) fields and we are guaranteed to have only + // a single display. + mLists[0]->dpy = eglGetCurrentDisplay(); + mLists[0]->sur = eglGetCurrentSurface(EGL_DRAW); + } + + err = mHwc->set(mHwc, mNumDisplays, mLists); + + for (size_t i=0 ; i<mNumDisplays ; i++) { + DisplayData& disp(mDisplayData[i]); + if (disp.list) { + if (disp.list->retireFenceFd != -1) { + close(disp.list->retireFenceFd); + disp.list->retireFenceFd = -1; + } + disp.list->flags &= ~HWC_GEOMETRY_CHANGED; + } + } } return (status_t)err; } -status_t HWComposer::release() const { +status_t HWComposer::release(int disp) { + LOG_FATAL_IF(disp >= HWC_NUM_DISPLAY_TYPES); if (mHwc) { - if (mHwc->common.version >= HWC_DEVICE_API_VERSION_0_3) { - mHwc->methods->eventControl(mHwc, HWC_EVENT_VSYNC, 0); - } - int err = mHwc->set(mHwc, NULL, NULL, NULL); - return (status_t)err; + eventControl(disp, HWC_EVENT_VSYNC, 0); + return (status_t)mHwc->blank(mHwc, disp, 1); } return NO_ERROR; } -status_t HWComposer::disable() { +status_t HWComposer::acquire(int disp) { + LOG_FATAL_IF(disp >= HWC_NUM_DISPLAY_TYPES); if (mHwc) { - free(mList); - mList = NULL; - int err = mHwc->prepare(mHwc, NULL); - return (status_t)err; + return (status_t)mHwc->blank(mHwc, disp, 0); } return NO_ERROR; } -size_t HWComposer::getNumLayers() const { - return mList ? mList->numHwLayers : 0; -} - -hwc_layer_t* HWComposer::getLayers() const { - return mList ? mList->hwLayers : 0; -} - -void HWComposer::dump(String8& result, char* buffer, size_t SIZE, - const Vector< sp<LayerBase> >& visibleLayersSortedByZ) const { - if (mHwc && mList) { - result.append("Hardware Composer state:\n"); - result.appendFormat(" mDebugForceFakeVSync=%d\n", - mDebugForceFakeVSync); - result.appendFormat(" numHwLayers=%u, flags=%08x\n", - mList->numHwLayers, mList->flags); - result.append( - " type | handle | hints | flags | tr | blend | format | source crop | frame name \n" - "----------+----------+----------+----------+----+-------+----------+---------------------------+--------------------------------\n"); - // " ________ | ________ | ________ | ________ | __ | _____ | ________ | [_____,_____,_____,_____] | [_____,_____,_____,_____] - for (size_t i=0 ; i<mList->numHwLayers ; i++) { - const hwc_layer_t& l(mList->hwLayers[i]); - const sp<LayerBase> layer(visibleLayersSortedByZ[i]); - int32_t format = -1; - if (layer->getLayer() != NULL) { - const sp<GraphicBuffer>& buffer(layer->getLayer()->getActiveBuffer()); - if (buffer != NULL) { - format = buffer->getPixelFormat(); +void HWComposer::disconnectDisplay(int disp) { + LOG_ALWAYS_FATAL_IF(disp < 0 || disp == HWC_DISPLAY_PRIMARY); + if (disp >= HWC_NUM_DISPLAY_TYPES) { + // nothing to do for these yet + return; + } + DisplayData& dd(mDisplayData[disp]); + if (dd.list != NULL) { + free(dd.list); + dd.list = NULL; + dd.framebufferTarget = NULL; // points into dd.list + dd.fbTargetHandle = NULL; + } +} + +int HWComposer::getVisualID() const { + if (mHwc && hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) { + // FIXME: temporary hack until HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED + // is supported by the implementation. we can only be in this case + // if we have HWC 1.1 + return HAL_PIXEL_FORMAT_RGBA_8888; + //return HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED; + } else { + return mFbDev->format; + } +} + +bool HWComposer::supportsFramebufferTarget() const { + return (mHwc && hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)); +} + +int HWComposer::fbPost(int32_t id, + const sp<Fence>& acquireFence, const sp<GraphicBuffer>& buffer) { + if (mHwc && hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) { + return setFramebufferTarget(id, acquireFence, buffer); + } else { + if (acquireFence != NULL) { + acquireFence->waitForever(1000, "HWComposer::fbPost"); + } + return mFbDev->post(mFbDev, buffer->handle); + } +} + +int HWComposer::fbCompositionComplete() { + if (mHwc && hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) + return NO_ERROR; + + if (mFbDev->compositionComplete) { + return mFbDev->compositionComplete(mFbDev); + } else { + return INVALID_OPERATION; + } +} + +void HWComposer::fbDump(String8& result) { + if (mFbDev && mFbDev->common.version >= 1 && mFbDev->dump) { + const size_t SIZE = 4096; + char buffer[SIZE]; + mFbDev->dump(mFbDev, buffer, SIZE); + result.append(buffer); + } +} + +/* + * Helper template to implement a concrete HWCLayer + * This holds the pointer to the concrete hwc layer type + * and implements the "iterable" side of HWCLayer. + */ +template<typename CONCRETE, typename HWCTYPE> +class Iterable : public HWComposer::HWCLayer { +protected: + HWCTYPE* const mLayerList; + HWCTYPE* mCurrentLayer; + Iterable(HWCTYPE* layer) : mLayerList(layer), mCurrentLayer(layer) { } + inline HWCTYPE const * getLayer() const { return mCurrentLayer; } + inline HWCTYPE* getLayer() { return mCurrentLayer; } + virtual ~Iterable() { } +private: + // returns a copy of ourselves + virtual HWComposer::HWCLayer* dup() { + return new CONCRETE( static_cast<const CONCRETE&>(*this) ); + } + virtual status_t setLayer(size_t index) { + mCurrentLayer = &mLayerList[index]; + return NO_ERROR; + } +}; + +/* + * Concrete implementation of HWCLayer for HWC_DEVICE_API_VERSION_1_0. + * This implements the HWCLayer side of HWCIterableLayer. + */ +class HWCLayerVersion1 : public Iterable<HWCLayerVersion1, hwc_layer_1_t> { +public: + HWCLayerVersion1(hwc_layer_1_t* layer) + : Iterable<HWCLayerVersion1, hwc_layer_1_t>(layer) { } + + virtual int32_t getCompositionType() const { + return getLayer()->compositionType; + } + virtual uint32_t getHints() const { + return getLayer()->hints; + } + virtual int getAndResetReleaseFenceFd() { + int fd = getLayer()->releaseFenceFd; + getLayer()->releaseFenceFd = -1; + return fd; + } + virtual void setAcquireFenceFd(int fenceFd) { + getLayer()->acquireFenceFd = fenceFd; + } + virtual void setPerFrameDefaultState() { + //getLayer()->compositionType = HWC_FRAMEBUFFER; + } + virtual void setDefaultState() { + getLayer()->compositionType = HWC_FRAMEBUFFER; + getLayer()->hints = 0; + getLayer()->flags = HWC_SKIP_LAYER; + getLayer()->handle = 0; + getLayer()->transform = 0; + getLayer()->blending = HWC_BLENDING_NONE; + getLayer()->visibleRegionScreen.numRects = 0; + getLayer()->visibleRegionScreen.rects = NULL; + getLayer()->acquireFenceFd = -1; + getLayer()->releaseFenceFd = -1; + } + virtual void setSkip(bool skip) { + if (skip) { + getLayer()->flags |= HWC_SKIP_LAYER; + } else { + getLayer()->flags &= ~HWC_SKIP_LAYER; + } + } + virtual void setBlending(uint32_t blending) { + getLayer()->blending = blending; + } + virtual void setTransform(uint32_t transform) { + getLayer()->transform = transform; + } + virtual void setFrame(const Rect& frame) { + reinterpret_cast<Rect&>(getLayer()->displayFrame) = frame; + } + virtual void setCrop(const Rect& crop) { + reinterpret_cast<Rect&>(getLayer()->sourceCrop) = crop; + } + virtual void setVisibleRegionScreen(const Region& reg) { + // Region::getSharedBuffer creates a reference to the underlying + // SharedBuffer of this Region, this reference is freed + // in onDisplayed() + hwc_region_t& visibleRegion = getLayer()->visibleRegionScreen; + SharedBuffer const* sb = reg.getSharedBuffer(&visibleRegion.numRects); + visibleRegion.rects = reinterpret_cast<hwc_rect_t const *>(sb->data()); + } + virtual void setBuffer(const sp<GraphicBuffer>& buffer) { + if (buffer == 0 || buffer->handle == 0) { + getLayer()->compositionType = HWC_FRAMEBUFFER; + getLayer()->flags |= HWC_SKIP_LAYER; + getLayer()->handle = 0; + } else { + getLayer()->handle = buffer->handle; + } + } + virtual void onDisplayed() { + hwc_region_t& visibleRegion = getLayer()->visibleRegionScreen; + SharedBuffer const* sb = SharedBuffer::bufferFromData(visibleRegion.rects); + if (sb) { + sb->release(); + // not technically needed but safer + visibleRegion.numRects = 0; + visibleRegion.rects = NULL; + } + + getLayer()->acquireFenceFd = -1; + } +}; + +/* + * returns an iterator initialized at a given index in the layer list + */ +HWComposer::LayerListIterator HWComposer::getLayerIterator(int32_t id, size_t index) { + if (uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id)) { + return LayerListIterator(); + } + const DisplayData& disp(mDisplayData[id]); + if (!mHwc || !disp.list || index > disp.list->numHwLayers) { + return LayerListIterator(); + } + return LayerListIterator(new HWCLayerVersion1(disp.list->hwLayers), index); +} + +/* + * returns an iterator on the beginning of the layer list + */ +HWComposer::LayerListIterator HWComposer::begin(int32_t id) { + return getLayerIterator(id, 0); +} + +/* + * returns an iterator on the end of the layer list + */ +HWComposer::LayerListIterator HWComposer::end(int32_t id) { + size_t numLayers = 0; + if (uint32_t(id) <= 31 && mAllocatedDisplayIDs.hasBit(id)) { + const DisplayData& disp(mDisplayData[id]); + if (mHwc && disp.list) { + numLayers = disp.list->numHwLayers; + if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) { + // with HWC 1.1, the last layer is always the HWC_FRAMEBUFFER_TARGET, + // which we ignore when iterating through the layer list. + ALOGE_IF(!numLayers, "mDisplayData[%d].list->numHwLayers is 0", id); + if (numLayers) { + numLayers--; + } + } + } + } + return getLayerIterator(id, numLayers); +} + +void HWComposer::dump(String8& result, char* buffer, size_t SIZE) const { + if (mHwc) { + result.appendFormat("Hardware Composer state (version %8x):\n", hwcApiVersion(mHwc)); + result.appendFormat(" mDebugForceFakeVSync=%d\n", mDebugForceFakeVSync); + for (size_t i=0 ; i<mNumDisplays ; i++) { + const DisplayData& disp(mDisplayData[i]); + + const Vector< sp<LayerBase> >& visibleLayersSortedByZ = + mFlinger->getLayerSortedByZForHwcDisplay(i); + + if (disp.connected) { + result.appendFormat( + " Display[%d] : %ux%u, xdpi=%f, ydpi=%f, refresh=%lld\n", + i, disp.width, disp.height, disp.xdpi, disp.ydpi, disp.refresh); + } + + if (disp.list && disp.connected) { + result.appendFormat( + " numHwLayers=%u, flags=%08x\n", + disp.list->numHwLayers, disp.list->flags); + + result.append( + " type | handle | hints | flags | tr | blend | format | source crop | frame name \n" + "------------+----------+----------+----------+----+-------+----------+---------------------------+--------------------------------\n"); + // " __________ | ________ | ________ | ________ | __ | _____ | ________ | [_____,_____,_____,_____] | [_____,_____,_____,_____] + for (size_t i=0 ; i<disp.list->numHwLayers ; i++) { + const hwc_layer_1_t&l = disp.list->hwLayers[i]; + int32_t format = -1; + String8 name("unknown"); + + if (i < visibleLayersSortedByZ.size()) { + const sp<LayerBase>& layer(visibleLayersSortedByZ[i]); + if (layer->getLayer() != NULL) { + const sp<GraphicBuffer>& buffer( + layer->getLayer()->getActiveBuffer()); + if (buffer != NULL) { + format = buffer->getPixelFormat(); + } + } + name = layer->getName(); + } + + int type = l.compositionType; + if (type == HWC_FRAMEBUFFER_TARGET) { + name = "HWC_FRAMEBUFFER_TARGET"; + format = disp.format; + } + + static char const* compositionTypeName[] = { + "GLES", + "HWC", + "BACKGROUND", + "FB TARGET", + "UNKNOWN"}; + if (type >= NELEM(compositionTypeName)) + type = NELEM(compositionTypeName) - 1; + + result.appendFormat( + " %10s | %08x | %08x | %08x | %02x | %05x | %08x | [%5d,%5d,%5d,%5d] | [%5d,%5d,%5d,%5d] %s\n", + compositionTypeName[type], + intptr_t(l.handle), l.hints, l.flags, l.transform, l.blending, format, + l.sourceCrop.left, l.sourceCrop.top, l.sourceCrop.right, l.sourceCrop.bottom, + l.displayFrame.left, l.displayFrame.top, l.displayFrame.right, l.displayFrame.bottom, + name.string()); } } - result.appendFormat( - " %8s | %08x | %08x | %08x | %02x | %05x | %08x | [%5d,%5d,%5d,%5d] | [%5d,%5d,%5d,%5d] %s\n", - l.compositionType ? "OVERLAY" : "FB", - intptr_t(l.handle), l.hints, l.flags, l.transform, l.blending, format, - l.sourceCrop.left, l.sourceCrop.top, l.sourceCrop.right, l.sourceCrop.bottom, - l.displayFrame.left, l.displayFrame.top, l.displayFrame.right, l.displayFrame.bottom, - layer->getName().string()); } } - if (mHwc && mHwc->common.version >= HWC_DEVICE_API_VERSION_0_1 && mHwc->dump) { + + if (mHwc && mHwc->dump) { mHwc->dump(mHwc, buffer, SIZE); result.append(buffer); } @@ -276,14 +981,16 @@ void HWComposer::dump(String8& result, char* buffer, size_t SIZE, HWComposer::VSyncThread::VSyncThread(HWComposer& hwc) : mHwc(hwc), mEnabled(false), mNextFakeVSync(0), - mRefreshPeriod(hwc.mRefreshPeriod) + mRefreshPeriod(hwc.getRefreshPeriod(HWC_DISPLAY_PRIMARY)) { } void HWComposer::VSyncThread::setEnabled(bool enabled) { Mutex::Autolock _l(mLock); - mEnabled = enabled; - mCondition.signal(); + if (mEnabled != enabled) { + mEnabled = enabled; + mCondition.signal(); + } } void HWComposer::VSyncThread::onFirstRef() { diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h index aada3cd..7c67407 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.h +++ b/services/surfaceflinger/DisplayHardware/HWComposer.h @@ -20,65 +20,206 @@ #include <stdint.h> #include <sys/types.h> -#include <EGL/egl.h> - -#include <hardware/hwcomposer.h> +#include <hardware/hwcomposer_defs.h> +#include <utils/Condition.h> +#include <utils/Mutex.h> #include <utils/StrongPointer.h> +#include <utils/Thread.h> +#include <utils/Timers.h> #include <utils/Vector.h> +#include <utils/BitSet.h> extern "C" int clock_nanosleep(clockid_t clock_id, int flags, const struct timespec *request, struct timespec *remain); +struct hwc_composer_device_1; +struct hwc_display_contents_1; +struct hwc_layer_1; +struct hwc_procs; +struct framebuffer_device_t; + namespace android { // --------------------------------------------------------------------------- +class GraphicBuffer; +class Fence; +class LayerBase; +class Region; class String8; class SurfaceFlinger; -class LayerBase; class HWComposer { public: class EventHandler { friend class HWComposer; - virtual void onVSyncReceived(int dpy, nsecs_t timestamp) = 0; + virtual void onVSyncReceived(int disp, nsecs_t timestamp) = 0; + virtual void onHotplugReceived(int disp, bool connected) = 0; protected: virtual ~EventHandler() {} }; - HWComposer(const sp<SurfaceFlinger>& flinger, - EventHandler& handler, nsecs_t refreshPeriod); + enum { + MAX_DISPLAYS = HWC_NUM_DISPLAY_TYPES + 1 + }; + + HWComposer( + const sp<SurfaceFlinger>& flinger, + EventHandler& handler); + ~HWComposer(); status_t initCheck() const; - // tells the HAL what the framebuffer is - void setFrameBuffer(EGLDisplay dpy, EGLSurface sur); + // returns a display ID starting at MAX_DISPLAYS, this ID + // is to be used with createWorkList (and all other + // methods requiring an ID below). + // IDs below MAX_DISPLAY are pre-defined and therefore are always valid. + // returns a negative error code if an ID cannot be allocated + int32_t allocateDisplayId(); - // create a work list for numLayers layer. sets HWC_GEOMETRY_CHANGED. - status_t createWorkList(size_t numLayers); + // recycles the given ID and frees the associated worklist. + // IDs below MAX_DISPLAYS are not recycled + status_t freeDisplayId(int32_t id); - // Asks the HAL what it can do - status_t prepare() const; - // disable hwc until next createWorkList - status_t disable(); + // Asks the HAL what it can do + status_t prepare(); // commits the list - status_t commit() const; + status_t commit(); - // release hardware resources - status_t release() const; + // release hardware resources and blank screen + status_t release(int disp); - // get the layer array created by createWorkList() - size_t getNumLayers() const; - hwc_layer_t* getLayers() const; + // acquire hardware resources and unblank screen + status_t acquire(int disp); + + // reset state when an external, non-virtual display is disconnected + void disconnectDisplay(int disp); + + // create a work list for numLayers layer. sets HWC_GEOMETRY_CHANGED. + status_t createWorkList(int32_t id, size_t numLayers); + + bool supportsFramebufferTarget() const; + + // does this display have layers handled by HWC + bool hasHwcComposition(int32_t id) const; + + // does this display have layers handled by GLES + bool hasGlesComposition(int32_t id) const; + + // get the releaseFence file descriptor for the given display + // the release fence is only valid after commit() + int getAndResetReleaseFenceFd(int32_t id); + + // needed forward declarations + class LayerListIterator; + + // return the visual id to be used to find a suitable EGLConfig for + // *ALL* displays. + int getVisualID() const; + + // Forwarding to FB HAL for pre-HWC-1.1 code (see FramebufferSurface). + int fbPost(int32_t id, const sp<Fence>& acquireFence, const sp<GraphicBuffer>& buf); + int fbCompositionComplete(); + void fbDump(String8& result); + + /* + * Interface to hardware composer's layers functionality. + * This abstracts the HAL interface to layers which can evolve in + * incompatible ways from one release to another. + * The idea is that we could extend this interface as we add + * features to h/w composer. + */ + class HWCLayerInterface { + protected: + virtual ~HWCLayerInterface() { } + public: + virtual int32_t getCompositionType() const = 0; + virtual uint32_t getHints() const = 0; + virtual int getAndResetReleaseFenceFd() = 0; + virtual void setPerFrameDefaultState() = 0; + virtual void setDefaultState() = 0; + virtual void setSkip(bool skip) = 0; + virtual void setBlending(uint32_t blending) = 0; + virtual void setTransform(uint32_t transform) = 0; + virtual void setFrame(const Rect& frame) = 0; + virtual void setCrop(const Rect& crop) = 0; + virtual void setVisibleRegionScreen(const Region& reg) = 0; + virtual void setBuffer(const sp<GraphicBuffer>& buffer) = 0; + virtual void setAcquireFenceFd(int fenceFd) = 0; + virtual void onDisplayed() = 0; + }; + + /* + * Interface used to implement an iterator to a list + * of HWCLayer. + */ + class HWCLayer : public HWCLayerInterface { + friend class LayerListIterator; + // select the layer at the given index + virtual status_t setLayer(size_t index) = 0; + virtual HWCLayer* dup() = 0; + static HWCLayer* copy(HWCLayer *rhs) { + return rhs ? rhs->dup() : NULL; + } + protected: + virtual ~HWCLayer() { } + }; + + /* + * Iterator through a HWCLayer list. + * This behaves more or less like a forward iterator. + */ + class LayerListIterator { + friend struct HWComposer; + HWCLayer* const mLayerList; + size_t mIndex; + + LayerListIterator() : mLayerList(NULL), mIndex(0) { } + + LayerListIterator(HWCLayer* layer, size_t index) + : mLayerList(layer), mIndex(index) { } + + // we don't allow assignment, because we don't need it for now + LayerListIterator& operator = (const LayerListIterator& rhs); + + public: + // copy operators + LayerListIterator(const LayerListIterator& rhs) + : mLayerList(HWCLayer::copy(rhs.mLayerList)), mIndex(rhs.mIndex) { + } + + ~LayerListIterator() { delete mLayerList; } + + // pre-increment + LayerListIterator& operator++() { + mLayerList->setLayer(++mIndex); + return *this; + } + + // dereference + HWCLayerInterface& operator * () { return *mLayerList; } + HWCLayerInterface* operator -> () { return mLayerList; } + + // comparison + bool operator == (const LayerListIterator& rhs) const { + return mIndex == rhs.mIndex; + } + bool operator != (const LayerListIterator& rhs) const { + return !operator==(rhs); + } + }; + + // Returns an iterator to the beginning of the layer list + LayerListIterator begin(int32_t id); + + // Returns an iterator to the end of the layer list + LayerListIterator end(int32_t id); - // get number of layers of the given type as updated in prepare(). - // type is HWC_OVERLAY or HWC_FRAMEBUFFER - size_t getLayerCount(int type) const; // Events handling --------------------------------------------------------- @@ -86,7 +227,18 @@ public: EVENT_VSYNC = HWC_EVENT_VSYNC }; - void eventControl(int event, int enabled); + void eventControl(int disp, int event, int enabled); + + // Query display parameters. Pass in a display index (e.g. + // HWC_DISPLAY_PRIMARY). + nsecs_t getRefreshPeriod(int disp) const; + nsecs_t getRefreshTimestamp(int disp) const; + uint32_t getWidth(int disp) const; + uint32_t getHeight(int disp) const; + uint32_t getFormat(int disp) const; + float getDpiX(int disp) const; + float getDpiY(int disp) const; + bool isConnected(int disp) const; // this class is only used to fake the VSync event on systems that don't // have it. @@ -107,46 +259,80 @@ public: friend class VSyncThread; // for debugging ---------------------------------------------------------- - void dump(String8& out, char* scratch, size_t SIZE, - const Vector< sp<LayerBase> >& visibleLayersSortedByZ) const; + void dump(String8& out, char* scratch, size_t SIZE) const; private: + void loadHwcModule(); + void loadFbHalModule(); - struct callbacks : public hwc_procs_t { - // these are here to facilitate the transition when adding - // new callbacks (an implementation can check for NULL before - // calling a new callback). - void (*zero[4])(void); - }; + LayerListIterator getLayerIterator(int32_t id, size_t index); - struct cb_context { - callbacks procs; - HWComposer* hwc; - }; + struct cb_context; - static void hook_invalidate(struct hwc_procs* procs); - static void hook_vsync(struct hwc_procs* procs, int dpy, int64_t timestamp); + static void hook_invalidate(const struct hwc_procs* procs); + static void hook_vsync(const struct hwc_procs* procs, int disp, + int64_t timestamp); + static void hook_hotplug(const struct hwc_procs* procs, int disp, + int connected); inline void invalidate(); - inline void vsync(int dpy, int64_t timestamp); - - sp<SurfaceFlinger> mFlinger; - hw_module_t const* mModule; - hwc_composer_device_t* mHwc; - hwc_layer_list_t* mList; - size_t mCapacity; - mutable size_t mNumOVLayers; - mutable size_t mNumFBLayers; - hwc_display_t mDpy; - hwc_surface_t mSur; - cb_context mCBContext; - EventHandler& mEventHandler; - nsecs_t mRefreshPeriod; - size_t mVSyncCount; - sp<VSyncThread> mVSyncThread; - bool mDebugForceFakeVSync; -}; + inline void vsync(int disp, int64_t timestamp); + inline void hotplug(int disp, int connected); + + status_t queryDisplayProperties(int disp); + + status_t setFramebufferTarget(int32_t id, + const sp<Fence>& acquireFence, const sp<GraphicBuffer>& buf); + + + struct DisplayData { + DisplayData() : xdpi(0), ydpi(0), refresh(0), + connected(false), hasFbComp(false), hasOvComp(false), + capacity(0), list(NULL), + framebufferTarget(NULL), fbTargetHandle(NULL), events(0) { } + ~DisplayData() { + free(list); + } + uint32_t width; + uint32_t height; + uint32_t format; // pixel format from FB hal, for pre-hwc-1.1 + float xdpi; + float ydpi; + nsecs_t refresh; + bool connected; + bool hasFbComp; + bool hasOvComp; + size_t capacity; + hwc_display_contents_1* list; + hwc_layer_1* framebufferTarget; + buffer_handle_t fbTargetHandle; + // protected by mEventControlLock + int32_t events; + }; + sp<SurfaceFlinger> mFlinger; + framebuffer_device_t* mFbDev; + struct hwc_composer_device_1* mHwc; + // invariant: mLists[0] != NULL iff mHwc != NULL + // mLists[i>0] can be NULL. that display is to be ignored + struct hwc_display_contents_1* mLists[MAX_DISPLAYS]; + DisplayData mDisplayData[MAX_DISPLAYS]; + size_t mNumDisplays; + + cb_context* mCBContext; + EventHandler& mEventHandler; + size_t mVSyncCount; + sp<VSyncThread> mVSyncThread; + bool mDebugForceFakeVSync; + BitSet32 mAllocatedDisplayIDs; + + // protected by mLock + mutable Mutex mLock; + mutable nsecs_t mLastHwVSync; + + // thread-safe + mutable Mutex mEventControlLock; +}; // --------------------------------------------------------------------------- }; // namespace android diff --git a/services/surfaceflinger/EventThread.cpp b/services/surfaceflinger/EventThread.cpp index 7c1aebe..edb9fa5 100644 --- a/services/surfaceflinger/EventThread.cpp +++ b/services/surfaceflinger/EventThread.cpp @@ -19,36 +19,37 @@ #include <stdint.h> #include <sys/types.h> +#include <cutils/compiler.h> + #include <gui/BitTube.h> #include <gui/IDisplayEventConnection.h> #include <gui/DisplayEventReceiver.h> #include <utils/Errors.h> +#include <utils/String8.h> #include <utils/Trace.h> -#include "DisplayHardware/DisplayHardware.h" #include "EventThread.h" #include "SurfaceFlinger.h" // --------------------------------------------------------------------------- - namespace android { - // --------------------------------------------------------------------------- EventThread::EventThread(const sp<SurfaceFlinger>& flinger) : mFlinger(flinger), - mHw(flinger->graphicPlane(0).editDisplayHardware()), - mLastVSyncTimestamp(0), - mVSyncTimestamp(0), mUseSoftwareVSync(false), - mDeliveredEvents(0), - mDebugVsyncEnabled(false) -{ + mDebugVsyncEnabled(false) { + + for (int32_t i=0 ; i<HWC_DISPLAY_TYPES_SUPPORTED ; i++) { + mVSyncEvent[i].header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC; + mVSyncEvent[i].header.id = 0; + mVSyncEvent[i].header.timestamp = 0; + mVSyncEvent[i].vsync.count = 0; + } } void EventThread::onFirstRef() { - mHw.setVSyncHandler(this); run("EventThread", PRIORITY_URGENT_DISPLAY + PRIORITY_MORE_FAVORABLE); } @@ -64,14 +65,6 @@ status_t EventThread::registerDisplayEventConnection( return NO_ERROR; } -status_t EventThread::unregisterDisplayEventConnection( - const wp<EventThread::Connection>& connection) { - Mutex::Autolock _l(mLock); - mDisplayEventConnections.remove(connection); - mCondition.broadcast(); - return NO_ERROR; -} - void EventThread::removeDisplayEventConnection( const wp<EventThread::Connection>& connection) { Mutex::Autolock _l(mLock); @@ -118,157 +111,215 @@ void EventThread::onScreenAcquired() { } -void EventThread::onVSyncReceived(int, nsecs_t timestamp) { +void EventThread::onVSyncReceived(int type, nsecs_t timestamp) { + ALOGE_IF(type >= HWC_DISPLAY_TYPES_SUPPORTED, + "received event for an invalid display (id=%d)", type); + Mutex::Autolock _l(mLock); - mVSyncTimestamp = timestamp; - mCondition.broadcast(); + if (type < HWC_DISPLAY_TYPES_SUPPORTED) { + mVSyncEvent[type].header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC; + mVSyncEvent[type].header.id = type; + mVSyncEvent[type].header.timestamp = timestamp; + mVSyncEvent[type].vsync.count++; + mCondition.broadcast(); + } +} + +void EventThread::onHotplugReceived(int type, bool connected) { + ALOGE_IF(type >= HWC_DISPLAY_TYPES_SUPPORTED, + "received event for an invalid display (id=%d)", type); + + Mutex::Autolock _l(mLock); + if (type < HWC_DISPLAY_TYPES_SUPPORTED) { + DisplayEventReceiver::Event event; + event.header.type = DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG; + event.header.id = type; + event.header.timestamp = systemTime(); + event.hotplug.connected = connected; + mPendingEvents.add(event); + mCondition.broadcast(); + } } bool EventThread::threadLoop() { + DisplayEventReceiver::Event event; + Vector< sp<EventThread::Connection> > signalConnections; + signalConnections = waitForEvent(&event); - nsecs_t timestamp; - DisplayEventReceiver::Event vsync; - Vector< wp<EventThread::Connection> > displayEventConnections; + // dispatch events to listeners... + const size_t count = signalConnections.size(); + for (size_t i=0 ; i<count ; i++) { + const sp<Connection>& conn(signalConnections[i]); + // now see if we still need to report this event + status_t err = conn->postEvent(event); + if (err == -EAGAIN || err == -EWOULDBLOCK) { + // The destination doesn't accept events anymore, it's probably + // full. For now, we just drop the events on the floor. + // FIXME: Note that some events cannot be dropped and would have + // to be re-sent later. + // Right-now we don't have the ability to do this. + ALOGW("EventThread: dropping event (%08x) for connection %p", + event.header.type, conn.get()); + } else if (err < 0) { + // handle any other error on the pipe as fatal. the only + // reasonable thing to do is to clean-up this connection. + // The most common error we'll get here is -EPIPE. + removeDisplayEventConnection(signalConnections[i]); + } + } + return true; +} + +// This will return when (1) a vsync event has been received, and (2) there was +// at least one connection interested in receiving it when we started waiting. +Vector< sp<EventThread::Connection> > EventThread::waitForEvent( + DisplayEventReceiver::Event* event) +{ + Mutex::Autolock _l(mLock); + Vector< sp<EventThread::Connection> > signalConnections; do { - Mutex::Autolock _l(mLock); - do { - // latch VSYNC event if any - timestamp = mVSyncTimestamp; - mVSyncTimestamp = 0; - - // check if we should be waiting for VSYNC events - bool waitForNextVsync = false; - size_t count = mDisplayEventConnections.size(); - for (size_t i=0 ; i<count ; i++) { - sp<Connection> connection = - mDisplayEventConnections.itemAt(i).promote(); - if (connection!=0 && connection->count >= 0) { - // at least one continuous mode or active one-shot event - waitForNextVsync = true; - break; - } - } + bool eventPending = false; + bool waitForVSync = false; + size_t vsyncCount = 0; + nsecs_t timestamp = 0; + for (int32_t i=0 ; i<HWC_DISPLAY_TYPES_SUPPORTED ; i++) { + timestamp = mVSyncEvent[i].header.timestamp; if (timestamp) { - if (!waitForNextVsync) { - // we received a VSYNC but we have no clients - // don't report it, and disable VSYNC events - disableVSyncLocked(); - } else { - // report VSYNC event - break; - } - } else { - // never disable VSYNC events immediately, instead - // we'll wait to receive the event and we'll - // reevaluate whether we need to dispatch it and/or - // disable VSYNC events then. - if (waitForNextVsync) { - // enable - enableVSyncLocked(); - } + // we have a vsync event to dispatch + *event = mVSyncEvent[i]; + mVSyncEvent[i].header.timestamp = 0; + vsyncCount = mVSyncEvent[i].vsync.count; + break; } + } - // wait for something to happen - if (mUseSoftwareVSync && waitForNextVsync) { - // h/w vsync cannot be used (screen is off), so we use - // a timeout instead. it doesn't matter how imprecise this - // is, we just need to make sure to serve the clients - if (mCondition.waitRelative(mLock, ms2ns(16)) == TIMED_OUT) { - mVSyncTimestamp = systemTime(SYSTEM_TIME_MONOTONIC); - } - } else { - mCondition.wait(mLock); + if (!timestamp) { + // no vsync event, see if there are some other event + eventPending = !mPendingEvents.isEmpty(); + if (eventPending) { + // we have some other event to dispatch + *event = mPendingEvents[0]; + mPendingEvents.removeAt(0); } - } while(true); - - // process vsync event - mDeliveredEvents++; - mLastVSyncTimestamp = timestamp; + } - // now see if we still need to report this VSYNC event - const size_t count = mDisplayEventConnections.size(); + // find out connections waiting for events + size_t count = mDisplayEventConnections.size(); for (size_t i=0 ; i<count ; i++) { - bool reportVsync = false; - sp<Connection> connection = - mDisplayEventConnections.itemAt(i).promote(); - if (connection == 0) - continue; - - const int32_t count = connection->count; - if (count >= 1) { - if (count==1 || (mDeliveredEvents % count) == 0) { - // continuous event, and time to report it - reportVsync = true; + sp<Connection> connection(mDisplayEventConnections[i].promote()); + if (connection != NULL) { + bool added = false; + if (connection->count >= 0) { + // we need vsync events because at least + // one connection is waiting for it + waitForVSync = true; + if (timestamp) { + // we consume the event only if it's time + // (ie: we received a vsync event) + if (connection->count == 0) { + // fired this time around + connection->count = -1; + signalConnections.add(connection); + added = true; + } else if (connection->count == 1 || + (vsyncCount % connection->count) == 0) { + // continuous event, and time to report it + signalConnections.add(connection); + added = true; + } + } } - } else if (count >= -1) { - if (count == 0) { - // fired this time around - reportVsync = true; + + if (eventPending && !timestamp && !added) { + // we don't have a vsync event to process + // (timestamp==0), but we have some pending + // messages. + signalConnections.add(connection); } - connection->count--; - } - if (reportVsync) { - displayEventConnections.add(connection); + } else { + // we couldn't promote this reference, the connection has + // died, so clean-up! + mDisplayEventConnections.removeAt(i); + --i; --count; } } - } while (!displayEventConnections.size()); - // dispatch vsync events to listeners... - vsync.header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC; - vsync.header.timestamp = timestamp; - vsync.vsync.count = mDeliveredEvents; + // Here we figure out if we need to enable or disable vsyncs + if (timestamp && !waitForVSync) { + // we received a VSYNC but we have no clients + // don't report it, and disable VSYNC events + disableVSyncLocked(); + } else if (!timestamp && waitForVSync) { + // we have at least one client, so we want vsync enabled + // (TODO: this function is called right after we finish + // notifying clients of a vsync, so this call will be made + // at the vsync rate, e.g. 60fps. If we can accurately + // track the current state we could avoid making this call + // so often.) + enableVSyncLocked(); + } - const size_t count = displayEventConnections.size(); - for (size_t i=0 ; i<count ; i++) { - sp<Connection> conn(displayEventConnections[i].promote()); - // make sure the connection didn't die - if (conn != NULL) { - status_t err = conn->postEvent(vsync); - if (err == -EAGAIN || err == -EWOULDBLOCK) { - // The destination doesn't accept events anymore, it's probably - // full. For now, we just drop the events on the floor. - // Note that some events cannot be dropped and would have to be - // re-sent later. Right-now we don't have the ability to do - // this, but it doesn't matter for VSYNC. - } else if (err < 0) { - // handle any other error on the pipe as fatal. the only - // reasonable thing to do is to clean-up this connection. - // The most common error we'll get here is -EPIPE. - removeDisplayEventConnection(displayEventConnections[i]); + // note: !timestamp implies signalConnections.isEmpty(), because we + // don't populate signalConnections if there's no vsync pending + if (!timestamp && !eventPending) { + // wait for something to happen + if (waitForVSync) { + // This is where we spend most of our time, waiting + // for vsync events and new client registrations. + // + // If the screen is off, we can't use h/w vsync, so we + // use a 16ms timeout instead. It doesn't need to be + // precise, we just need to keep feeding our clients. + // + // We don't want to stall if there's a driver bug, so we + // use a (long) timeout when waiting for h/w vsync, and + // generate fake events when necessary. + bool softwareSync = mUseSoftwareVSync; + nsecs_t timeout = softwareSync ? ms2ns(16) : ms2ns(1000); + if (mCondition.waitRelative(mLock, timeout) == TIMED_OUT) { + if (!softwareSync) { + ALOGW("Timed out waiting for hw vsync; faking it"); + } + // FIXME: how do we decide which display id the fake + // vsync came from ? + mVSyncEvent[0].header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC; + mVSyncEvent[0].header.id = HWC_DISPLAY_PRIMARY; + mVSyncEvent[0].header.timestamp = systemTime(SYSTEM_TIME_MONOTONIC); + mVSyncEvent[0].vsync.count++; + } + } else { + // Nobody is interested in vsync, so we just want to sleep. + // h/w vsync should be disabled, so this will wait until we + // get a new connection, or an existing connection becomes + // interested in receiving vsync again. + mCondition.wait(mLock); } - } else { - // somehow the connection is dead, but we still have it in our list - // just clean the list. - removeDisplayEventConnection(displayEventConnections[i]); } - } + } while (signalConnections.isEmpty()); - // clear all our references without holding mLock - displayEventConnections.clear(); - - return true; + // here we're guaranteed to have a timestamp and some connections to signal + // (The connections might have dropped out of mDisplayEventConnections + // while we were asleep, but we'll still have strong references to them.) + return signalConnections; } void EventThread::enableVSyncLocked() { if (!mUseSoftwareVSync) { // never enable h/w VSYNC when screen is off - mHw.eventControl(DisplayHardware::EVENT_VSYNC, true); + mFlinger->eventControl(HWC_DISPLAY_PRIMARY, SurfaceFlinger::EVENT_VSYNC, true); + mPowerHAL.vsyncHint(true); } mDebugVsyncEnabled = true; } void EventThread::disableVSyncLocked() { - mHw.eventControl(DisplayHardware::EVENT_VSYNC, false); + mFlinger->eventControl(HWC_DISPLAY_PRIMARY, SurfaceFlinger::EVENT_VSYNC, false); + mPowerHAL.vsyncHint(false); mDebugVsyncEnabled = false; } -status_t EventThread::readyToRun() { - ALOGI("EventThread ready to run."); - return NO_ERROR; -} - void EventThread::dump(String8& result, char* buffer, size_t SIZE) const { Mutex::Autolock _l(mLock); result.appendFormat("VSYNC state: %s\n", @@ -276,7 +327,8 @@ void EventThread::dump(String8& result, char* buffer, size_t SIZE) const { result.appendFormat(" soft-vsync: %s\n", mUseSoftwareVSync?"enabled":"disabled"); result.appendFormat(" numListeners=%u,\n events-delivered: %u\n", - mDisplayEventConnections.size(), mDeliveredEvents); + mDisplayEventConnections.size(), + mVSyncEvent[HWC_DISPLAY_PRIMARY].vsync.count); for (size_t i=0 ; i<mDisplayEventConnections.size() ; i++) { sp<Connection> connection = mDisplayEventConnections.itemAt(i).promote(); @@ -294,7 +346,8 @@ EventThread::Connection::Connection( } EventThread::Connection::~Connection() { - mEventThread->unregisterDisplayEventConnection(this); + // do nothing here -- clean-up will happen automatically + // when the main thread wakes up } void EventThread::Connection::onFirstRef() { diff --git a/services/surfaceflinger/EventThread.h b/services/surfaceflinger/EventThread.h index b42cab6..1934f98 100644 --- a/services/surfaceflinger/EventThread.h +++ b/services/surfaceflinger/EventThread.h @@ -23,23 +23,24 @@ #include <gui/DisplayEventReceiver.h> #include <gui/IDisplayEventConnection.h> +#include <hardware/hwcomposer_defs.h> + #include <utils/Errors.h> #include <utils/threads.h> #include <utils/SortedVector.h> -#include "DisplayHardware/DisplayHardware.h" +#include "DisplayHardware/PowerHAL.h" // --------------------------------------------------------------------------- - namespace android { - // --------------------------------------------------------------------------- class SurfaceFlinger; +class String8; // --------------------------------------------------------------------------- -class EventThread : public Thread, public DisplayHardware::VSyncHandler { +class EventThread : public Thread { class Connection : public BnDisplayEventConnection { public: Connection(const sp<EventThread>& eventThread); @@ -48,7 +49,6 @@ class EventThread : public Thread, public DisplayHardware::VSyncHandler { // count >= 1 : continuous event. count is the vsync rate // count == 0 : one-shot event that has not fired // count ==-1 : one-shot event that fired this round / disabled - // count ==-2 : one-shot event that fired the round before int32_t count; private: @@ -67,7 +67,6 @@ public: sp<Connection> createEventConnection() const; status_t registerDisplayEventConnection(const sp<Connection>& connection); - status_t unregisterDisplayEventConnection(const wp<Connection>& connection); void setVsyncRate(uint32_t count, const sp<Connection>& connection); void requestNextVsync(const sp<Connection>& connection); @@ -78,13 +77,18 @@ public: // called after the screen is turned on from main thread void onScreenAcquired(); + // called when receiving a vsync event + void onVSyncReceived(int type, nsecs_t timestamp); + void onHotplugReceived(int type, bool connected); + + Vector< sp<EventThread::Connection> > waitForEvent( + DisplayEventReceiver::Event* event); + void dump(String8& result, char* buffer, size_t SIZE) const; private: virtual bool threadLoop(); - virtual status_t readyToRun(); virtual void onFirstRef(); - virtual void onVSyncReceived(int, nsecs_t timestamp); void removeDisplayEventConnection(const wp<Connection>& connection); void enableVSyncLocked(); @@ -92,20 +96,17 @@ private: // constants sp<SurfaceFlinger> mFlinger; - DisplayHardware& mHw; + PowerHAL mPowerHAL; mutable Mutex mLock; mutable Condition mCondition; // protected by mLock SortedVector< wp<Connection> > mDisplayEventConnections; - nsecs_t mLastVSyncTimestamp; - nsecs_t mVSyncTimestamp; + Vector< DisplayEventReceiver::Event > mPendingEvents; + DisplayEventReceiver::Event mVSyncEvent[HWC_DISPLAY_TYPES_SUPPORTED]; bool mUseSoftwareVSync; - // main thread only - size_t mDeliveredEvents; - // for debugging bool mDebugVsyncEnabled; }; diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 4062340..7edbdc5 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -36,22 +36,22 @@ #include <gui/Surface.h> #include "clz.h" -#include "DisplayHardware/DisplayHardware.h" -#include "DisplayHardware/HWComposer.h" +#include "DisplayDevice.h" #include "GLExtensions.h" #include "Layer.h" #include "SurfaceFlinger.h" #include "SurfaceTextureLayer.h" +#include "DisplayHardware/HWComposer.h" + #define DEBUG_RESIZE 0 namespace android { // --------------------------------------------------------------------------- -Layer::Layer(SurfaceFlinger* flinger, - DisplayID display, const sp<Client>& client) - : LayerBaseClient(flinger, display, client), +Layer::Layer(SurfaceFlinger* flinger, const sp<Client>& client) + : LayerBaseClient(flinger, client), mTextureName(-1U), mQueuedFrames(0), mCurrentTransform(0), @@ -63,7 +63,6 @@ Layer::Layer(SurfaceFlinger* flinger, mFormat(PIXEL_FORMAT_NONE), mGLExtensions(GLExtensions::getInstance()), mOpaqueLayer(true), - mNeedsDithering(false), mSecure(false), mProtectedByApp(false) { @@ -71,14 +70,11 @@ Layer::Layer(SurfaceFlinger* flinger, glGenTextures(1, &mTextureName); } -void Layer::onLayerDisplayed() { - if (mFrameLatencyNeeded) { - const DisplayHardware& hw(graphicPlane(0).displayHardware()); - mFrameStats[mFrameLatencyOffset].timestamp = mSurfaceTexture->getTimestamp(); - mFrameStats[mFrameLatencyOffset].set = systemTime(); - mFrameStats[mFrameLatencyOffset].vsync = hw.getRefreshTimestamp(); - mFrameLatencyOffset = (mFrameLatencyOffset + 1) % 128; - mFrameLatencyNeeded = false; +void Layer::onLayerDisplayed(const sp<const DisplayDevice>& hw, + HWComposer::HWCLayerInterface* layer) { + LayerBaseClient::onLayerDisplayed(hw, layer); + if (layer) { + mSurfaceTexture->setReleaseFence(layer->getAndResetReleaseFenceFd()); } } @@ -109,16 +105,18 @@ void Layer::onFirstRef() #ifdef TARGET_DISABLE_TRIPLE_BUFFERING #warning "disabling triple buffering" - mSurfaceTexture->setBufferCountServer(2); + mSurfaceTexture->setDefaultMaxBufferCount(2); #else - mSurfaceTexture->setBufferCountServer(3); + mSurfaceTexture->setDefaultMaxBufferCount(3); #endif + + const sp<const DisplayDevice> hw(mFlinger->getDefaultDisplayDevice()); + updateTransformHint(hw); } Layer::~Layer() { - mFlinger->postMessageAsync( - new SurfaceFlinger::MessageDestroyGLTexture(mTextureName) ); + mFlinger->deleteTextureAsync(mTextureName); } void Layer::onFrameQueued() { @@ -138,14 +136,6 @@ void Layer::setName(const String8& name) { mSurfaceTexture->setName(name); } -void Layer::validateVisibility(const Transform& globalTransform) { - LayerBase::validateVisibility(globalTransform); - - // This optimization allows the SurfaceTexture to bake in - // the rotation so hardware overlays can be used - mSurfaceTexture->setTransformHint(getTransformHint()); -} - sp<ISurface> Layer::createSurface() { class BSurface : public BnSurface, public LayerCleaner { @@ -183,10 +173,8 @@ status_t Layer::setBuffers( uint32_t w, uint32_t h, return err; } - // the display's pixel format - const DisplayHardware& hw(graphicPlane(0).displayHardware()); uint32_t const maxSurfaceDims = min( - hw.getMaxTextureSize(), hw.getMaxViewportDims()); + mFlinger->getMaxTextureSize(), mFlinger->getMaxViewportDims()); // never allow a surface larger than what our underlying GL implementation // can handle. @@ -195,26 +183,17 @@ status_t Layer::setBuffers( uint32_t w, uint32_t h, return BAD_VALUE; } - PixelFormatInfo displayInfo; - getPixelFormatInfo(hw.getFormat(), &displayInfo); - const uint32_t hwFlags = hw.getFlags(); - mFormat = format; - mSecure = (flags & ISurfaceComposer::eSecure) ? true : false; - mProtectedByApp = (flags & ISurfaceComposer::eProtectedByApp) ? true : false; - mOpaqueLayer = (flags & ISurfaceComposer::eOpaque); + mSecure = (flags & ISurfaceComposerClient::eSecure) ? true : false; + mProtectedByApp = (flags & ISurfaceComposerClient::eProtectedByApp) ? true : false; + mOpaqueLayer = (flags & ISurfaceComposerClient::eOpaque); mCurrentOpacity = getOpacityForFormat(format); mSurfaceTexture->setDefaultBufferSize(w, h); mSurfaceTexture->setDefaultBufferFormat(format); mSurfaceTexture->setConsumerUsageBits(getEffectiveUsage(0)); - // we use the red index - int displayRedSize = displayInfo.getSize(PixelFormatInfo::INDEX_RED); - int layerRedsize = info.getSize(PixelFormatInfo::INDEX_RED); - mNeedsDithering = layerRedsize > displayRedSize; - return NO_ERROR; } @@ -226,7 +205,8 @@ Rect Layer::computeBufferCrop() const { } else if (mActiveBuffer != NULL){ crop = Rect(mActiveBuffer->getWidth(), mActiveBuffer->getHeight()); } else { - crop = Rect(mTransformedBounds.width(), mTransformedBounds.height()); + crop.makeInvalid(); + return crop; } // ... then reduce that in the same proportions as the window crop reduces @@ -259,16 +239,23 @@ Rect Layer::computeBufferCrop() const { return crop; } -void Layer::setGeometry(hwc_layer_t* hwcl) +void Layer::setGeometry( + const sp<const DisplayDevice>& hw, + HWComposer::HWCLayerInterface& layer) { - LayerBaseClient::setGeometry(hwcl); + LayerBaseClient::setGeometry(hw, layer); - hwcl->flags &= ~HWC_SKIP_LAYER; + // enable this layer + layer.setSkip(false); // we can't do alpha-fade with the hwc HAL const State& s(drawingState()); if (s.alpha < 0xFF) { - hwcl->flags = HWC_SKIP_LAYER; + layer.setSkip(true); + } + + if (isSecure() && !hw->isSecure()) { + layer.setSkip(true); } /* @@ -276,44 +263,52 @@ void Layer::setGeometry(hwc_layer_t* hwcl) * 1) buffer orientation/flip/mirror * 2) state transformation (window manager) * 3) layer orientation (screen orientation) - * mTransform is already the composition of (2) and (3) * (NOTE: the matrices are multiplied in reverse order) */ const Transform bufferOrientation(mCurrentTransform); - const Transform tr(mTransform * bufferOrientation); + const Transform tr(hw->getTransform() * s.transform * bufferOrientation); // this gives us only the "orientation" component of the transform const uint32_t finalTransform = tr.getOrientation(); // we can only handle simple transformation if (finalTransform & Transform::ROT_INVALID) { - hwcl->flags = HWC_SKIP_LAYER; + layer.setSkip(true); } else { - hwcl->transform = finalTransform; + layer.setTransform(finalTransform); } + layer.setCrop(computeBufferCrop()); +} - Rect crop = computeBufferCrop(); - hwcl->sourceCrop.left = crop.left; - hwcl->sourceCrop.top = crop.top; - hwcl->sourceCrop.right = crop.right; - hwcl->sourceCrop.bottom = crop.bottom; +void Layer::setPerFrameData(const sp<const DisplayDevice>& hw, + HWComposer::HWCLayerInterface& layer) { + LayerBaseClient::setPerFrameData(hw, layer); + // NOTE: buffer can be NULL if the client never drew into this + // layer yet, or if we ran out of memory + layer.setBuffer(mActiveBuffer); } -void Layer::setPerFrameData(hwc_layer_t* hwcl) { - const sp<GraphicBuffer>& buffer(mActiveBuffer); - if (buffer == NULL) { - // this can happen if the client never drew into this layer yet, - // or if we ran out of memory. In that case, don't let - // HWC handle it. - hwcl->flags |= HWC_SKIP_LAYER; - hwcl->handle = NULL; - } else { - hwcl->handle = buffer->handle; +void Layer::setAcquireFence(const sp<const DisplayDevice>& hw, + HWComposer::HWCLayerInterface& layer) { + int fenceFd = -1; + + // TODO: there is a possible optimization here: we only need to set the + // acquire fence the first time a new buffer is acquired on EACH display. + + if (layer.getCompositionType() == HWC_OVERLAY) { + sp<Fence> fence = mSurfaceTexture->getCurrentFence(); + if (fence.get()) { + fenceFd = fence->dup(); + if (fenceFd == -1) { + ALOGW("failed to dup layer fence, skipping sync: %d", errno); + } + } } + layer.setAcquireFenceFd(fenceFd); } -void Layer::onDraw(const Region& clip) const +void Layer::onDraw(const sp<const DisplayDevice>& hw, const Region& clip) const { ATRACE_CALL(); @@ -335,19 +330,28 @@ void Layer::onDraw(const Region& clip) const const sp<LayerBase>& layer(drawingLayers[i]); if (layer.get() == static_cast<LayerBase const*>(this)) break; - under.orSelf(layer->visibleRegionScreen); + under.orSelf( hw->getTransform().transform(layer->visibleRegion) ); } // if not everything below us is covered, we plug the holes! Region holes(clip.subtract(under)); if (!holes.isEmpty()) { - clearWithOpenGL(holes, 0, 0, 0, 1); + clearWithOpenGL(hw, holes, 0, 0, 0, 1); } return; } - if (!isProtected()) { + status_t err = mSurfaceTexture->doGLFenceWait(); + if (err != OK) { + ALOGE("onDraw: failed waiting for fence: %d", err); + // Go ahead and draw the buffer anyway; no matter what we do the screen + // is probably going to have something visibly wrong. + } + + bool blackOutLayer = isProtected() || (isSecure() && !hw->isSecure()); + + if (!blackOutLayer) { // TODO: we could be more subtle with isFixedSize() - const bool useFiltering = getFiltering() || needsFiltering() || isFixedSize(); + const bool useFiltering = getFiltering() || needsFiltering(hw) || isFixedSize(); // Query the texture matrix given our current filtering mode. float textureMatrix[16]; @@ -376,7 +380,7 @@ void Layer::onDraw(const Region& clip) const glEnable(GL_TEXTURE_2D); } - drawWithOpenGL(clip); + drawWithOpenGL(hw, clip); glDisable(GL_TEXTURE_EXTERNAL_OES); glDisable(GL_TEXTURE_2D); @@ -434,12 +438,12 @@ uint32_t Layer::doTransaction(uint32_t flags) if (sizeChanged) { // the size changed, we need to ask our client to request a new buffer ALOGD_IF(DEBUG_RESIZE, - "doTransaction: geometry (layer=%p), scalingMode=%d\n" + "doTransaction: geometry (layer=%p '%s'), tr=%02x, scalingMode=%d\n" " current={ active ={ wh={%4u,%4u} crop={%4d,%4d,%4d,%4d} (%4d,%4d) }\n" " requested={ wh={%4u,%4u} crop={%4d,%4d,%4d,%4d} (%4d,%4d) }}\n" " drawing={ active ={ wh={%4u,%4u} crop={%4d,%4d,%4d,%4d} (%4d,%4d) }\n" " requested={ wh={%4u,%4u} crop={%4d,%4d,%4d,%4d} (%4d,%4d) }}\n", - this, mCurrentScalingMode, + this, (const char*) getName(), mCurrentTransform, mCurrentScalingMode, temp.active.w, temp.active.h, temp.active.crop.left, temp.active.crop.top, @@ -514,10 +518,27 @@ bool Layer::onPreComposition() { return mQueuedFrames > 0; } -void Layer::lockPageFlip(bool& recomputeVisibleRegions) +void Layer::onPostComposition() { + if (mFrameLatencyNeeded) { + const HWComposer& hwc = mFlinger->getHwComposer(); + const size_t offset = mFrameLatencyOffset; + mFrameStats[offset].timestamp = mSurfaceTexture->getTimestamp(); + mFrameStats[offset].set = systemTime(); + mFrameStats[offset].vsync = hwc.getRefreshTimestamp(HWC_DISPLAY_PRIMARY); + mFrameLatencyOffset = (mFrameLatencyOffset + 1) % 128; + mFrameLatencyNeeded = false; + } +} + +bool Layer::isVisible() const { + return LayerBaseClient::isVisible() && (mActiveBuffer != NULL); +} + +Region Layer::latchBuffer(bool& recomputeVisibleRegions) { ATRACE_CALL(); + Region outDirtyRegion; if (mQueuedFrames > 0) { // if we've already called updateTexImage() without going through @@ -526,8 +547,7 @@ void Layer::lockPageFlip(bool& recomputeVisibleRegions) // compositionComplete() call. // we'll trigger an update in onPreComposition(). if (mRefreshPending) { - mPostedDirtyRegion.clear(); - return; + return outDirtyRegion; } // Capture the old state of the layer for comparisons later @@ -590,10 +610,10 @@ void Layer::lockPageFlip(bool& recomputeVisibleRegions) } ALOGD_IF(DEBUG_RESIZE, - "lockPageFlip: (layer=%p), buffer (%ux%u, tr=%02x), scalingMode=%d\n" + "latchBuffer/reject: buffer (%ux%u, tr=%02x), scalingMode=%d\n" " drawing={ active ={ wh={%4u,%4u} crop={%4d,%4d,%4d,%4d} (%4d,%4d) }\n" " requested={ wh={%4u,%4u} crop={%4d,%4d,%4d,%4d} (%4d,%4d) }}\n", - this, bufWidth, bufHeight, item.mTransform, item.mScalingMode, + bufWidth, bufHeight, item.mTransform, item.mScalingMode, front.active.w, front.active.h, front.active.crop.left, front.active.crop.top, @@ -624,17 +644,17 @@ void Layer::lockPageFlip(bool& recomputeVisibleRegions) Reject r(mDrawingState, currentState(), recomputeVisibleRegions); - if (mSurfaceTexture->updateTexImage(&r) < NO_ERROR) { + if (mSurfaceTexture->updateTexImage(&r, true) < NO_ERROR) { // something happened! recomputeVisibleRegions = true; - return; + return outDirtyRegion; } // update the active buffer mActiveBuffer = mSurfaceTexture->getCurrentBuffer(); if (mActiveBuffer == NULL) { // this can only happen if the very first buffer was rejected. - return; + return outDirtyRegion; } mRefreshPending = true; @@ -642,7 +662,7 @@ void Layer::lockPageFlip(bool& recomputeVisibleRegions) if (oldActiveBuffer == NULL) { // the first time we receive a buffer, we need to trigger a // geometry invalidation. - mFlinger->invalidateHwcGeometry(); + recomputeVisibleRegions = true; } Rect crop(mSurfaceTexture->getCurrentCrop()); @@ -655,7 +675,7 @@ void Layer::lockPageFlip(bool& recomputeVisibleRegions) mCurrentCrop = crop; mCurrentTransform = transform; mCurrentScalingMode = scalingMode; - mFlinger->invalidateHwcGeometry(); + recomputeVisibleRegions = true; } if (oldActiveBuffer != NULL) { @@ -663,7 +683,7 @@ void Layer::lockPageFlip(bool& recomputeVisibleRegions) uint32_t bufHeight = mActiveBuffer->getHeight(); if (bufWidth != uint32_t(oldActiveBuffer->width) || bufHeight != uint32_t(oldActiveBuffer->height)) { - mFlinger->invalidateHwcGeometry(); + recomputeVisibleRegions = true; } } @@ -672,38 +692,17 @@ void Layer::lockPageFlip(bool& recomputeVisibleRegions) recomputeVisibleRegions = true; } - // FIXME: mPostedDirtyRegion = dirty & bounds - const Layer::State& front(drawingState()); - mPostedDirtyRegion.set(front.active.w, front.active.h); - glTexParameterx(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameterx(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - } -} -void Layer::unlockPageFlip( - const Transform& planeTransform, Region& outDirtyRegion) -{ - ATRACE_CALL(); + // FIXME: postedRegion should be dirty & bounds + const Layer::State& front(drawingState()); + Region dirtyRegion(Rect(front.active.w, front.active.h)); - Region postedRegion(mPostedDirtyRegion); - if (!postedRegion.isEmpty()) { - mPostedDirtyRegion.clear(); - if (!visibleRegionScreen.isEmpty()) { - // The dirty region is given in the layer's coordinate space - // transform the dirty region by the surface's transformation - // and the global transformation. - const Layer::State& s(drawingState()); - const Transform tr(planeTransform * s.transform); - postedRegion = tr.transform(postedRegion); - - // At this point, the dirty region is in screen space. - // Make sure it's constrained by the visible region (which - // is in screen space as well). - postedRegion.andSelf(visibleRegionScreen); - outDirtyRegion.orSelf(postedRegion); - } + // transform the dirty region to window-manager space + outDirtyRegion = (front.transform.transform(dirtyRegion)); } + return outDirtyRegion; } void Layer::dump(String8& result, char* buffer, size_t SIZE) const @@ -721,9 +720,9 @@ void Layer::dump(String8& result, char* buffer, size_t SIZE) const snprintf(buffer, SIZE, " " "format=%2d, activeBuffer=[%4ux%4u:%4u,%3X]," - " transform-hint=0x%02x, queued-frames=%d, mRefreshPending=%d\n", + " queued-frames=%d, mRefreshPending=%d\n", mFormat, w0, h0, s0,f0, - getTransformHint(), mQueuedFrames, mRefreshPending); + mQueuedFrames, mRefreshPending); result.append(buffer); @@ -736,8 +735,8 @@ void Layer::dumpStats(String8& result, char* buffer, size_t SIZE) const { LayerBaseClient::dumpStats(result, buffer, SIZE); const size_t o = mFrameLatencyOffset; - const DisplayHardware& hw(graphicPlane(0).displayHardware()); - const nsecs_t period = hw.getRefreshPeriod(); + const nsecs_t period = + mFlinger->getHwComposer().getRefreshPeriod(HWC_DISPLAY_PRIMARY); result.appendFormat("%lld\n", period); for (size_t i=0 ; i<128 ; i++) { const size_t index = (o+i) % 128; @@ -769,15 +768,19 @@ uint32_t Layer::getEffectiveUsage(uint32_t usage) const return usage; } -uint32_t Layer::getTransformHint() const { +void Layer::updateTransformHint(const sp<const DisplayDevice>& hw) const { uint32_t orientation = 0; if (!mFlinger->mDebugDisableTransformHint) { - orientation = getPlaneOrientation(); + // The transform hint is used to improve performance, but we can + // only have a single transform hint, it cannot + // apply to all displays. + const Transform& planeTransform(hw->getTransform()); + orientation = planeTransform.getOrientation(); if (orientation & Transform::ROT_INVALID) { orientation = 0; } } - return orientation; + mSurfaceTexture->setTransformHint(orientation); } // --------------------------------------------------------------------------- diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 393599f..c5eb26b 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -50,9 +50,7 @@ class GLExtensions; class Layer : public LayerBaseClient { public: - Layer(SurfaceFlinger* flinger, DisplayID display, - const sp<Client>& client); - + Layer(SurfaceFlinger* flinger, const sp<Client>& client); virtual ~Layer(); virtual const char* getTypeId() const { return "Layer"; } @@ -64,30 +62,38 @@ public: bool isFixedSize() const; // LayerBase interface - virtual void setGeometry(hwc_layer_t* hwcl); - virtual void setPerFrameData(hwc_layer_t* hwcl); - virtual void onDraw(const Region& clip) const; + virtual void setGeometry(const sp<const DisplayDevice>& hw, + HWComposer::HWCLayerInterface& layer); + virtual void setPerFrameData(const sp<const DisplayDevice>& hw, + HWComposer::HWCLayerInterface& layer); + virtual void setAcquireFence(const sp<const DisplayDevice>& hw, + HWComposer::HWCLayerInterface& layer); + virtual void onLayerDisplayed(const sp<const DisplayDevice>& hw, + HWComposer::HWCLayerInterface* layer); + virtual bool onPreComposition(); + virtual void onPostComposition(); + + virtual void onDraw(const sp<const DisplayDevice>& hw, const Region& clip) const; virtual uint32_t doTransaction(uint32_t transactionFlags); - virtual void lockPageFlip(bool& recomputeVisibleRegions); - virtual void unlockPageFlip(const Transform& planeTransform, Region& outDirtyRegion); + virtual Region latchBuffer(bool& recomputeVisibleRegions); virtual bool isOpaque() const; - virtual bool needsDithering() const { return mNeedsDithering; } virtual bool isSecure() const { return mSecure; } virtual bool isProtected() const; virtual void onRemoved(); virtual sp<Layer> getLayer() const { return const_cast<Layer*>(this); } virtual void setName(const String8& name); - virtual void validateVisibility(const Transform& globalTransform); + virtual bool isVisible() const; // LayerBaseClient interface virtual wp<IBinder> getSurfaceTextureBinder() const; - virtual void onLayerDisplayed(); - virtual bool onPreComposition(); - // only for debugging inline const sp<GraphicBuffer>& getActiveBuffer() const { return mActiveBuffer; } + // Updates the transform hint in our SurfaceTexture to match + // the current orientation of the display device. + virtual void updateTransformHint(const sp<const DisplayDevice>& hw) const; + protected: virtual void onFirstRef(); virtual void dump(String8& result, char* scratch, size_t size) const; @@ -99,7 +105,6 @@ private: void onFrameQueued(); virtual sp<ISurface> createSurface(); uint32_t getEffectiveUsage(uint32_t usage) const; - uint32_t getTransformHint() const; bool isCropped() const; Rect computeBufferCrop() const; static bool getOpacityForFormat(uint32_t format); @@ -137,12 +142,10 @@ private: PixelFormat mFormat; const GLExtensions& mGLExtensions; bool mOpaqueLayer; - bool mNeedsDithering; // page-flip thread (currently main thread) bool mSecure; // no screenshots bool mProtectedByApp; // application requires protected path to external sink - Region mPostedDirtyRegion; }; // --------------------------------------------------------------------------- diff --git a/services/surfaceflinger/LayerBase.cpp b/services/surfaceflinger/LayerBase.cpp index 16bac8f..9b03c74 100644 --- a/services/surfaceflinger/LayerBase.cpp +++ b/services/surfaceflinger/LayerBase.cpp @@ -29,9 +29,11 @@ #include <hardware/hardware.h> #include "clz.h" +#include "Client.h" #include "LayerBase.h" +#include "Layer.h" #include "SurfaceFlinger.h" -#include "DisplayHardware/DisplayHardware.h" +#include "DisplayDevice.h" namespace android { @@ -39,18 +41,14 @@ namespace android { int32_t LayerBase::sSequence = 1; -LayerBase::LayerBase(SurfaceFlinger* flinger, DisplayID display) - : dpy(display), contentDirty(false), +LayerBase::LayerBase(SurfaceFlinger* flinger) + : contentDirty(false), sequence(uint32_t(android_atomic_inc(&sSequence))), mFlinger(flinger), mFiltering(false), mNeedsFiltering(false), - mOrientation(0), - mPlaneOrientation(0), mTransactionFlags(0), mPremultipliedAlpha(true), mName("unnamed"), mDebug(false) { - const DisplayHardware& hw(flinger->graphicPlane(0).displayHardware()); - mFlags = hw.getFlags(); } LayerBase::~LayerBase() @@ -65,23 +63,13 @@ String8 LayerBase::getName() const { return mName; } -const GraphicPlane& LayerBase::graphicPlane(int dpy) const -{ - return mFlinger->graphicPlane(dpy); -} - -GraphicPlane& LayerBase::graphicPlane(int dpy) -{ - return mFlinger->graphicPlane(dpy); -} - void LayerBase::initStates(uint32_t w, uint32_t h, uint32_t flags) { uint32_t layerFlags = 0; - if (flags & ISurfaceComposer::eHidden) - layerFlags = ISurfaceComposer::eLayerHidden; + if (flags & ISurfaceComposerClient::eHidden) + layerFlags = layer_state_t::eLayerHidden; - if (flags & ISurfaceComposer::eNonPremultiplied) + if (flags & ISurfaceComposerClient::eNonPremultiplied) mPremultipliedAlpha = false; mCurrentState.active.w = w; @@ -89,6 +77,7 @@ void LayerBase::initStates(uint32_t w, uint32_t h, uint32_t flags) mCurrentState.active.crop.makeInvalid(); mCurrentState.z = 0; mCurrentState.alpha = 0xFF; + mCurrentState.layerStack = 0; mCurrentState.flags = layerFlags; mCurrentState.sequence = 0; mCurrentState.transform.set(0, 0); @@ -98,6 +87,10 @@ void LayerBase::initStates(uint32_t w, uint32_t h, uint32_t flags) mDrawingState = mCurrentState; } +bool LayerBase::needsFiltering(const sp<const DisplayDevice>& hw) const { + return mNeedsFiltering || hw->needsFiltering(); +} + void LayerBase::commitTransaction() { mDrawingState = mCurrentState; } @@ -181,19 +174,29 @@ bool LayerBase::setCrop(const Rect& crop) { return true; } -Rect LayerBase::visibleBounds() const -{ - return mTransformedBounds; -} +bool LayerBase::setLayerStack(uint32_t layerStack) { + if (mCurrentState.layerStack == layerStack) + return false; + mCurrentState.sequence++; + mCurrentState.layerStack = layerStack; + requestTransaction(); + return true; +} void LayerBase::setVisibleRegion(const Region& visibleRegion) { // always called from main thread - visibleRegionScreen = visibleRegion; + this->visibleRegion = visibleRegion; } void LayerBase::setCoveredRegion(const Region& coveredRegion) { // always called from main thread - coveredRegionScreen = coveredRegion; + this->coveredRegion = coveredRegion; +} + +void LayerBase::setVisibleNonTransparentRegion(const Region& + setVisibleNonTransparentRegion) { + // always called from main thread + this->visibleNonTransparentRegion = setVisibleNonTransparentRegion; } uint32_t LayerBase::doTransaction(uint32_t flags) @@ -230,99 +233,91 @@ uint32_t LayerBase::doTransaction(uint32_t flags) return flags; } -void LayerBase::validateVisibility(const Transform& planeTransform) +void LayerBase::computeGeometry(const sp<const DisplayDevice>& hw, LayerMesh* mesh) const { const Layer::State& s(drawingState()); - const Transform tr(planeTransform * s.transform); - const bool transformed = tr.transformed(); - const DisplayHardware& hw(graphicPlane(0).displayHardware()); - const uint32_t hw_h = hw.getHeight(); - const Rect& crop(s.active.crop); - + const Transform tr(hw->getTransform() * s.transform); + const uint32_t hw_h = hw->getHeight(); Rect win(s.active.w, s.active.h); - if (!crop.isEmpty()) { - win.intersect(crop, &win); + if (!s.active.crop.isEmpty()) { + win.intersect(s.active.crop, &win); } - - mNumVertices = 4; - tr.transform(mVertices[0], win.left, win.top); - tr.transform(mVertices[1], win.left, win.bottom); - tr.transform(mVertices[2], win.right, win.bottom); - tr.transform(mVertices[3], win.right, win.top); - for (size_t i=0 ; i<4 ; i++) - mVertices[i][1] = hw_h - mVertices[i][1]; - - if (CC_UNLIKELY(transformed)) { - // NOTE: here we could also punt if we have too many rectangles - // in the transparent region - if (tr.preserveRects()) { - // transform the transparent region - transparentRegionScreen = tr.transform(s.transparentRegion); - } else { - // transformation too complex, can't do the transparent region - // optimization. - transparentRegionScreen.clear(); + if (mesh) { + tr.transform(mesh->mVertices[0], win.left, win.top); + tr.transform(mesh->mVertices[1], win.left, win.bottom); + tr.transform(mesh->mVertices[2], win.right, win.bottom); + tr.transform(mesh->mVertices[3], win.right, win.top); + for (size_t i=0 ; i<4 ; i++) { + mesh->mVertices[i][1] = hw_h - mesh->mVertices[i][1]; } - } else { - transparentRegionScreen = s.transparentRegion; } - - // cache a few things... - mOrientation = tr.getOrientation(); - mPlaneOrientation = planeTransform.getOrientation(); - mTransform = tr; - mTransformedBounds = tr.transform(win); } -void LayerBase::lockPageFlip(bool& recomputeVisibleRegions) { +Rect LayerBase::computeBounds() const { + const Layer::State& s(drawingState()); + Rect win(s.active.w, s.active.h); + if (!s.active.crop.isEmpty()) { + win.intersect(s.active.crop, &win); + } + return s.transform.transform(win); } -void LayerBase::unlockPageFlip( - const Transform& planeTransform, Region& outDirtyRegion) { +Region LayerBase::latchBuffer(bool& recomputeVisibleRegions) { + Region result; + return result; } -void LayerBase::setGeometry(hwc_layer_t* hwcl) +void LayerBase::setGeometry( + const sp<const DisplayDevice>& hw, + HWComposer::HWCLayerInterface& layer) { - hwcl->compositionType = HWC_FRAMEBUFFER; - hwcl->hints = 0; - hwcl->flags = HWC_SKIP_LAYER; - hwcl->transform = 0; - hwcl->blending = HWC_BLENDING_NONE; + layer.setDefaultState(); // this gives us only the "orientation" component of the transform const State& s(drawingState()); const uint32_t finalTransform = s.transform.getOrientation(); // we can only handle simple transformation if (finalTransform & Transform::ROT_INVALID) { - hwcl->flags = HWC_SKIP_LAYER; + layer.setTransform(0); } else { - hwcl->transform = finalTransform; + layer.setTransform(finalTransform); } if (!isOpaque()) { - hwcl->blending = mPremultipliedAlpha ? - HWC_BLENDING_PREMULT : HWC_BLENDING_COVERAGE; + layer.setBlending(mPremultipliedAlpha ? + HWC_BLENDING_PREMULT : + HWC_BLENDING_COVERAGE); } - // scaling is already applied in mTransformedBounds - hwcl->displayFrame.left = mTransformedBounds.left; - hwcl->displayFrame.top = mTransformedBounds.top; - hwcl->displayFrame.right = mTransformedBounds.right; - hwcl->displayFrame.bottom = mTransformedBounds.bottom; - hwcl->visibleRegionScreen.rects = - reinterpret_cast<hwc_rect_t const *>( - visibleRegionScreen.getArray( - &hwcl->visibleRegionScreen.numRects)); + const Transform& tr = hw->getTransform(); + Rect transformedBounds(computeBounds()); + transformedBounds = tr.transform(transformedBounds); + + // scaling is already applied in transformedBounds + layer.setFrame(transformedBounds); + layer.setCrop(transformedBounds.getBounds()); +} - hwcl->sourceCrop.left = 0; - hwcl->sourceCrop.top = 0; - hwcl->sourceCrop.right = mTransformedBounds.width(); - hwcl->sourceCrop.bottom = mTransformedBounds.height(); +void LayerBase::setPerFrameData(const sp<const DisplayDevice>& hw, + HWComposer::HWCLayerInterface& layer) { + layer.setPerFrameDefaultState(); + // we have to set the visible region on every frame because + // we currently free it during onLayerDisplayed(), which is called + // after HWComposer::commit() -- every frame. + const Transform& tr = hw->getTransform(); + layer.setVisibleRegionScreen(tr.transform(visibleRegion)); } -void LayerBase::setPerFrameData(hwc_layer_t* hwcl) { - hwcl->compositionType = HWC_FRAMEBUFFER; - hwcl->handle = NULL; +void LayerBase::setAcquireFence(const sp<const DisplayDevice>& hw, + HWComposer::HWCLayerInterface& layer) { + layer.setAcquireFenceFd(-1); +} + +void LayerBase::onLayerDisplayed(const sp<const DisplayDevice>& hw, + HWComposer::HWCLayerInterface* layer) { + if (layer) { + layer->onDisplayed(); + } } void LayerBase::setFiltering(bool filtering) @@ -335,44 +330,46 @@ bool LayerBase::getFiltering() const return mFiltering; } -void LayerBase::draw(const Region& clip) const +bool LayerBase::isVisible() const { + const Layer::State& s(mDrawingState); + return !(s.flags & layer_state_t::eLayerHidden) && s.alpha; +} + +void LayerBase::draw(const sp<const DisplayDevice>& hw, const Region& clip) const { - onDraw(clip); + onDraw(hw, clip); } -void LayerBase::drawForSreenShot() +void LayerBase::draw(const sp<const DisplayDevice>& hw) { - const DisplayHardware& hw(graphicPlane(0).displayHardware()); - setFiltering(true); - onDraw( Region(hw.bounds()) ); - setFiltering(false); + onDraw( hw, Region(hw->bounds()) ); } -void LayerBase::clearWithOpenGL(const Region& clip, GLclampf red, - GLclampf green, GLclampf blue, - GLclampf alpha) const +void LayerBase::clearWithOpenGL(const sp<const DisplayDevice>& hw, const Region& clip, + GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) const { - const DisplayHardware& hw(graphicPlane(0).displayHardware()); - const uint32_t fbHeight = hw.getHeight(); + const uint32_t fbHeight = hw->getHeight(); glColor4f(red,green,blue,alpha); glDisable(GL_TEXTURE_EXTERNAL_OES); glDisable(GL_TEXTURE_2D); glDisable(GL_BLEND); - glVertexPointer(2, GL_FLOAT, 0, mVertices); - glDrawArrays(GL_TRIANGLE_FAN, 0, mNumVertices); + LayerMesh mesh; + computeGeometry(hw, &mesh); + + glVertexPointer(2, GL_FLOAT, 0, mesh.getVertices()); + glDrawArrays(GL_TRIANGLE_FAN, 0, mesh.getVertexCount()); } -void LayerBase::clearWithOpenGL(const Region& clip) const +void LayerBase::clearWithOpenGL(const sp<const DisplayDevice>& hw, const Region& clip) const { - clearWithOpenGL(clip,0,0,0,0); + clearWithOpenGL(hw, clip, 0,0,0,0); } -void LayerBase::drawWithOpenGL(const Region& clip) const +void LayerBase::drawWithOpenGL(const sp<const DisplayDevice>& hw, const Region& clip) const { - const DisplayHardware& hw(graphicPlane(0).displayHardware()); - const uint32_t fbHeight = hw.getHeight(); + const uint32_t fbHeight = hw->getHeight(); const State& s(drawingState()); GLenum src = mPremultipliedAlpha ? GL_ONE : GL_SRC_ALPHA; @@ -397,19 +394,26 @@ void LayerBase::drawWithOpenGL(const Region& clip) const } } + LayerMesh mesh; + computeGeometry(hw, &mesh); + + // TODO: we probably want to generate the texture coords with the mesh + // here we assume that we only have 4 vertices + struct TexCoords { GLfloat u; GLfloat v; }; - Rect crop(s.active.w, s.active.h); + Rect win(s.active.w, s.active.h); if (!s.active.crop.isEmpty()) { - crop = s.active.crop; + win.intersect(s.active.crop, &win); } - GLfloat left = GLfloat(crop.left) / GLfloat(s.active.w); - GLfloat top = GLfloat(crop.top) / GLfloat(s.active.h); - GLfloat right = GLfloat(crop.right) / GLfloat(s.active.w); - GLfloat bottom = GLfloat(crop.bottom) / GLfloat(s.active.h); + + GLfloat left = GLfloat(win.left) / GLfloat(s.active.w); + GLfloat top = GLfloat(win.top) / GLfloat(s.active.h); + GLfloat right = GLfloat(win.right) / GLfloat(s.active.w); + GLfloat bottom = GLfloat(win.bottom) / GLfloat(s.active.h); TexCoords texCoords[4]; texCoords[0].u = left; @@ -425,9 +429,9 @@ void LayerBase::drawWithOpenGL(const Region& clip) const } glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glVertexPointer(2, GL_FLOAT, 0, mVertices); glTexCoordPointer(2, GL_FLOAT, 0, texCoords); - glDrawArrays(GL_TRIANGLE_FAN, 0, mNumVertices); + glVertexPointer(2, GL_FLOAT, 0, mesh.getVertices()); + glDrawArrays(GL_TRIANGLE_FAN, 0, mesh.getVertexCount()); glDisableClientState(GL_TEXTURE_COORD_ARRAY); glDisable(GL_BLEND); @@ -443,15 +447,14 @@ void LayerBase::dump(String8& result, char* buffer, size_t SIZE) const result.append(buffer); s.transparentRegion.dump(result, "transparentRegion"); - transparentRegionScreen.dump(result, "transparentRegionScreen"); - visibleRegionScreen.dump(result, "visibleRegionScreen"); + visibleRegion.dump(result, "visibleRegion"); snprintf(buffer, SIZE, " " - "z=%9d, pos=(%g,%g), size=(%4d,%4d), crop=(%4d,%4d,%4d,%4d), " + "layerStack=%4d, z=%9d, pos=(%g,%g), size=(%4d,%4d), crop=(%4d,%4d,%4d,%4d), " "isOpaque=%1d, needsDithering=%1d, invalidate=%1d, " "alpha=0x%02x, flags=0x%08x, tr=[%.2f, %.2f][%.2f, %.2f]\n", - s.z, s.transform.tx(), s.transform.ty(), s.active.w, s.active.h, + s.layerStack, s.z, s.transform.tx(), s.transform.ty(), s.active.w, s.active.h, s.active.crop.left, s.active.crop.top, s.active.crop.right, s.active.crop.bottom, isOpaque(), needsDithering(), contentDirty, @@ -471,13 +474,21 @@ void LayerBase::dumpStats(String8& result, char* scratch, size_t SIZE) const { void LayerBase::clearStats() { } +sp<LayerBaseClient> LayerBase::getLayerBaseClient() const { + return 0; +} + +sp<Layer> LayerBase::getLayer() const { + return 0; +} + // --------------------------------------------------------------------------- int32_t LayerBaseClient::sIdentity = 1; -LayerBaseClient::LayerBaseClient(SurfaceFlinger* flinger, DisplayID display, +LayerBaseClient::LayerBaseClient(SurfaceFlinger* flinger, const sp<Client>& client) - : LayerBase(flinger, display), + : LayerBase(flinger), mHasSurface(false), mClientRef(client), mIdentity(uint32_t(android_atomic_inc(&sIdentity))) @@ -554,7 +565,7 @@ LayerBaseClient::LayerCleaner::LayerCleaner(const sp<SurfaceFlinger>& flinger, LayerBaseClient::LayerCleaner::~LayerCleaner() { // destroy client resources - mFlinger->destroySurface(mLayer); + mFlinger->onLayerDestroyed(mLayer); } // --------------------------------------------------------------------------- diff --git a/services/surfaceflinger/LayerBase.h b/services/surfaceflinger/LayerBase.h index c547a40..4d5a5b0 100644 --- a/services/surfaceflinger/LayerBase.h +++ b/services/surfaceflinger/LayerBase.h @@ -25,6 +25,7 @@ #include <GLES/gl.h> #include <utils/RefBase.h> +#include <utils/String8.h> #include <ui/Region.h> @@ -32,19 +33,16 @@ #include <private/gui/LayerState.h> -#include <hardware/hwcomposer.h> - -#include "DisplayHardware/DisplayHardware.h" #include "Transform.h" +#include "DisplayHardware/HWComposer.h" namespace android { // --------------------------------------------------------------------------- class Client; -class DisplayHardware; +class DisplayDevice; class GraphicBuffer; -class GraphicPlane; class Layer; class LayerBaseClient; class SurfaceFlinger; @@ -56,13 +54,13 @@ class LayerBase : public RefBase static int32_t sSequence; public: - LayerBase(SurfaceFlinger* flinger, DisplayID display); + LayerBase(SurfaceFlinger* flinger); - DisplayID dpy; mutable bool contentDirty; - Region visibleRegionScreen; - Region transparentRegionScreen; - Region coveredRegionScreen; + // regions below are in window-manager space + Region visibleRegion; + Region coveredRegion; + Region visibleNonTransparentRegion; int32_t sequence; struct Geometry { @@ -81,6 +79,7 @@ public: Geometry active; Geometry requested; uint32_t z; + uint32_t layerStack; uint8_t alpha; uint8_t flags; uint8_t reserved[2]; @@ -89,6 +88,20 @@ public: Region transparentRegion; }; + class LayerMesh { + friend class LayerBase; + GLfloat mVertices[4][2]; + size_t mNumVertices; + public: + LayerMesh() : mNumVertices(4) { } + GLfloat const* getVertices() const { + return &mVertices[0][0]; + } + size_t getVertexCount() const { + return mNumVertices; + } + }; + virtual void setName(const String8& name); String8 getName() const; @@ -98,27 +111,33 @@ public: bool setSize(uint32_t w, uint32_t h); bool setAlpha(uint8_t alpha); bool setMatrix(const layer_state_t::matrix22_t& matrix); - bool setTransparentRegionHint(const Region& opaque); + bool setTransparentRegionHint(const Region& transparent); bool setFlags(uint8_t flags, uint8_t mask); bool setCrop(const Rect& crop); - + bool setLayerStack(uint32_t layerStack); + void commitTransaction(); bool requestTransaction(); void forceVisibilityTransaction(); uint32_t getTransactionFlags(uint32_t flags); uint32_t setTransactionFlags(uint32_t flags); - - Rect visibleBounds() const; - virtual sp<LayerBaseClient> getLayerBaseClient() const { return 0; } - virtual sp<Layer> getLayer() const { return 0; } + void computeGeometry(const sp<const DisplayDevice>& hw, LayerMesh* mesh) const; + Rect computeBounds() const; - virtual const char* getTypeId() const { return "LayerBase"; } - virtual void setGeometry(hwc_layer_t* hwcl); - virtual void setPerFrameData(hwc_layer_t* hwcl); + virtual sp<LayerBaseClient> getLayerBaseClient() const; + virtual sp<Layer> getLayer() const; + + virtual const char* getTypeId() const { return "LayerBase"; } + virtual void setGeometry(const sp<const DisplayDevice>& hw, + HWComposer::HWCLayerInterface& layer); + virtual void setPerFrameData(const sp<const DisplayDevice>& hw, + HWComposer::HWCLayerInterface& layer); + virtual void setAcquireFence(const sp<const DisplayDevice>& hw, + HWComposer::HWCLayerInterface& layer); /** * draw - performs some global clipping optimizations @@ -126,13 +145,13 @@ public: * Typically this method is not overridden, instead implement onDraw() * to perform the actual drawing. */ - virtual void draw(const Region& clip) const; - virtual void drawForSreenShot(); + virtual void draw(const sp<const DisplayDevice>& hw, const Region& clip) const; + virtual void draw(const sp<const DisplayDevice>& hw); /** * onDraw - draws the surface. */ - virtual void onDraw(const Region& clip) const = 0; + virtual void onDraw(const sp<const DisplayDevice>& hw, const Region& clip) const = 0; /** * initStates - called just after construction @@ -159,26 +178,20 @@ public: virtual void setCoveredRegion(const Region& coveredRegion); /** - * validateVisibility - cache a bunch of things + * setVisibleNonTransparentRegion - called when the visible and + * non-transparent region changes. */ - virtual void validateVisibility(const Transform& globalTransform); + virtual void setVisibleNonTransparentRegion(const Region& + visibleNonTransparentRegion); /** - * lockPageFlip - called each time the screen is redrawn and returns whether + * latchBuffer - called each time the screen is redrawn and returns whether * the visible regions need to be recomputed (this is a fairly heavy * operation, so this should be set only if needed). Typically this is used * to figure out if the content or size of a surface has changed. */ - virtual void lockPageFlip(bool& recomputeVisibleRegions); - - /** - * unlockPageFlip - called each time the screen is redrawn. updates the - * final dirty region wrt the planeTransform. - * At this point, all visible regions, surface position and size, etc... are - * correct. - */ - virtual void unlockPageFlip(const Transform& planeTransform, Region& outDirtyRegion); - + virtual Region latchBuffer(bool& recomputeVisibleRegions); + /** * isOpaque - true if this surface is opaque */ @@ -192,7 +205,7 @@ public: /** * needsLinearFiltering - true if this surface's state requires filtering */ - virtual bool needsFiltering() const { return mNeedsFiltering; } + virtual bool needsFiltering(const sp<const DisplayDevice>& hw) const; /** * isSecure - true if this surface is secure, that is if it prevents @@ -206,19 +219,35 @@ public: */ virtual bool isProtected() const { return false; } + /* + * isVisible - true if this layer is visibile, false otherwise + */ + virtual bool isVisible() const; + /** called with the state lock when the surface is removed from the * current list */ virtual void onRemoved() { } /** called after page-flip */ - virtual void onLayerDisplayed() { } + virtual void onLayerDisplayed(const sp<const DisplayDevice>& hw, + HWComposer::HWCLayerInterface* layer); /** called before composition. * returns true if the layer has pending updates. */ virtual bool onPreComposition() { return false; } + /** called before composition. + */ + virtual void onPostComposition() { } + + /** + * Updates the SurfaceTexture's transform hint, for layers that have + * a SurfaceTexture. + */ + virtual void updateTransformHint(const sp<const DisplayDevice>& hw) const { } + /** always call base class first */ virtual void dump(String8& result, char* scratch, size_t size) const; virtual void shortDump(String8& result, char* scratch, size_t size) const; @@ -236,43 +265,27 @@ public: inline const State& currentState() const { return mCurrentState; } inline State& currentState() { return mCurrentState; } - int32_t getOrientation() const { return mOrientation; } - int32_t getPlaneOrientation() const { return mPlaneOrientation; } + void clearWithOpenGL(const sp<const DisplayDevice>& hw, const Region& clip) const; - void clearWithOpenGL(const Region& clip) const; + void setFiltering(bool filtering); + bool getFiltering() const; protected: - const GraphicPlane& graphicPlane(int dpy) const; - GraphicPlane& graphicPlane(int dpy); - - void clearWithOpenGL(const Region& clip, GLclampf r, GLclampf g, - GLclampf b, GLclampf alpha) const; - void drawWithOpenGL(const Region& clip) const; - - void setFiltering(bool filtering); - bool getFiltering() const; + void clearWithOpenGL(const sp<const DisplayDevice>& hw, const Region& clip, + GLclampf r, GLclampf g, GLclampf b, GLclampf alpha) const; + void drawWithOpenGL(const sp<const DisplayDevice>& hw, const Region& clip) const; sp<SurfaceFlinger> mFlinger; - uint32_t mFlags; private: // accessed only in the main thread // Whether filtering is forced on or not bool mFiltering; - // cached during validateVisibility() // Whether filtering is needed b/c of the drawingstate bool mNeedsFiltering; protected: - // cached during validateVisibility() - int32_t mOrientation; - int32_t mPlaneOrientation; - Transform mTransform; - GLfloat mVertices[4][2]; - size_t mNumVertices; - Rect mTransformedBounds; - // these are protected by an external lock State mCurrentState; State mDrawingState; @@ -298,8 +311,7 @@ private: class LayerBaseClient : public LayerBase { public: - LayerBaseClient(SurfaceFlinger* flinger, DisplayID display, - const sp<Client>& client); + LayerBaseClient(SurfaceFlinger* flinger, const sp<Client>& client); virtual ~LayerBaseClient(); diff --git a/services/surfaceflinger/LayerDim.cpp b/services/surfaceflinger/LayerDim.cpp index 96a310f..25caa0a 100644 --- a/services/surfaceflinger/LayerDim.cpp +++ b/services/surfaceflinger/LayerDim.cpp @@ -18,6 +18,9 @@ #include <stdint.h> #include <sys/types.h> +#include <GLES/gl.h> +#include <GLES/glext.h> + #include <utils/Errors.h> #include <utils/Log.h> @@ -25,14 +28,13 @@ #include "LayerDim.h" #include "SurfaceFlinger.h" -#include "DisplayHardware/DisplayHardware.h" +#include "DisplayDevice.h" namespace android { // --------------------------------------------------------------------------- -LayerDim::LayerDim(SurfaceFlinger* flinger, DisplayID display, - const sp<Client>& client) - : LayerBaseClient(flinger, display, client) +LayerDim::LayerDim(SurfaceFlinger* flinger, const sp<Client>& client) + : LayerBaseClient(flinger, client) { } @@ -40,13 +42,12 @@ LayerDim::~LayerDim() { } -void LayerDim::onDraw(const Region& clip) const +void LayerDim::onDraw(const sp<const DisplayDevice>& hw, const Region& clip) const { const State& s(drawingState()); if (s.alpha>0) { - const DisplayHardware& hw(graphicPlane(0).displayHardware()); const GLfloat alpha = s.alpha/255.0f; - const uint32_t fbHeight = hw.getHeight(); + const uint32_t fbHeight = hw->getHeight(); glDisable(GL_TEXTURE_EXTERNAL_OES); glDisable(GL_TEXTURE_2D); @@ -59,8 +60,11 @@ void LayerDim::onDraw(const Region& clip) const glColor4f(0, 0, 0, alpha); - glVertexPointer(2, GL_FLOAT, 0, mVertices); - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + LayerMesh mesh; + computeGeometry(hw, &mesh); + + glVertexPointer(2, GL_FLOAT, 0, mesh.getVertices()); + glDrawArrays(GL_TRIANGLE_FAN, 0, mesh.getVertexCount()); glDisable(GL_BLEND); glDisableClientState(GL_TEXTURE_COORD_ARRAY); diff --git a/services/surfaceflinger/LayerDim.h b/services/surfaceflinger/LayerDim.h index 8770e6d..06f312d 100644 --- a/services/surfaceflinger/LayerDim.h +++ b/services/surfaceflinger/LayerDim.h @@ -32,11 +32,10 @@ namespace android { class LayerDim : public LayerBaseClient { public: - LayerDim(SurfaceFlinger* flinger, DisplayID display, - const sp<Client>& client); + LayerDim(SurfaceFlinger* flinger, const sp<Client>& client); virtual ~LayerDim(); - virtual void onDraw(const Region& clip) const; + virtual void onDraw(const sp<const DisplayDevice>& hw, const Region& clip) const; virtual bool isOpaque() const { return false; } virtual bool isSecure() const { return false; } virtual bool isProtectedByApp() const { return false; } diff --git a/services/surfaceflinger/LayerScreenshot.cpp b/services/surfaceflinger/LayerScreenshot.cpp index b42353c..f8009b3 100644 --- a/services/surfaceflinger/LayerScreenshot.cpp +++ b/services/surfaceflinger/LayerScreenshot.cpp @@ -18,6 +18,9 @@ #include <stdint.h> #include <sys/types.h> +#include <GLES/gl.h> +#include <GLES/glext.h> + #include <utils/Errors.h> #include <utils/Log.h> @@ -25,34 +28,38 @@ #include "LayerScreenshot.h" #include "SurfaceFlinger.h" -#include "DisplayHardware/DisplayHardware.h" +#include "DisplayDevice.h" namespace android { // --------------------------------------------------------------------------- -LayerScreenshot::LayerScreenshot(SurfaceFlinger* flinger, DisplayID display, +LayerScreenshot::LayerScreenshot(SurfaceFlinger* flinger, const sp<Client>& client) - : LayerBaseClient(flinger, display, client), - mTextureName(0), mFlinger(flinger) + : LayerBaseClient(flinger, client), + mTextureName(0), mFlinger(flinger), mIsSecure(false) { } LayerScreenshot::~LayerScreenshot() { if (mTextureName) { - mFlinger->postMessageAsync( - new SurfaceFlinger::MessageDestroyGLTexture(mTextureName) ); + mFlinger->deleteTextureAsync(mTextureName); } } -status_t LayerScreenshot::captureLocked() { +status_t LayerScreenshot::captureLocked(int32_t layerStack) { GLfloat u, v; - status_t result = mFlinger->renderScreenToTextureLocked(0, &mTextureName, &u, &v); + status_t result = mFlinger->renderScreenToTextureLocked(layerStack, + &mTextureName, &u, &v); if (result != NO_ERROR) { return result; } initTexture(u, v); + + // Currently screenshot always comes from the default display + mIsSecure = mFlinger->getDefaultDisplayDevice()->getSecureLayerVisible(); + return NO_ERROR; } @@ -63,6 +70,10 @@ status_t LayerScreenshot::capture() { return result; } initTexture(u, v); + + // Currently screenshot always comes from the default display + mIsSecure = mFlinger->getDefaultDisplayDevice()->getSecureLayerVisible(); + return NO_ERROR; } @@ -78,25 +89,29 @@ void LayerScreenshot::initTexture(GLfloat u, GLfloat v) { void LayerScreenshot::initStates(uint32_t w, uint32_t h, uint32_t flags) { LayerBaseClient::initStates(w, h, flags); - if (!(flags & ISurfaceComposer::eHidden)) { + if (!(flags & ISurfaceComposerClient::eHidden)) { capture(); } + if (flags & ISurfaceComposerClient::eSecure) { + ALOGW("ignoring surface flag eSecure - LayerScreenshot is considered " + "secure iff it captures the contents of a secure surface."); + } } uint32_t LayerScreenshot::doTransaction(uint32_t flags) { - const Layer::State& draw(drawingState()); - const Layer::State& curr(currentState()); + const LayerBase::State& draw(drawingState()); + const LayerBase::State& curr(currentState()); - if (draw.flags & ISurfaceComposer::eLayerHidden) { - if (!(curr.flags & ISurfaceComposer::eLayerHidden)) { + if (draw.flags & layer_state_t::eLayerHidden) { + if (!(curr.flags & layer_state_t::eLayerHidden)) { // we're going from hidden to visible - status_t err = captureLocked(); + status_t err = captureLocked(curr.layerStack); if (err != NO_ERROR) { ALOGW("createScreenshotSurface failed (%s)", strerror(-err)); } } - } else if (curr.flags & ISurfaceComposer::eLayerHidden) { + } else if (curr.flags & layer_state_t::eLayerHidden) { // we're going from visible to hidden if (mTextureName) { glDeleteTextures(1, &mTextureName); @@ -106,36 +121,44 @@ uint32_t LayerScreenshot::doTransaction(uint32_t flags) return LayerBaseClient::doTransaction(flags); } -void LayerScreenshot::onDraw(const Region& clip) const +void LayerScreenshot::onDraw(const sp<const DisplayDevice>& hw, const Region& clip) const { const State& s(drawingState()); if (s.alpha>0) { - const DisplayHardware& hw(graphicPlane(0).displayHardware()); const GLfloat alpha = s.alpha/255.0f; - const uint32_t fbHeight = hw.getHeight(); + const uint32_t fbHeight = hw->getHeight(); if (s.alpha == 0xFF) { glDisable(GL_BLEND); + glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); } else { glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + } + + GLuint texName = mTextureName; + if (isSecure() && !hw->isSecure()) { + texName = mFlinger->getProtectedTexName(); } - glColor4f(0, 0, 0, alpha); + LayerMesh mesh; + computeGeometry(hw, &mesh); + + glColor4f(alpha, alpha, alpha, alpha); glDisable(GL_TEXTURE_EXTERNAL_OES); glEnable(GL_TEXTURE_2D); - glBindTexture(GL_TEXTURE_2D, mTextureName); - glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + glBindTexture(GL_TEXTURE_2D, texName); glMatrixMode(GL_TEXTURE); glLoadIdentity(); glMatrixMode(GL_MODELVIEW); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glTexCoordPointer(2, GL_FLOAT, 0, mTexCoords); - glVertexPointer(2, GL_FLOAT, 0, mVertices); - glDrawArrays(GL_TRIANGLE_FAN, 0, mNumVertices); + glVertexPointer(2, GL_FLOAT, 0, mesh.getVertices()); + glDrawArrays(GL_TRIANGLE_FAN, 0, mesh.getVertexCount()); glDisable(GL_BLEND); glDisable(GL_TEXTURE_2D); diff --git a/services/surfaceflinger/LayerScreenshot.h b/services/surfaceflinger/LayerScreenshot.h index ab90047..38cbd88 100644 --- a/services/surfaceflinger/LayerScreenshot.h +++ b/services/surfaceflinger/LayerScreenshot.h @@ -34,24 +34,24 @@ class LayerScreenshot : public LayerBaseClient GLuint mTextureName; GLfloat mTexCoords[8]; sp<SurfaceFlinger> mFlinger; + bool mIsSecure; public: - LayerScreenshot(SurfaceFlinger* flinger, DisplayID display, - const sp<Client>& client); + LayerScreenshot(SurfaceFlinger* flinger, const sp<Client>& client); virtual ~LayerScreenshot(); status_t capture(); virtual void initStates(uint32_t w, uint32_t h, uint32_t flags); virtual uint32_t doTransaction(uint32_t flags); - virtual void onDraw(const Region& clip) const; + virtual void onDraw(const sp<const DisplayDevice>& hw, const Region& clip) const; virtual bool isOpaque() const { return false; } - virtual bool isSecure() const { return false; } + virtual bool isSecure() const { return mIsSecure; } virtual bool isProtectedByApp() const { return false; } virtual bool isProtectedByDRM() const { return false; } virtual const char* getTypeId() const { return "LayerScreenshot"; } private: - status_t captureLocked(); + status_t captureLocked(int32_t layerStack); void initTexture(GLfloat u, GLfloat v); }; diff --git a/services/surfaceflinger/MessageQueue.cpp b/services/surfaceflinger/MessageQueue.cpp index 290fff4..3f77f74 100644 --- a/services/surfaceflinger/MessageQueue.cpp +++ b/services/surfaceflinger/MessageQueue.cpp @@ -49,13 +49,13 @@ void MessageBase::handleMessage(const Message&) { // --------------------------------------------------------------------------- -void MessageQueue::Handler::signalRefresh() { +void MessageQueue::Handler::dispatchRefresh() { if ((android_atomic_or(eventMaskRefresh, &mEventMask) & eventMaskRefresh) == 0) { mQueue.mLooper->sendMessage(this, Message(MessageQueue::REFRESH)); } } -void MessageQueue::Handler::signalInvalidate() { +void MessageQueue::Handler::dispatchInvalidate() { if ((android_atomic_or(eventMaskInvalidate, &mEventMask) & eventMaskInvalidate) == 0) { mQueue.mLooper->sendMessage(this, Message(MessageQueue::INVALIDATE)); } @@ -132,13 +132,31 @@ status_t MessageQueue::postMessage( return NO_ERROR; } +/* when INVALIDATE_ON_VSYNC is set SF only processes + * buffer updates on VSYNC and performs a refresh immediately + * after. + * + * when INVALIDATE_ON_VSYNC is set to false, SF will instead + * perform the buffer updates immediately, but the refresh only + * at the next VSYNC. + * THIS MODE IS BUGGY ON GALAXY NEXUS AND WILL CAUSE HANGS + */ +#define INVALIDATE_ON_VSYNC 1 + void MessageQueue::invalidate() { -// mHandler->signalInvalidate(); +#if INVALIDATE_ON_VSYNC mEvents->requestNextVsync(); +#else + mHandler->dispatchInvalidate(); +#endif } void MessageQueue::refresh() { +#if INVALIDATE_ON_VSYNC + mHandler->dispatchRefresh(); +#else mEvents->requestNextVsync(); +#endif } int MessageQueue::cb_eventReceiver(int fd, int events, void* data) { @@ -152,7 +170,11 @@ int MessageQueue::eventReceiver(int fd, int events) { while ((n = DisplayEventReceiver::getEvents(mEventTube, buffer, 8)) > 0) { for (int i=0 ; i<n ; i++) { if (buffer[i].header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) { - mHandler->signalRefresh(); +#if INVALIDATE_ON_VSYNC + mHandler->dispatchInvalidate(); +#else + mHandler->dispatchRefresh(); +#endif break; } } diff --git a/services/surfaceflinger/MessageQueue.h b/services/surfaceflinger/MessageQueue.h index ea29e7e..710b2c2 100644 --- a/services/surfaceflinger/MessageQueue.h +++ b/services/surfaceflinger/MessageQueue.h @@ -70,8 +70,8 @@ class MessageQueue { public: Handler(MessageQueue& queue) : mQueue(queue), mEventMask(0) { } virtual void handleMessage(const Message& message); - void signalRefresh(); - void signalInvalidate(); + void dispatchRefresh(); + void dispatchInvalidate(); }; friend class Handler; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 51fcce4..055bfe4 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -16,17 +16,14 @@ #define ATRACE_TAG ATRACE_TAG_GRAPHICS -#include <stdlib.h> -#include <stdio.h> #include <stdint.h> -#include <unistd.h> -#include <fcntl.h> +#include <sys/types.h> #include <errno.h> #include <math.h> -#include <limits.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <sys/ioctl.h> +#include <dlfcn.h> + +#include <EGL/egl.h> +#include <GLES/gl.h> #include <cutils/log.h> #include <cutils/properties.h> @@ -36,20 +33,30 @@ #include <binder/MemoryHeapBase.h> #include <binder/PermissionCache.h> +#include <ui/DisplayInfo.h> + +#include <gui/BitTube.h> +#include <gui/BufferQueue.h> +#include <gui/GuiConfig.h> #include <gui/IDisplayEventConnection.h> +#include <gui/SurfaceTextureClient.h> +#include <ui/GraphicBufferAllocator.h> +#include <ui/PixelFormat.h> +#include <ui/UiConfig.h> + +#include <utils/misc.h> #include <utils/String8.h> #include <utils/String16.h> #include <utils/StopWatch.h> #include <utils/Trace.h> -#include <ui/GraphicBufferAllocator.h> -#include <ui/PixelFormat.h> - -#include <GLES/gl.h> +#include <private/android_filesystem_config.h> #include "clz.h" #include "DdmConnection.h" +#include "DisplayDevice.h" +#include "Client.h" #include "EventThread.h" #include "GLExtensions.h" #include "Layer.h" @@ -57,12 +64,10 @@ #include "LayerScreenshot.h" #include "SurfaceFlinger.h" -#include "DisplayHardware/DisplayHardware.h" +#include "DisplayHardware/FramebufferSurface.h" +#include "DisplayHardware/GraphicBufferAlloc.h" #include "DisplayHardware/HWComposer.h" -#include <private/android_filesystem_config.h> -#include <private/gui/SharedBufferStack.h> -#include <gui/BitTube.h> #define EGL_VERSION_HW_ANDROID 0x3143 @@ -81,12 +86,13 @@ const String16 sDump("android.permission.DUMP"); SurfaceFlinger::SurfaceFlinger() : BnSurfaceComposer(), Thread(false), mTransactionFlags(0), - mTransationPending(false), + mTransactionPending(false), + mAnimTransactionPending(false), mLayersRemoved(false), + mRepaintEverything(0), mBootTime(systemTime()), mVisibleRegionsDirty(false), mHwWorkListDirty(false), - mElectronBeamAnimationMode(0), mDebugRegion(0), mDebugDDMS(0), mDebugDisableHWC(0), @@ -95,13 +101,7 @@ SurfaceFlinger::SurfaceFlinger() mLastSwapBufferTime(0), mDebugInTransaction(0), mLastTransactionTime(0), - mBootFinished(false), - mSecureFrameBuffer(0) -{ - init(); -} - -void SurfaceFlinger::init() + mBootFinished(false) { ALOGI("SurfaceFlinger is starting"); @@ -111,16 +111,16 @@ void SurfaceFlinger::init() property_get("debug.sf.showupdates", value, "0"); mDebugRegion = atoi(value); -#ifdef DDMS_DEBUGGING property_get("debug.sf.ddms", value, "0"); mDebugDDMS = atoi(value); if (mDebugDDMS) { - DdmConnection::start(getServiceName()); + if (!startDdmConnection()) { + // start failed, and DDMS debugging not enabled + mDebugDDMS = 0; + } } -#endif - - ALOGI_IF(mDebugRegion, "showupdates enabled"); - ALOGI_IF(mDebugDDMS, "DDMS debugging enabled"); + ALOGI_IF(mDebugRegion, "showupdates enabled"); + ALOGI_IF(mDebugDDMS, "DDMS debugging enabled"); } void SurfaceFlinger::onFirstRef() @@ -136,26 +136,22 @@ void SurfaceFlinger::onFirstRef() SurfaceFlinger::~SurfaceFlinger() { - glDeleteTextures(1, &mWormholeTexName); + EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY); + eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + eglTerminate(display); } void SurfaceFlinger::binderDied(const wp<IBinder>& who) { // the window manager died on us. prepare its eulogy. - // reset screen orientation - Vector<ComposerState> state; - setTransactionState(state, eOrientationDefault, 0); + // restore initial conditions (default device unblank, etc) + initializeDisplays(); // restart the boot-animation startBootAnim(); } -sp<IMemoryHeap> SurfaceFlinger::getCblk() const -{ - return mServerHeap; -} - sp<ISurfaceComposerClient> SurfaceFlinger::createConnection() { sp<ISurfaceComposerClient> bclient; @@ -167,23 +163,56 @@ sp<ISurfaceComposerClient> SurfaceFlinger::createConnection() return bclient; } -sp<IGraphicBufferAlloc> SurfaceFlinger::createGraphicBufferAlloc() +sp<IBinder> SurfaceFlinger::createDisplay(const String8& displayName, + bool secure) { - sp<GraphicBufferAlloc> gba(new GraphicBufferAlloc()); - return gba; + class DisplayToken : public BBinder { + sp<SurfaceFlinger> flinger; + virtual ~DisplayToken() { + // no more references, this display must be terminated + Mutex::Autolock _l(flinger->mStateLock); + flinger->mCurrentState.displays.removeItem(this); + flinger->setTransactionFlags(eDisplayTransactionNeeded); + } + public: + DisplayToken(const sp<SurfaceFlinger>& flinger) + : flinger(flinger) { + } + }; + + sp<BBinder> token = new DisplayToken(this); + + Mutex::Autolock _l(mStateLock); + DisplayDeviceState info(DisplayDevice::DISPLAY_VIRTUAL); + info.displayName = displayName; + info.isSecure = secure; + mCurrentState.displays.add(token, info); + + return token; } -const GraphicPlane& SurfaceFlinger::graphicPlane(int dpy) const -{ - ALOGE_IF(uint32_t(dpy) >= DISPLAY_COUNT, "Invalid DisplayID %d", dpy); - const GraphicPlane& plane(mGraphicPlanes[dpy]); - return plane; +void SurfaceFlinger::createBuiltinDisplayLocked(DisplayDevice::DisplayType type) { + ALOGW_IF(mBuiltinDisplays[type], + "Overwriting display token for display type %d", type); + mBuiltinDisplays[type] = new BBinder(); + DisplayDeviceState info(type); + // All non-virtual displays are currently considered secure. + info.isSecure = true; + mCurrentState.displays.add(mBuiltinDisplays[type], info); +} + +sp<IBinder> SurfaceFlinger::getBuiltInDisplay(int32_t id) { + if (uint32_t(id) >= DisplayDevice::NUM_DISPLAY_TYPES) { + ALOGE("getDefaultDisplay: id=%d is not a valid default display id", id); + return NULL; + } + return mBuiltinDisplays[id]; } -GraphicPlane& SurfaceFlinger::graphicPlane(int dpy) +sp<IGraphicBufferAlloc> SurfaceFlinger::createGraphicBufferAlloc() { - return const_cast<GraphicPlane&>( - const_cast<SurfaceFlinger const *>(this)->graphicPlane(dpy)); + sp<GraphicBufferAlloc> gba(new GraphicBufferAlloc()); + return gba; } void SurfaceFlinger::bootFinished() @@ -197,7 +226,7 @@ void SurfaceFlinger::bootFinished() const String16 name("window"); sp<IBinder> window(defaultServiceManager()->getService(name)); if (window != 0) { - window->linkToDeath(this); + window->linkToDeath(static_cast<IBinder::DeathRecipient*>(this)); } // stop boot animation @@ -206,60 +235,194 @@ void SurfaceFlinger::bootFinished() property_set("service.bootanim.exit", "1"); } -static inline uint16_t pack565(int r, int g, int b) { - return (r<<11)|(g<<5)|b; +void SurfaceFlinger::deleteTextureAsync(GLuint texture) { + class MessageDestroyGLTexture : public MessageBase { + GLuint texture; + public: + MessageDestroyGLTexture(GLuint texture) + : texture(texture) { + } + virtual bool handler() { + glDeleteTextures(1, &texture); + return true; + } + }; + postMessageAsync(new MessageDestroyGLTexture(texture)); +} + +status_t SurfaceFlinger::selectConfigForAttribute( + EGLDisplay dpy, + EGLint const* attrs, + EGLint attribute, EGLint wanted, + EGLConfig* outConfig) +{ + EGLConfig config = NULL; + EGLint numConfigs = -1, n=0; + eglGetConfigs(dpy, NULL, 0, &numConfigs); + EGLConfig* const configs = new EGLConfig[numConfigs]; + eglChooseConfig(dpy, attrs, configs, numConfigs, &n); + + if (n) { + if (attribute != EGL_NONE) { + for (int i=0 ; i<n ; i++) { + EGLint value = 0; + eglGetConfigAttrib(dpy, configs[i], attribute, &value); + if (wanted == value) { + *outConfig = configs[i]; + delete [] configs; + return NO_ERROR; + } + } + } else { + // just pick the first one + *outConfig = configs[0]; + delete [] configs; + return NO_ERROR; + } + } + delete [] configs; + return NAME_NOT_FOUND; } -status_t SurfaceFlinger::readyToRun() -{ - ALOGI( "SurfaceFlinger's main thread ready to run. " - "Initializing graphics H/W..."); +class EGLAttributeVector { + struct Attribute; + class Adder; + friend class Adder; + KeyedVector<Attribute, EGLint> mList; + struct Attribute { + Attribute() {}; + Attribute(EGLint v) : v(v) { } + EGLint v; + bool operator < (const Attribute& other) const { + // this places EGL_NONE at the end + EGLint lhs(v); + EGLint rhs(other.v); + if (lhs == EGL_NONE) lhs = 0x7FFFFFFF; + if (rhs == EGL_NONE) rhs = 0x7FFFFFFF; + return lhs < rhs; + } + }; + class Adder { + friend class EGLAttributeVector; + EGLAttributeVector& v; + EGLint attribute; + Adder(EGLAttributeVector& v, EGLint attribute) + : v(v), attribute(attribute) { + } + public: + void operator = (EGLint value) { + if (attribute != EGL_NONE) { + v.mList.add(attribute, value); + } + } + operator EGLint () const { return v.mList[attribute]; } + }; +public: + EGLAttributeVector() { + mList.add(EGL_NONE, EGL_NONE); + } + void remove(EGLint attribute) { + if (attribute != EGL_NONE) { + mList.removeItem(attribute); + } + } + Adder operator [] (EGLint attribute) { + return Adder(*this, attribute); + } + EGLint operator [] (EGLint attribute) const { + return mList[attribute]; + } + // cast-operator to (EGLint const*) + operator EGLint const* () const { return &mList.keyAt(0).v; } +}; + +EGLConfig SurfaceFlinger::selectEGLConfig(EGLDisplay display, EGLint nativeVisualId) { + // select our EGLConfig. It must support EGL_RECORDABLE_ANDROID if + // it is to be used with WIFI displays + EGLConfig config; + EGLint dummy; + status_t err; + + EGLAttributeVector attribs; + attribs[EGL_SURFACE_TYPE] = EGL_WINDOW_BIT; + attribs[EGL_RECORDABLE_ANDROID] = EGL_TRUE; + attribs[EGL_FRAMEBUFFER_TARGET_ANDROID] = EGL_TRUE; + attribs[EGL_RED_SIZE] = 8; + attribs[EGL_GREEN_SIZE] = 8; + attribs[EGL_BLUE_SIZE] = 8; + + err = selectConfigForAttribute(display, attribs, EGL_NONE, EGL_NONE, &config); + if (!err) + goto success; + + // maybe we failed because of EGL_FRAMEBUFFER_TARGET_ANDROID + ALOGW("no suitable EGLConfig found, trying without EGL_FRAMEBUFFER_TARGET_ANDROID"); + attribs.remove(EGL_FRAMEBUFFER_TARGET_ANDROID); + err = selectConfigForAttribute(display, attribs, + EGL_NATIVE_VISUAL_ID, nativeVisualId, &config); + if (!err) + goto success; + + // maybe we failed because of EGL_RECORDABLE_ANDROID + ALOGW("no suitable EGLConfig found, trying without EGL_RECORDABLE_ANDROID"); + attribs.remove(EGL_RECORDABLE_ANDROID); + err = selectConfigForAttribute(display, attribs, + EGL_NATIVE_VISUAL_ID, nativeVisualId, &config); + if (!err) + goto success; + + // allow less than 24-bit color; the non-gpu-accelerated emulator only + // supports 16-bit color + ALOGW("no suitable EGLConfig found, trying with 16-bit color allowed"); + attribs.remove(EGL_RED_SIZE); + attribs.remove(EGL_GREEN_SIZE); + attribs.remove(EGL_BLUE_SIZE); + err = selectConfigForAttribute(display, attribs, + EGL_NATIVE_VISUAL_ID, nativeVisualId, &config); + if (!err) + goto success; + + // this EGL is too lame for Android + ALOGE("no suitable EGLConfig found, giving up"); + + return 0; + +success: + if (eglGetConfigAttrib(display, config, EGL_CONFIG_CAVEAT, &dummy)) + ALOGW_IF(dummy == EGL_SLOW_CONFIG, "EGL_SLOW_CONFIG selected!"); + return config; +} + +EGLContext SurfaceFlinger::createGLContext(EGLDisplay display, EGLConfig config) { + // Also create our EGLContext + EGLint contextAttributes[] = { +#ifdef EGL_IMG_context_priority +#ifdef HAS_CONTEXT_PRIORITY +#warning "using EGL_IMG_context_priority" + EGL_CONTEXT_PRIORITY_LEVEL_IMG, EGL_CONTEXT_PRIORITY_HIGH_IMG, +#endif +#endif + EGL_NONE, EGL_NONE + }; + EGLContext ctxt = eglCreateContext(display, config, NULL, contextAttributes); + ALOGE_IF(ctxt==EGL_NO_CONTEXT, "EGLContext creation failed"); + return ctxt; +} + +void SurfaceFlinger::initializeGL(EGLDisplay display) { + GLExtensions& extensions(GLExtensions::getInstance()); + extensions.initWithGLStrings( + glGetString(GL_VENDOR), + glGetString(GL_RENDERER), + glGetString(GL_VERSION), + glGetString(GL_EXTENSIONS), + eglQueryString(display, EGL_VENDOR), + eglQueryString(display, EGL_VERSION), + eglQueryString(display, EGL_EXTENSIONS)); + + glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize); + glGetIntegerv(GL_MAX_VIEWPORT_DIMS, mMaxViewportDims); - // we only support one display currently - int dpy = 0; - - { - // initialize the main display - GraphicPlane& plane(graphicPlane(dpy)); - DisplayHardware* const hw = new DisplayHardware(this, dpy); - plane.setDisplayHardware(hw); - } - - // create the shared control-block - mServerHeap = new MemoryHeapBase(4096, - MemoryHeapBase::READ_ONLY, "SurfaceFlinger read-only heap"); - ALOGE_IF(mServerHeap==0, "can't create shared memory dealer"); - - mServerCblk = static_cast<surface_flinger_cblk_t*>(mServerHeap->getBase()); - ALOGE_IF(mServerCblk==0, "can't get to shared control block's address"); - - new(mServerCblk) surface_flinger_cblk_t; - - // initialize primary screen - // (other display should be initialized in the same manner, but - // asynchronously, as they could come and go. None of this is supported - // yet). - const GraphicPlane& plane(graphicPlane(dpy)); - const DisplayHardware& hw = plane.displayHardware(); - const uint32_t w = hw.getWidth(); - const uint32_t h = hw.getHeight(); - const uint32_t f = hw.getFormat(); - hw.makeCurrent(); - - // initialize the shared control block - mServerCblk->connected |= 1<<dpy; - display_cblk_t* dcblk = mServerCblk->displays + dpy; - memset(dcblk, 0, sizeof(display_cblk_t)); - dcblk->w = plane.getWidth(); - dcblk->h = plane.getHeight(); - dcblk->format = f; - dcblk->orientation = ISurfaceComposer::eOrientationDefault; - dcblk->xdpi = hw.getDpiX(); - dcblk->ydpi = hw.getDpiY(); - dcblk->fps = hw.getRefreshRate(); - dcblk->density = hw.getDensity(); - - // Initialize OpenGL|ES glPixelStorei(GL_UNPACK_ALIGNMENT, 4); glPixelStorei(GL_PACK_ALIGNMENT, 4); glEnableClientState(GL_VERTEX_ARRAY); @@ -267,17 +430,11 @@ status_t SurfaceFlinger::readyToRun() glDisable(GL_DITHER); glDisable(GL_CULL_FACE); - const uint16_t g0 = pack565(0x0F,0x1F,0x0F); - const uint16_t g1 = pack565(0x17,0x2f,0x17); - const uint16_t wormholeTexData[4] = { g0, g1, g1, g0 }; - glGenTextures(1, &mWormholeTexName); - glBindTexture(GL_TEXTURE_2D, mWormholeTexName); - glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 2, 2, 0, - GL_RGB, GL_UNSIGNED_SHORT_5_6_5, wormholeTexData); + struct pack565 { + inline uint16_t operator() (int r, int g, int b) const { + return (r<<11)|(g<<5)|b; + } + } pack565; const uint16_t protTexData[] = { pack565(0x03, 0x03, 0x03) }; glGenTextures(1, &mProtectedTexName); @@ -289,36 +446,128 @@ status_t SurfaceFlinger::readyToRun() glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, protTexData); - glViewport(0, 0, w, h); - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - // put the origin in the left-bottom corner - glOrthof(0, w, 0, h, 0, 1); // l=0, r=w ; b=0, t=h + // print some debugging info + EGLint r,g,b,a; + eglGetConfigAttrib(display, mEGLConfig, EGL_RED_SIZE, &r); + eglGetConfigAttrib(display, mEGLConfig, EGL_GREEN_SIZE, &g); + eglGetConfigAttrib(display, mEGLConfig, EGL_BLUE_SIZE, &b); + eglGetConfigAttrib(display, mEGLConfig, EGL_ALPHA_SIZE, &a); + ALOGI("EGL informations:"); + ALOGI("vendor : %s", extensions.getEglVendor()); + ALOGI("version : %s", extensions.getEglVersion()); + ALOGI("extensions: %s", extensions.getEglExtension()); + ALOGI("Client API: %s", eglQueryString(display, EGL_CLIENT_APIS)?:"Not Supported"); + ALOGI("EGLSurface: %d-%d-%d-%d, config=%p", r, g, b, a, mEGLConfig); + ALOGI("OpenGL ES informations:"); + ALOGI("vendor : %s", extensions.getVendor()); + ALOGI("renderer : %s", extensions.getRenderer()); + ALOGI("version : %s", extensions.getVersion()); + ALOGI("extensions: %s", extensions.getExtension()); + ALOGI("GL_MAX_TEXTURE_SIZE = %d", mMaxTextureSize); + ALOGI("GL_MAX_VIEWPORT_DIMS = %d x %d", mMaxViewportDims[0], mMaxViewportDims[1]); +} +status_t SurfaceFlinger::readyToRun() +{ + ALOGI( "SurfaceFlinger's main thread ready to run. " + "Initializing graphics H/W..."); + + Mutex::Autolock _l(mStateLock); + + // initialize EGL for the default display + mEGLDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); + eglInitialize(mEGLDisplay, NULL, NULL); + + // Initialize the H/W composer object. There may or may not be an + // actual hardware composer underneath. + mHwc = new HWComposer(this, + *static_cast<HWComposer::EventHandler *>(this)); + + // initialize the config and context + EGLint format = mHwc->getVisualID(); + mEGLConfig = selectEGLConfig(mEGLDisplay, format); + mEGLContext = createGLContext(mEGLDisplay, mEGLConfig); + + LOG_ALWAYS_FATAL_IF(mEGLContext == EGL_NO_CONTEXT, + "couldn't create EGLContext"); + + // initialize our non-virtual displays + for (size_t i=0 ; i<DisplayDevice::NUM_DISPLAY_TYPES ; i++) { + DisplayDevice::DisplayType type((DisplayDevice::DisplayType)i); + // set-up the displays that are already connected + if (mHwc->isConnected(i) || type==DisplayDevice::DISPLAY_PRIMARY) { + // All non-virtual displays are currently considered secure. + bool isSecure = true; + createBuiltinDisplayLocked(type); + wp<IBinder> token = mBuiltinDisplays[i]; + + sp<FramebufferSurface> fbs = new FramebufferSurface(*mHwc, i); + sp<SurfaceTextureClient> stc = new SurfaceTextureClient( + static_cast< sp<ISurfaceTexture> >(fbs->getBufferQueue())); + sp<DisplayDevice> hw = new DisplayDevice(this, + type, isSecure, token, stc, fbs, mEGLConfig); + if (i > DisplayDevice::DISPLAY_PRIMARY) { + // FIXME: currently we don't get blank/unblank requests + // for displays other than the main display, so we always + // assume a connected display is unblanked. + ALOGD("marking display %d as acquired/unblanked", i); + hw->acquireScreen(); + } + mDisplays.add(token, hw); + } + } + + // we need a GL context current in a few places, when initializing + // OpenGL ES (see below), or creating a layer, + // or when a texture is (asynchronously) destroyed, and for that + // we need a valid surface, so it's convenient to use the main display + // for that. + sp<const DisplayDevice> hw(getDefaultDisplayDevice()); + + // initialize OpenGL ES + DisplayDevice::makeCurrent(mEGLDisplay, hw, mEGLContext); + initializeGL(mEGLDisplay); // start the EventThread mEventThread = new EventThread(this); mEventQueue.setEventThread(mEventThread); - hw.startSleepManagement(); - /* - * We're now ready to accept clients... - */ + // initialize our drawing state + mDrawingState = mCurrentState; + + // We're now ready to accept clients... mReadyToRunBarrier.open(); + // set initial conditions (e.g. unblank default device) + initializeDisplays(); + // start boot animation startBootAnim(); return NO_ERROR; } +int32_t SurfaceFlinger::allocateHwcDisplayId(DisplayDevice::DisplayType type) { + return (uint32_t(type) < DisplayDevice::NUM_DISPLAY_TYPES) ? + type : mHwc->allocateDisplayId(); +} + void SurfaceFlinger::startBootAnim() { // start boot animation property_set("service.bootanim.exit", "0"); property_set("ctl.start", "bootanim"); } +uint32_t SurfaceFlinger::getMaxTextureSize() const { + return mMaxTextureSize; +} + +uint32_t SurfaceFlinger::getMaxViewportDims() const { + return mMaxViewportDims[0] < mMaxViewportDims[1] ? + mMaxViewportDims[0] : mMaxViewportDims[1]; +} + // ---------------------------------------------------------------------------- bool SurfaceFlinger::authenticateSurfaceTexture( @@ -362,6 +611,79 @@ bool SurfaceFlinger::authenticateSurfaceTexture( return false; } +status_t SurfaceFlinger::getDisplayInfo(const sp<IBinder>& display, DisplayInfo* info) { + int32_t type = NAME_NOT_FOUND; + for (int i=0 ; i<DisplayDevice::NUM_DISPLAY_TYPES ; i++) { + if (display == mBuiltinDisplays[i]) { + type = i; + break; + } + } + + if (type < 0) { + return type; + } + + const HWComposer& hwc(getHwComposer()); + float xdpi = hwc.getDpiX(type); + float ydpi = hwc.getDpiY(type); + + // TODO: Not sure if display density should handled by SF any longer + class Density { + static int getDensityFromProperty(char const* propName) { + char property[PROPERTY_VALUE_MAX]; + int density = 0; + if (property_get(propName, property, NULL) > 0) { + density = atoi(property); + } + return density; + } + public: + static int getEmuDensity() { + return getDensityFromProperty("qemu.sf.lcd_density"); } + static int getBuildDensity() { + return getDensityFromProperty("ro.sf.lcd_density"); } + }; + + if (type == DisplayDevice::DISPLAY_PRIMARY) { + // The density of the device is provided by a build property + float density = Density::getBuildDensity() / 160.0f; + if (density == 0) { + // the build doesn't provide a density -- this is wrong! + // use xdpi instead + ALOGE("ro.sf.lcd_density must be defined as a build property"); + density = xdpi / 160.0f; + } + if (Density::getEmuDensity()) { + // if "qemu.sf.lcd_density" is specified, it overrides everything + xdpi = ydpi = density = Density::getEmuDensity(); + density /= 160.0f; + } + info->density = density; + + // TODO: this needs to go away (currently needed only by webkit) + sp<const DisplayDevice> hw(getDefaultDisplayDevice()); + info->orientation = hw->getOrientation(); + getPixelFormatInfo(hw->getFormat(), &info->pixelFormatInfo); + } else { + // TODO: where should this value come from? + static const int TV_DENSITY = 213; + info->density = TV_DENSITY / 160.0f; + info->orientation = 0; + } + + info->w = hwc.getWidth(type); + info->h = hwc.getHeight(type); + info->xdpi = xdpi; + info->ydpi = ydpi; + info->fps = float(1e9 / hwc.getRefreshPeriod(type)); + + // All non-virtual displays are currently considered secure. + info->secure = true; + + return NO_ERROR; +} + // ---------------------------------------------------------------------------- sp<IDisplayEventConnection> SurfaceFlinger::createDisplayEventConnection() { @@ -400,83 +722,323 @@ status_t SurfaceFlinger::postMessageSync(const sp<MessageBase>& msg, return res; } -bool SurfaceFlinger::threadLoop() -{ +bool SurfaceFlinger::threadLoop() { waitForEvent(); return true; } -void SurfaceFlinger::onMessageReceived(int32_t what) -{ +void SurfaceFlinger::onVSyncReceived(int type, nsecs_t timestamp) { + if (mEventThread == NULL) { + // This is a temporary workaround for b/7145521. A non-null pointer + // does not mean EventThread has finished initializing, so this + // is not a correct fix. + ALOGW("WARNING: EventThread not started, ignoring vsync"); + return; + } + if (uint32_t(type) < DisplayDevice::NUM_DISPLAY_TYPES) { + // we should only receive DisplayDevice::DisplayType from the vsync callback + mEventThread->onVSyncReceived(type, timestamp); + } +} + +void SurfaceFlinger::onHotplugReceived(int type, bool connected) { + if (mEventThread == NULL) { + // This is a temporary workaround for b/7145521. A non-null pointer + // does not mean EventThread has finished initializing, so this + // is not a correct fix. + ALOGW("WARNING: EventThread not started, ignoring hotplug"); + return; + } + + if (uint32_t(type) < DisplayDevice::NUM_DISPLAY_TYPES) { + Mutex::Autolock _l(mStateLock); + if (connected) { + createBuiltinDisplayLocked((DisplayDevice::DisplayType)type); + } else { + mCurrentState.displays.removeItem(mBuiltinDisplays[type]); + mBuiltinDisplays[type].clear(); + } + setTransactionFlags(eDisplayTransactionNeeded); + + // Defer EventThread notification until SF has updated mDisplays. + } +} + +void SurfaceFlinger::eventControl(int disp, int event, int enabled) { + getHwComposer().eventControl(disp, event, enabled); +} + +void SurfaceFlinger::onMessageReceived(int32_t what) { ATRACE_CALL(); switch (what) { - case MessageQueue::REFRESH: { -// case MessageQueue::INVALIDATE: { - // if we're in a global transaction, don't do anything. - const uint32_t mask = eTransactionNeeded | eTraversalNeeded; - uint32_t transactionFlags = peekTransactionFlags(mask); - if (CC_UNLIKELY(transactionFlags)) { - handleTransaction(transactionFlags); + case MessageQueue::INVALIDATE: + handleMessageTransaction(); + handleMessageInvalidate(); + signalRefresh(); + break; + case MessageQueue::REFRESH: + handleMessageRefresh(); + break; + } +} + +void SurfaceFlinger::handleMessageTransaction() { + uint32_t transactionFlags = peekTransactionFlags(eTransactionMask); + if (transactionFlags) { + handleTransaction(transactionFlags); + } +} + +void SurfaceFlinger::handleMessageInvalidate() { + ATRACE_CALL(); + handlePageFlip(); +} + +void SurfaceFlinger::handleMessageRefresh() { + ATRACE_CALL(); + preComposition(); + rebuildLayerStacks(); + setUpHWComposer(); + doDebugFlashRegions(); + doComposition(); + postComposition(); +} + +void SurfaceFlinger::doDebugFlashRegions() +{ + // is debugging enabled + if (CC_LIKELY(!mDebugRegion)) + return; + + const bool repaintEverything = mRepaintEverything; + for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) { + const sp<DisplayDevice>& hw(mDisplays[dpy]); + if (hw->canDraw()) { + // transform the dirty region into this screen's coordinate space + const Region dirtyRegion(hw->getDirtyRegion(repaintEverything)); + if (!dirtyRegion.isEmpty()) { + // redraw the whole screen + doComposeSurfaces(hw, Region(hw->bounds())); + + // and draw the dirty region + glDisable(GL_TEXTURE_EXTERNAL_OES); + glDisable(GL_TEXTURE_2D); + glDisable(GL_BLEND); + glColor4f(1, 0, 1, 1); + const int32_t height = hw->getHeight(); + Region::const_iterator it = dirtyRegion.begin(); + Region::const_iterator const end = dirtyRegion.end(); + while (it != end) { + const Rect& r = *it++; + GLfloat vertices[][2] = { + { r.left, height - r.top }, + { r.left, height - r.bottom }, + { r.right, height - r.bottom }, + { r.right, height - r.top } + }; + glVertexPointer(2, GL_FLOAT, 0, vertices); + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + } + hw->compositionComplete(); + hw->swapBuffers(getHwComposer()); } + } + } - // post surfaces (if needed) - handlePageFlip(); + postFramebuffer(); -// signalRefresh(); -// -// } break; -// -// case MessageQueue::REFRESH: { + if (mDebugRegion > 1) { + usleep(mDebugRegion * 1000); + } - handleRefresh(); + HWComposer& hwc(getHwComposer()); + if (hwc.initCheck() == NO_ERROR) { + status_t err = hwc.prepare(); + ALOGE_IF(err, "HWComposer::prepare failed (%s)", strerror(-err)); + } +} - const DisplayHardware& hw(graphicPlane(0).displayHardware()); +void SurfaceFlinger::preComposition() +{ + bool needExtraInvalidate = false; + const LayerVector& currentLayers(mDrawingState.layersSortedByZ); + const size_t count = currentLayers.size(); + for (size_t i=0 ; i<count ; i++) { + if (currentLayers[i]->onPreComposition()) { + needExtraInvalidate = true; + } + } + if (needExtraInvalidate) { + signalLayerUpdate(); + } +} -// if (mDirtyRegion.isEmpty()) { -// return; -// } +void SurfaceFlinger::postComposition() +{ + const LayerVector& currentLayers(mDrawingState.layersSortedByZ); + const size_t count = currentLayers.size(); + for (size_t i=0 ; i<count ; i++) { + currentLayers[i]->onPostComposition(); + } +} - if (CC_UNLIKELY(mHwWorkListDirty)) { - // build the h/w work list - handleWorkList(); +void SurfaceFlinger::rebuildLayerStacks() { + // rebuild the visible layer list per screen + if (CC_UNLIKELY(mVisibleRegionsDirty)) { + ATRACE_CALL(); + mVisibleRegionsDirty = false; + invalidateHwcGeometry(); + + const LayerVector& currentLayers(mDrawingState.layersSortedByZ); + for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) { + Region opaqueRegion; + Region dirtyRegion; + Vector< sp<LayerBase> > layersSortedByZ; + const sp<DisplayDevice>& hw(mDisplays[dpy]); + const Transform& tr(hw->getTransform()); + const Rect bounds(hw->getBounds()); + if (hw->canDraw()) { + SurfaceFlinger::computeVisibleRegions(currentLayers, + hw->getLayerStack(), dirtyRegion, opaqueRegion); + + const size_t count = currentLayers.size(); + for (size_t i=0 ; i<count ; i++) { + const sp<LayerBase>& layer(currentLayers[i]); + const Layer::State& s(layer->drawingState()); + if (s.layerStack == hw->getLayerStack()) { + Region drawRegion(tr.transform( + layer->visibleNonTransparentRegion)); + drawRegion.andSelf(bounds); + if (!drawRegion.isEmpty()) { + layersSortedByZ.add(layer); + } + } + } } + hw->setVisibleLayersSortedByZ(layersSortedByZ); + hw->undefinedRegion.set(bounds); + hw->undefinedRegion.subtractSelf(tr.transform(opaqueRegion)); + hw->dirtyRegion.orSelf(dirtyRegion); + } + } +} - if (CC_LIKELY(hw.canDraw())) { - // repaint the framebuffer (if needed) - handleRepaint(); - // inform the h/w that we're done compositing - hw.compositionComplete(); - postFramebuffer(); - } else { - // pretend we did the post - hw.compositionComplete(); +void SurfaceFlinger::setUpHWComposer() { + HWComposer& hwc(getHwComposer()); + if (hwc.initCheck() == NO_ERROR) { + // build the h/w work list + if (CC_UNLIKELY(mHwWorkListDirty)) { + mHwWorkListDirty = false; + for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) { + sp<const DisplayDevice> hw(mDisplays[dpy]); + const int32_t id = hw->getHwcDisplayId(); + if (id >= 0) { + const Vector< sp<LayerBase> >& currentLayers( + hw->getVisibleLayersSortedByZ()); + const size_t count = currentLayers.size(); + if (hwc.createWorkList(id, count) == NO_ERROR) { + HWComposer::LayerListIterator cur = hwc.begin(id); + const HWComposer::LayerListIterator end = hwc.end(id); + for (size_t i=0 ; cur!=end && i<count ; ++i, ++cur) { + const sp<LayerBase>& layer(currentLayers[i]); + layer->setGeometry(hw, *cur); + if (mDebugDisableHWC || mDebugRegion) { + cur->setSkip(true); + } + } + } + } } + } - } break; + // set the per-frame data + for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) { + sp<const DisplayDevice> hw(mDisplays[dpy]); + const int32_t id = hw->getHwcDisplayId(); + if (id >= 0) { + const Vector< sp<LayerBase> >& currentLayers( + hw->getVisibleLayersSortedByZ()); + const size_t count = currentLayers.size(); + HWComposer::LayerListIterator cur = hwc.begin(id); + const HWComposer::LayerListIterator end = hwc.end(id); + for (size_t i=0 ; cur!=end && i<count ; ++i, ++cur) { + /* + * update the per-frame h/w composer data for each layer + * and build the transparent region of the FB + */ + const sp<LayerBase>& layer(currentLayers[i]); + layer->setPerFrameData(hw, *cur); + } + } + } + + status_t err = hwc.prepare(); + ALOGE_IF(err, "HWComposer::prepare failed (%s)", strerror(-err)); + } +} + +void SurfaceFlinger::doComposition() { + ATRACE_CALL(); + const bool repaintEverything = android_atomic_and(0, &mRepaintEverything); + for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) { + const sp<DisplayDevice>& hw(mDisplays[dpy]); + if (hw->canDraw()) { + // transform the dirty region into this screen's coordinate space + const Region dirtyRegion(hw->getDirtyRegion(repaintEverything)); + + // repaint the framebuffer (if needed) + doDisplayComposition(hw, dirtyRegion); + + hw->dirtyRegion.clear(); + hw->flip(hw->swapRegion); + hw->swapRegion.clear(); + } + // inform the h/w that we're done compositing + hw->compositionComplete(); } + postFramebuffer(); } void SurfaceFlinger::postFramebuffer() { ATRACE_CALL(); - // mSwapRegion can be empty here is some cases, for instance if a hidden - // or fully transparent window is updating. - // in that case, we need to flip anyways to not risk a deadlock with - // h/w composer. - const DisplayHardware& hw(graphicPlane(0).displayHardware()); const nsecs_t now = systemTime(); mDebugInSwapBuffers = now; - hw.flip(mSwapRegion); - size_t numLayers = mVisibleLayersSortedByZ.size(); - for (size_t i = 0; i < numLayers; i++) { - mVisibleLayersSortedByZ[i]->onLayerDisplayed(); + HWComposer& hwc(getHwComposer()); + if (hwc.initCheck() == NO_ERROR) { + if (!hwc.supportsFramebufferTarget()) { + // EGL spec says: + // "surface must be bound to the calling thread's current context, + // for the current rendering API." + DisplayDevice::makeCurrent(mEGLDisplay, + getDefaultDisplayDevice(), mEGLContext); + } + hwc.commit(); + } + + for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) { + sp<const DisplayDevice> hw(mDisplays[dpy]); + const Vector< sp<LayerBase> >& currentLayers(hw->getVisibleLayersSortedByZ()); + hw->onSwapBuffersCompleted(hwc); + const size_t count = currentLayers.size(); + int32_t id = hw->getHwcDisplayId(); + if (id >=0 && hwc.initCheck() == NO_ERROR) { + HWComposer::LayerListIterator cur = hwc.begin(id); + const HWComposer::LayerListIterator end = hwc.end(id); + for (size_t i = 0; cur != end && i < count; ++i, ++cur) { + currentLayers[i]->onLayerDisplayed(hw, &*cur); + } + } else { + for (size_t i = 0; i < count; i++) { + currentLayers[i]->onLayerDisplayed(hw, NULL); + } + } } mLastSwapBufferTime = systemTime() - now; mDebugInSwapBuffers = 0; - mSwapRegion.clear(); } void SurfaceFlinger::handleTransaction(uint32_t transactionFlags) @@ -493,8 +1055,7 @@ void SurfaceFlinger::handleTransaction(uint32_t transactionFlags) // with mStateLock held to guarantee that mCurrentState won't change // until the transaction is committed. - const uint32_t mask = eTransactionNeeded | eTraversalNeeded; - transactionFlags = getTransactionFlags(mask); + transactionFlags = getTransactionFlags(eTransactionMask); handleTransactionLocked(transactionFlags); mLastTransactionTime = systemTime() - now; @@ -513,10 +1074,9 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) * (perform the transaction for each of them if needed) */ - const bool layersNeedTransaction = transactionFlags & eTraversalNeeded; - if (layersNeedTransaction) { + if (transactionFlags & eTraversalNeeded) { for (size_t i=0 ; i<count ; i++) { - const sp<LayerBase>& layer = currentLayers[i]; + const sp<LayerBase>& layer(currentLayers[i]); uint32_t trFlags = layer->getTransactionFlags(eTransactionNeeded); if (!trFlags) continue; @@ -527,49 +1087,198 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) } /* - * Perform our own transaction if needed + * Perform display own transactions if needed */ - if (transactionFlags & eTransactionNeeded) { - if (mCurrentState.orientation != mDrawingState.orientation) { - // the orientation has changed, recompute all visible regions - // and invalidate everything. + if (transactionFlags & eDisplayTransactionNeeded) { + // here we take advantage of Vector's copy-on-write semantics to + // improve performance by skipping the transaction entirely when + // know that the lists are identical + const KeyedVector< wp<IBinder>, DisplayDeviceState>& curr(mCurrentState.displays); + const KeyedVector< wp<IBinder>, DisplayDeviceState>& draw(mDrawingState.displays); + if (!curr.isIdenticalTo(draw)) { + mVisibleRegionsDirty = true; + const size_t cc = curr.size(); + size_t dc = draw.size(); + + // find the displays that were removed + // (ie: in drawing state but not in current state) + // also handle displays that changed + // (ie: displays that are in both lists) + for (size_t i=0 ; i<dc ; i++) { + const ssize_t j = curr.indexOfKey(draw.keyAt(i)); + if (j < 0) { + // in drawing state but not in current state + if (!draw[i].isMainDisplay()) { + // Call makeCurrent() on the primary display so we can + // be sure that nothing associated with this display + // is current. + const sp<const DisplayDevice> hw(getDefaultDisplayDevice()); + DisplayDevice::makeCurrent(mEGLDisplay, hw, mEGLContext); + mDisplays.removeItem(draw.keyAt(i)); + getHwComposer().disconnectDisplay(draw[i].type); + mEventThread->onHotplugReceived(draw[i].type, false); + } else { + ALOGW("trying to remove the main display"); + } + } else { + // this display is in both lists. see if something changed. + const DisplayDeviceState& state(curr[j]); + const wp<IBinder>& display(curr.keyAt(j)); + if (state.surface->asBinder() != draw[i].surface->asBinder()) { + // changing the surface is like destroying and + // recreating the DisplayDevice, so we just remove it + // from the drawing state, so that it get re-added + // below. + mDisplays.removeItem(display); + mDrawingState.displays.removeItemsAt(i); + dc--; i--; + // at this point we must loop to the next item + continue; + } - const int dpy = 0; - const int orientation = mCurrentState.orientation; - // Currently unused: const uint32_t flags = mCurrentState.orientationFlags; - GraphicPlane& plane(graphicPlane(dpy)); - plane.setOrientation(orientation); + const sp<DisplayDevice> disp(getDisplayDevice(display)); + if (disp != NULL) { + if (state.layerStack != draw[i].layerStack) { + disp->setLayerStack(state.layerStack); + } + if ((state.orientation != draw[i].orientation) + || (state.viewport != draw[i].viewport) + || (state.frame != draw[i].frame)) + { + disp->setProjection(state.orientation, + state.viewport, state.frame); + } + } + } + } - // update the shared control block - const DisplayHardware& hw(plane.displayHardware()); - volatile display_cblk_t* dcblk = mServerCblk->displays + dpy; - dcblk->orientation = orientation; - dcblk->w = plane.getWidth(); - dcblk->h = plane.getHeight(); + // find displays that were added + // (ie: in current state but not in drawing state) + for (size_t i=0 ; i<cc ; i++) { + if (draw.indexOfKey(curr.keyAt(i)) < 0) { + const DisplayDeviceState& state(curr[i]); + + sp<FramebufferSurface> fbs; + sp<SurfaceTextureClient> stc; + if (!state.isVirtualDisplay()) { + + ALOGE_IF(state.surface!=NULL, + "adding a supported display, but rendering " + "surface is provided (%p), ignoring it", + state.surface.get()); + + // for supported (by hwc) displays we provide our + // own rendering surface + fbs = new FramebufferSurface(*mHwc, state.type); + stc = new SurfaceTextureClient( + static_cast< sp<ISurfaceTexture> >( + fbs->getBufferQueue())); + } else { + if (state.surface != NULL) { + stc = new SurfaceTextureClient(state.surface); + } + } - mVisibleRegionsDirty = true; - mDirtyRegion.set(hw.bounds()); + const wp<IBinder>& display(curr.keyAt(i)); + if (stc != NULL) { + sp<DisplayDevice> hw = new DisplayDevice(this, + state.type, state.isSecure, display, stc, fbs, + mEGLConfig); + hw->setLayerStack(state.layerStack); + hw->setProjection(state.orientation, + state.viewport, state.frame); + hw->setDisplayName(state.displayName); + mDisplays.add(display, hw); + mEventThread->onHotplugReceived(state.type, true); + } + } + } } + } - if (currentLayers.size() > mDrawingState.layersSortedByZ.size()) { - // layers have been added - mVisibleRegionsDirty = true; + if (transactionFlags & (eTraversalNeeded|eDisplayTransactionNeeded)) { + // The transform hint might have changed for some layers + // (either because a display has changed, or because a layer + // as changed). + // + // Walk through all the layers in currentLayers, + // and update their transform hint. + // + // If a layer is visible only on a single display, then that + // display is used to calculate the hint, otherwise we use the + // default display. + // + // NOTE: we do this here, rather than in rebuildLayerStacks() so that + // the hint is set before we acquire a buffer from the surface texture. + // + // NOTE: layer transactions have taken place already, so we use their + // drawing state. However, SurfaceFlinger's own transaction has not + // happened yet, so we must use the current state layer list + // (soon to become the drawing state list). + // + sp<const DisplayDevice> disp; + uint32_t currentlayerStack = 0; + for (size_t i=0; i<count; i++) { + // NOTE: we rely on the fact that layers are sorted by + // layerStack first (so we don't have to traverse the list + // of displays for every layer). + const sp<LayerBase>& layerBase(currentLayers[i]); + uint32_t layerStack = layerBase->drawingState().layerStack; + if (i==0 || currentlayerStack != layerStack) { + currentlayerStack = layerStack; + // figure out if this layerstack is mirrored + // (more than one display) if so, pick the default display, + // if not, pick the only display it's on. + disp.clear(); + for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) { + sp<const DisplayDevice> hw(mDisplays[dpy]); + if (hw->getLayerStack() == currentlayerStack) { + if (disp == NULL) { + disp = hw; + } else { + disp = getDefaultDisplayDevice(); + break; + } + } + } + } + if (disp != NULL) { + // presumably this means this layer is using a layerStack + // that is not visible on any display + layerBase->updateTransformHint(disp); + } } + } - // some layers might have been removed, so - // we need to update the regions they're exposing. - if (mLayersRemoved) { - mLayersRemoved = false; - mVisibleRegionsDirty = true; - const LayerVector& previousLayers(mDrawingState.layersSortedByZ); - const size_t count = previousLayers.size(); - for (size_t i=0 ; i<count ; i++) { - const sp<LayerBase>& layer(previousLayers[i]); - if (currentLayers.indexOf( layer ) < 0) { - // this layer is not visible anymore - mDirtyRegionRemovedLayer.orSelf(layer->visibleRegionScreen); - } + + /* + * Perform our own transaction if needed + */ + + const LayerVector& previousLayers(mDrawingState.layersSortedByZ); + if (currentLayers.size() > previousLayers.size()) { + // layers have been added + mVisibleRegionsDirty = true; + } + + // some layers might have been removed, so + // we need to update the regions they're exposing. + if (mLayersRemoved) { + mLayersRemoved = false; + mVisibleRegionsDirty = true; + const size_t count = previousLayers.size(); + for (size_t i=0 ; i<count ; i++) { + const sp<LayerBase>& layer(previousLayers[i]); + if (currentLayers.indexOf(layer) < 0) { + // this layer is not visible anymore + // TODO: we could traverse the tree from front to back and + // compute the actual visible region + // TODO: we could cache the transformed region + const Layer::State& s(layer->drawingState()); + Region visibleReg = s.transform.transform( + Region(Rect(s.active.w, s.active.h))); + invalidateLayerStack(s.layerStack, visibleReg); } } } @@ -577,30 +1286,45 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) commitTransaction(); } +void SurfaceFlinger::commitTransaction() +{ + if (!mLayersPendingRemoval.isEmpty()) { + // Notify removed layers now that they can't be drawn from + for (size_t i = 0; i < mLayersPendingRemoval.size(); i++) { + mLayersPendingRemoval[i]->onRemoved(); + } + mLayersPendingRemoval.clear(); + } + + mDrawingState = mCurrentState; + mTransactionPending = false; + mAnimTransactionPending = false; + mTransactionCV.broadcast(); +} + void SurfaceFlinger::computeVisibleRegions( - const LayerVector& currentLayers, Region& dirtyRegion, Region& opaqueRegion) + const LayerVector& currentLayers, uint32_t layerStack, + Region& outDirtyRegion, Region& outOpaqueRegion) { ATRACE_CALL(); - const GraphicPlane& plane(graphicPlane(0)); - const Transform& planeTransform(plane.transform()); - const DisplayHardware& hw(plane.displayHardware()); - const Region screenRegion(hw.bounds()); - Region aboveOpaqueLayers; Region aboveCoveredLayers; Region dirty; - bool secureFrameBuffer = false; + outDirtyRegion.clear(); size_t i = currentLayers.size(); while (i--) { const sp<LayerBase>& layer = currentLayers[i]; - layer->validateVisibility(planeTransform); // start with the whole surface at its current location const Layer::State& s(layer->drawingState()); + // only consider the layers on the given later stack + if (s.layerStack != layerStack) + continue; + /* * opaqueRegion: area of a surface that is fully opaque. */ @@ -620,21 +1344,42 @@ void SurfaceFlinger::computeVisibleRegions( */ Region coveredRegion; + /* + * transparentRegion: area of a surface that is hinted to be completely + * transparent. This is only used to tell when the layer has no visible + * non-transparent regions and can be removed from the layer list. It + * does not affect the visibleRegion of this layer or any layers + * beneath it. The hint may not be correct if apps don't respect the + * SurfaceView restrictions (which, sadly, some don't). + */ + Region transparentRegion; + // handle hidden surfaces by setting the visible region to empty - if (CC_LIKELY(!(s.flags & ISurfaceComposer::eLayerHidden) && s.alpha)) { + if (CC_LIKELY(layer->isVisible())) { const bool translucent = !layer->isOpaque(); - const Rect bounds(layer->visibleBounds()); + Rect bounds(layer->computeBounds()); visibleRegion.set(bounds); - visibleRegion.andSelf(screenRegion); if (!visibleRegion.isEmpty()) { // Remove the transparent area from the visible region if (translucent) { - visibleRegion.subtractSelf(layer->transparentRegionScreen); + const Transform tr(s.transform); + if (tr.transformed()) { + if (tr.preserveRects()) { + // transform the transparent region + transparentRegion = tr.transform(s.transparentRegion); + } else { + // transformation too complex, can't do the + // transparent region optimization. + transparentRegion.clear(); + } + } else { + transparentRegion = s.transparentRegion; + } } // compute the opaque region - const int32_t layerOrientation = layer->getOrientation(); + const int32_t layerOrientation = s.transform.getOrientation(); if (s.alpha==255 && !translucent && ((layerOrientation & Transform::ROT_INVALID) == false)) { // the opaque region is the layer's footprint @@ -657,7 +1402,7 @@ void SurfaceFlinger::computeVisibleRegions( // we need to invalidate the whole region dirty = visibleRegion; // as well, as the old visible region - dirty.orSelf(layer->visibleRegionScreen); + dirty.orSelf(layer->visibleRegion); layer->contentDirty = false; } else { /* compute the exposed region: @@ -673,241 +1418,121 @@ void SurfaceFlinger::computeVisibleRegions( * exposed because of a resize. */ const Region newExposed = visibleRegion - coveredRegion; - const Region oldVisibleRegion = layer->visibleRegionScreen; - const Region oldCoveredRegion = layer->coveredRegionScreen; + const Region oldVisibleRegion = layer->visibleRegion; + const Region oldCoveredRegion = layer->coveredRegion; const Region oldExposed = oldVisibleRegion - oldCoveredRegion; dirty = (visibleRegion&oldCoveredRegion) | (newExposed-oldExposed); } dirty.subtractSelf(aboveOpaqueLayers); // accumulate to the screen dirty region - dirtyRegion.orSelf(dirty); + outDirtyRegion.orSelf(dirty); // Update aboveOpaqueLayers for next (lower) layer aboveOpaqueLayers.orSelf(opaqueRegion); - // Store the visible region is screen space + // Store the visible region in screen space layer->setVisibleRegion(visibleRegion); layer->setCoveredRegion(coveredRegion); - - // If a secure layer is partially visible, lock-down the screen! - if (layer->isSecure() && !visibleRegion.isEmpty()) { - secureFrameBuffer = true; - } + layer->setVisibleNonTransparentRegion( + visibleRegion.subtract(transparentRegion)); } - // invalidate the areas where a layer was removed - dirtyRegion.orSelf(mDirtyRegionRemovedLayer); - mDirtyRegionRemovedLayer.clear(); - - mSecureFrameBuffer = secureFrameBuffer; - opaqueRegion = aboveOpaqueLayers; + outOpaqueRegion = aboveOpaqueLayers; } - -void SurfaceFlinger::commitTransaction() -{ - if (!mLayersPendingRemoval.isEmpty()) { - // Notify removed layers now that they can't be drawn from - for (size_t i = 0; i < mLayersPendingRemoval.size(); i++) { - mLayersPendingRemoval[i]->onRemoved(); +void SurfaceFlinger::invalidateLayerStack(uint32_t layerStack, + const Region& dirty) { + for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) { + const sp<DisplayDevice>& hw(mDisplays[dpy]); + if (hw->getLayerStack() == layerStack) { + hw->dirtyRegion.orSelf(dirty); } - mLayersPendingRemoval.clear(); } - - mDrawingState = mCurrentState; - mTransationPending = false; - mTransactionCV.broadcast(); } void SurfaceFlinger::handlePageFlip() { - ATRACE_CALL(); - const DisplayHardware& hw = graphicPlane(0).displayHardware(); - const Region screenRegion(hw.bounds()); - - const LayerVector& currentLayers(mDrawingState.layersSortedByZ); - const bool visibleRegions = lockPageFlip(currentLayers); - - if (visibleRegions || mVisibleRegionsDirty) { - Region opaqueRegion; - computeVisibleRegions(currentLayers, mDirtyRegion, opaqueRegion); - - /* - * rebuild the visible layer list - */ - const size_t count = currentLayers.size(); - mVisibleLayersSortedByZ.clear(); - mVisibleLayersSortedByZ.setCapacity(count); - for (size_t i=0 ; i<count ; i++) { - if (!currentLayers[i]->visibleRegionScreen.isEmpty()) - mVisibleLayersSortedByZ.add(currentLayers[i]); - } - - mWormholeRegion = screenRegion.subtract(opaqueRegion); - mVisibleRegionsDirty = false; - invalidateHwcGeometry(); - } - - unlockPageFlip(currentLayers); - - mDirtyRegion.orSelf(getAndClearInvalidateRegion()); - mDirtyRegion.andSelf(screenRegion); -} - -void SurfaceFlinger::invalidateHwcGeometry() -{ - mHwWorkListDirty = true; -} + Region dirtyRegion; -bool SurfaceFlinger::lockPageFlip(const LayerVector& currentLayers) -{ - bool recomputeVisibleRegions = false; - size_t count = currentLayers.size(); - sp<LayerBase> const* layers = currentLayers.array(); - for (size_t i=0 ; i<count ; i++) { - const sp<LayerBase>& layer(layers[i]); - layer->lockPageFlip(recomputeVisibleRegions); - } - return recomputeVisibleRegions; -} - -void SurfaceFlinger::unlockPageFlip(const LayerVector& currentLayers) -{ - const GraphicPlane& plane(graphicPlane(0)); - const Transform& planeTransform(plane.transform()); - const size_t count = currentLayers.size(); - sp<LayerBase> const* layers = currentLayers.array(); - for (size_t i=0 ; i<count ; i++) { - const sp<LayerBase>& layer(layers[i]); - layer->unlockPageFlip(planeTransform, mDirtyRegion); - } -} - -void SurfaceFlinger::handleRefresh() -{ - bool needInvalidate = false; + bool visibleRegions = false; const LayerVector& currentLayers(mDrawingState.layersSortedByZ); const size_t count = currentLayers.size(); for (size_t i=0 ; i<count ; i++) { const sp<LayerBase>& layer(currentLayers[i]); - if (layer->onPreComposition()) { - needInvalidate = true; - } - } - if (needInvalidate) { - signalLayerUpdate(); + const Region dirty(layer->latchBuffer(visibleRegions)); + const Layer::State& s(layer->drawingState()); + invalidateLayerStack(s.layerStack, dirty); } -} + mVisibleRegionsDirty |= visibleRegions; +} -void SurfaceFlinger::handleWorkList() +void SurfaceFlinger::invalidateHwcGeometry() { - mHwWorkListDirty = false; - HWComposer& hwc(graphicPlane(0).displayHardware().getHwComposer()); - if (hwc.initCheck() == NO_ERROR) { - const Vector< sp<LayerBase> >& currentLayers(mVisibleLayersSortedByZ); - const size_t count = currentLayers.size(); - hwc.createWorkList(count); - hwc_layer_t* const cur(hwc.getLayers()); - for (size_t i=0 ; cur && i<count ; i++) { - currentLayers[i]->setGeometry(&cur[i]); - if (mDebugDisableHWC || mDebugRegion) { - cur[i].compositionType = HWC_FRAMEBUFFER; - cur[i].flags |= HWC_SKIP_LAYER; - } - } - } + mHwWorkListDirty = true; } -void SurfaceFlinger::handleRepaint() + +void SurfaceFlinger::doDisplayComposition(const sp<const DisplayDevice>& hw, + const Region& inDirtyRegion) { - ATRACE_CALL(); + Region dirtyRegion(inDirtyRegion); // compute the invalid region - mSwapRegion.orSelf(mDirtyRegion); + hw->swapRegion.orSelf(dirtyRegion); - if (CC_UNLIKELY(mDebugRegion)) { - debugFlashRegions(); - } - - // set the frame buffer - const DisplayHardware& hw(graphicPlane(0).displayHardware()); - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - - uint32_t flags = hw.getFlags(); - if (flags & DisplayHardware::SWAP_RECTANGLE) { + uint32_t flags = hw->getFlags(); + if (flags & DisplayDevice::SWAP_RECTANGLE) { // we can redraw only what's dirty, but since SWAP_RECTANGLE only // takes a rectangle, we must make sure to update that whole // rectangle in that case - mDirtyRegion.set(mSwapRegion.bounds()); + dirtyRegion.set(hw->swapRegion.bounds()); } else { - if (flags & DisplayHardware::PARTIAL_UPDATES) { + if (flags & DisplayDevice::PARTIAL_UPDATES) { // We need to redraw the rectangle that will be updated // (pushed to the framebuffer). // This is needed because PARTIAL_UPDATES only takes one - // rectangle instead of a region (see DisplayHardware::flip()) - mDirtyRegion.set(mSwapRegion.bounds()); + // rectangle instead of a region (see DisplayDevice::flip()) + dirtyRegion.set(hw->swapRegion.bounds()); } else { // we need to redraw everything (the whole screen) - mDirtyRegion.set(hw.bounds()); - mSwapRegion = mDirtyRegion; + dirtyRegion.set(hw->bounds()); + hw->swapRegion = dirtyRegion; } } - setupHardwareComposer(); - composeSurfaces(mDirtyRegion); + doComposeSurfaces(hw, dirtyRegion); // update the swap region and clear the dirty region - mSwapRegion.orSelf(mDirtyRegion); - mDirtyRegion.clear(); + hw->swapRegion.orSelf(dirtyRegion); + + // swap buffers (presentation) + hw->swapBuffers(getHwComposer()); } -void SurfaceFlinger::setupHardwareComposer() +void SurfaceFlinger::doComposeSurfaces(const sp<const DisplayDevice>& hw, const Region& dirty) { - const DisplayHardware& hw(graphicPlane(0).displayHardware()); - HWComposer& hwc(hw.getHwComposer()); - hwc_layer_t* const cur(hwc.getLayers()); - if (!cur) { - return; - } + const int32_t id = hw->getHwcDisplayId(); + HWComposer& hwc(getHwComposer()); + HWComposer::LayerListIterator cur = hwc.begin(id); + const HWComposer::LayerListIterator end = hwc.end(id); - const Vector< sp<LayerBase> >& layers(mVisibleLayersSortedByZ); - size_t count = layers.size(); - - ALOGE_IF(hwc.getNumLayers() != count, - "HAL number of layers (%d) doesn't match surfaceflinger (%d)", - hwc.getNumLayers(), count); - - // just to be extra-safe, use the smallest count - if (hwc.initCheck() == NO_ERROR) { - count = count < hwc.getNumLayers() ? count : hwc.getNumLayers(); - } - - /* - * update the per-frame h/w composer data for each layer - * and build the transparent region of the FB - */ - for (size_t i=0 ; i<count ; i++) { - const sp<LayerBase>& layer(layers[i]); - layer->setPerFrameData(&cur[i]); - } - status_t err = hwc.prepare(); - ALOGE_IF(err, "HWComposer::prepare failed (%s)", strerror(-err)); -} + const bool hasGlesComposition = hwc.hasGlesComposition(id) || (cur==end); + if (hasGlesComposition) { + if (!DisplayDevice::makeCurrent(mEGLDisplay, hw, mEGLContext)) { + ALOGW("DisplayDevice::makeCurrent failed. Aborting surface composition for display %s", + hw->getDisplayName().string()); + return; + } -void SurfaceFlinger::composeSurfaces(const Region& dirty) -{ - const DisplayHardware& hw(graphicPlane(0).displayHardware()); - HWComposer& hwc(hw.getHwComposer()); - hwc_layer_t* const cur(hwc.getLayers()); + // set the frame buffer + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); - const size_t fbLayerCount = hwc.getLayerCount(HWC_FRAMEBUFFER); - if (!cur || fbLayerCount) { // Never touch the framebuffer if we don't have any framebuffer layers - - if (hwc.getLayerCount(HWC_OVERLAY)) { + const bool hasHwcComposition = hwc.hasHwcComposition(id); + if (hasHwcComposition) { // when using overlays, we assume a fully transparent framebuffer // NOTE: we could reduce how much we need to clear, for instance // remove where there are opaque FB layers. however, on some @@ -916,69 +1541,103 @@ void SurfaceFlinger::composeSurfaces(const Region& dirty) glClearColor(0, 0, 0, 0); glClear(GL_COLOR_BUFFER_BIT); } else { + const Region region(hw->undefinedRegion.intersect(dirty)); // screen is already cleared here - if (!mWormholeRegion.isEmpty()) { + if (!region.isEmpty()) { // can happen with SurfaceView - drawWormhole(); + drawWormhole(hw, region); } } - /* - * and then, render the layers targeted at the framebuffer - */ + if (hw->getDisplayType() >= DisplayDevice::DISPLAY_EXTERNAL) { + // TODO: just to be on the safe side, we don't set the + // scissor on the main display. It should never be needed + // anyways (though in theory it could since the API allows it). + const Rect& bounds(hw->getBounds()); + const Transform& tr(hw->getTransform()); + const Rect scissor(tr.transform(hw->getViewport())); + if (scissor != bounds) { + // scissor doesn't match the screen's dimensions, so we + // need to clear everything outside of it and enable + // the GL scissor so we don't draw anything where we shouldn't + const GLint height = hw->getHeight(); + glScissor(scissor.left, height - scissor.bottom, + scissor.getWidth(), scissor.getHeight()); + // clear everything unscissored + glClearColor(0, 0, 0, 0); + glClear(GL_COLOR_BUFFER_BIT); + // enable scissor for this frame + glEnable(GL_SCISSOR_TEST); + } + } + } - const Vector< sp<LayerBase> >& layers(mVisibleLayersSortedByZ); - const size_t count = layers.size(); + /* + * and then, render the layers targeted at the framebuffer + */ - for (size_t i=0 ; i<count ; i++) { + const Vector< sp<LayerBase> >& layers(hw->getVisibleLayersSortedByZ()); + const size_t count = layers.size(); + const Transform& tr = hw->getTransform(); + if (cur != end) { + // we're using h/w composer + for (size_t i=0 ; i<count && cur!=end ; ++i, ++cur) { const sp<LayerBase>& layer(layers[i]); - const Region clip(dirty.intersect(layer->visibleRegionScreen)); + const Region clip(dirty.intersect(tr.transform(layer->visibleRegion))); if (!clip.isEmpty()) { - if (cur && (cur[i].compositionType == HWC_OVERLAY)) { - if (i && (cur[i].hints & HWC_HINT_CLEAR_FB) - && layer->isOpaque()) { - // never clear the very first layer since we're - // guaranteed the FB is already cleared - layer->clearWithOpenGL(clip); + switch (cur->getCompositionType()) { + case HWC_OVERLAY: { + if ((cur->getHints() & HWC_HINT_CLEAR_FB) + && i + && layer->isOpaque() + && hasGlesComposition) { + // never clear the very first layer since we're + // guaranteed the FB is already cleared + layer->clearWithOpenGL(hw, clip); + } + break; + } + case HWC_FRAMEBUFFER: { + layer->draw(hw, clip); + break; + } + case HWC_FRAMEBUFFER_TARGET: { + // this should not happen as the iterator shouldn't + // let us get there. + ALOGW("HWC_FRAMEBUFFER_TARGET found in hwc list (index=%d)", i); + break; } - continue; } - // render the layer - layer->draw(clip); + } + layer->setAcquireFence(hw, *cur); + } + } else { + // we're not using h/w composer + for (size_t i=0 ; i<count ; ++i) { + const sp<LayerBase>& layer(layers[i]); + const Region clip(dirty.intersect( + tr.transform(layer->visibleRegion))); + if (!clip.isEmpty()) { + layer->draw(hw, clip); } } } + + // disable scissor at the end of the frame + glDisable(GL_SCISSOR_TEST); } -void SurfaceFlinger::debugFlashRegions() +void SurfaceFlinger::drawWormhole(const sp<const DisplayDevice>& hw, + const Region& region) const { - const DisplayHardware& hw(graphicPlane(0).displayHardware()); - const uint32_t flags = hw.getFlags(); - const int32_t height = hw.getHeight(); - if (mSwapRegion.isEmpty()) { - return; - } - - if (!(flags & DisplayHardware::SWAP_RECTANGLE)) { - const Region repaint((flags & DisplayHardware::PARTIAL_UPDATES) ? - mDirtyRegion.bounds() : hw.bounds()); - composeSurfaces(repaint); - } - glDisable(GL_TEXTURE_EXTERNAL_OES); glDisable(GL_TEXTURE_2D); glDisable(GL_BLEND); + glColor4f(0,0,0,0); - static int toggle = 0; - toggle = 1 - toggle; - if (toggle) { - glColor4f(1, 0, 1, 1); - } else { - glColor4f(1, 1, 0, 1); - } - - Region::const_iterator it = mDirtyRegion.begin(); - Region::const_iterator const end = mDirtyRegion.end(); + const int32_t height = hw->getHeight(); + Region::const_iterator it = region.begin(); + Region::const_iterator const end = region.end(); while (it != end) { const Rect& r = *it++; GLfloat vertices[][2] = { @@ -990,54 +1649,6 @@ void SurfaceFlinger::debugFlashRegions() glVertexPointer(2, GL_FLOAT, 0, vertices); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); } - - hw.flip(mSwapRegion); - - if (mDebugRegion > 1) - usleep(mDebugRegion * 1000); -} - -void SurfaceFlinger::drawWormhole() const -{ - const Region region(mWormholeRegion.intersect(mDirtyRegion)); - if (region.isEmpty()) - return; - - glDisable(GL_TEXTURE_EXTERNAL_OES); - glDisable(GL_TEXTURE_2D); - glDisable(GL_BLEND); - glColor4f(0,0,0,0); - - GLfloat vertices[4][2]; - glVertexPointer(2, GL_FLOAT, 0, vertices); - Region::const_iterator it = region.begin(); - Region::const_iterator const end = region.end(); - while (it != end) { - const Rect& r = *it++; - vertices[0][0] = r.left; - vertices[0][1] = r.top; - vertices[1][0] = r.right; - vertices[1][1] = r.top; - vertices[2][0] = r.right; - vertices[2][1] = r.bottom; - vertices[3][0] = r.left; - vertices[3][1] = r.bottom; - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - } -} - -status_t SurfaceFlinger::addLayer(const sp<LayerBase>& layer) -{ - Mutex::Autolock _l(mStateLock); - addLayer_l(layer); - setTransactionFlags(eTransactionNeeded|eTraversalNeeded); - return NO_ERROR; -} - -status_t SurfaceFlinger::addLayer_l(const sp<LayerBase>& layer) -{ - ssize_t i = mCurrentState.layersSortedByZ.add(layer); - return (i < 0) ? status_t(i) : status_t(NO_ERROR); } ssize_t SurfaceFlinger::addClientLayer(const sp<Client>& client, @@ -1046,10 +1657,9 @@ ssize_t SurfaceFlinger::addClientLayer(const sp<Client>& client, // attach this layer to the client size_t name = client->attachLayer(lbc); - Mutex::Autolock _l(mStateLock); - // add this layer to the current state list - addLayer_l(lbc); + Mutex::Autolock _l(mStateLock); + mCurrentState.layersSortedByZ.add(lbc); return ssize_t(name); } @@ -1065,10 +1675,6 @@ status_t SurfaceFlinger::removeLayer(const sp<LayerBase>& layer) status_t SurfaceFlinger::removeLayer_l(const sp<LayerBase>& layerBase) { - sp<LayerBaseClient> lbc(layerBase->getLayerBaseClient()); - if (lbc != 0) { - mLayerMap.removeItem( lbc->getSurfaceBinder() ); - } ssize_t index = mCurrentState.layersSortedByZ.remove(layerBase); if (index >= 0) { mLayersRemoved = true; @@ -1095,13 +1701,6 @@ status_t SurfaceFlinger::purgatorizeLayer_l(const sp<LayerBase>& layerBase) return (err == NAME_NOT_FOUND) ? status_t(NO_ERROR) : err; } -status_t SurfaceFlinger::invalidateLayerVisibility(const sp<LayerBase>& layer) -{ - layer->forceVisibilityTransaction(); - setTransactionFlags(eTraversalNeeded); - return NO_ERROR; -} - uint32_t SurfaceFlinger::peekTransactionFlags(uint32_t flags) { return android_atomic_release_load(&mTransactionFlags); @@ -1121,27 +1720,57 @@ uint32_t SurfaceFlinger::setTransactionFlags(uint32_t flags) return old; } - -void SurfaceFlinger::setTransactionState(const Vector<ComposerState>& state, - int orientation, uint32_t flags) { +void SurfaceFlinger::setTransactionState( + const Vector<ComposerState>& state, + const Vector<DisplayState>& displays, + uint32_t flags) +{ + ATRACE_CALL(); Mutex::Autolock _l(mStateLock); - uint32_t transactionFlags = 0; - if (mCurrentState.orientation != orientation) { - if (uint32_t(orientation)<=eOrientation270 || orientation==42) { - mCurrentState.orientation = orientation; - transactionFlags |= eTransactionNeeded; - } else if (orientation != eOrientationUnchanged) { - ALOGW("setTransactionState: ignoring unrecognized orientation: %d", - orientation); + + if (flags & eAnimation) { + // For window updates that are part of an animation we must wait for + // previous animation "frames" to be handled. + while (mAnimTransactionPending) { + status_t err = mTransactionCV.waitRelative(mStateLock, s2ns(5)); + if (CC_UNLIKELY(err != NO_ERROR)) { + // just in case something goes wrong in SF, return to the + // caller after a few seconds. + ALOGW_IF(err == TIMED_OUT, "setTransactionState timed out " + "waiting for previous animation frame"); + mAnimTransactionPending = false; + break; + } } } - const size_t count = state.size(); + size_t count = displays.size(); + for (size_t i=0 ; i<count ; i++) { + const DisplayState& s(displays[i]); + transactionFlags |= setDisplayStateLocked(s); + } + + count = state.size(); for (size_t i=0 ; i<count ; i++) { const ComposerState& s(state[i]); - sp<Client> client( static_cast<Client *>(s.client.get()) ); - transactionFlags |= setClientStateLocked(client, s.state); + // Here we need to check that the interface we're given is indeed + // one of our own. A malicious client could give us a NULL + // IInterface, or one of its own or even one of our own but a + // different type. All these situations would cause us to crash. + // + // NOTE: it would be better to use RTTI as we could directly check + // that we have a Client*. however, RTTI is disabled in Android. + if (s.client != NULL) { + sp<IBinder> binder = s.client->asBinder(); + if (binder != NULL) { + String16 desc(binder->getInterfaceDescriptor()); + if (desc == ISurfaceComposerClient::descriptor) { + sp<Client> client( static_cast<Client *>(s.client.get()) ); + transactionFlags |= setClientStateLocked(client, s.state); + } + } + } } if (transactionFlags) { @@ -1151,52 +1780,154 @@ void SurfaceFlinger::setTransactionState(const Vector<ComposerState>& state, // if this is a synchronous transaction, wait for it to take effect // before returning. if (flags & eSynchronous) { - mTransationPending = true; + mTransactionPending = true; } - while (mTransationPending) { + if (flags & eAnimation) { + mAnimTransactionPending = true; + } + while (mTransactionPending) { status_t err = mTransactionCV.waitRelative(mStateLock, s2ns(5)); if (CC_UNLIKELY(err != NO_ERROR)) { // just in case something goes wrong in SF, return to the // called after a few seconds. - ALOGW_IF(err == TIMED_OUT, "closeGlobalTransaction timed out!"); - mTransationPending = false; + ALOGW_IF(err == TIMED_OUT, "setTransactionState timed out!"); + mTransactionPending = false; break; } } } } -sp<ISurface> SurfaceFlinger::createSurface( +uint32_t SurfaceFlinger::setDisplayStateLocked(const DisplayState& s) +{ + ssize_t dpyIdx = mCurrentState.displays.indexOfKey(s.token); + if (dpyIdx < 0) + return 0; + + uint32_t flags = 0; + DisplayDeviceState& disp(mCurrentState.displays.editValueAt(dpyIdx)); + if (disp.isValid()) { + const uint32_t what = s.what; + if (what & DisplayState::eSurfaceChanged) { + if (disp.surface->asBinder() != s.surface->asBinder()) { + disp.surface = s.surface; + flags |= eDisplayTransactionNeeded; + } + } + if (what & DisplayState::eLayerStackChanged) { + if (disp.layerStack != s.layerStack) { + disp.layerStack = s.layerStack; + flags |= eDisplayTransactionNeeded; + } + } + if (what & DisplayState::eDisplayProjectionChanged) { + if (disp.orientation != s.orientation) { + disp.orientation = s.orientation; + flags |= eDisplayTransactionNeeded; + } + if (disp.frame != s.frame) { + disp.frame = s.frame; + flags |= eDisplayTransactionNeeded; + } + if (disp.viewport != s.viewport) { + disp.viewport = s.viewport; + flags |= eDisplayTransactionNeeded; + } + } + } + return flags; +} + +uint32_t SurfaceFlinger::setClientStateLocked( + const sp<Client>& client, + const layer_state_t& s) +{ + uint32_t flags = 0; + sp<LayerBaseClient> layer(client->getLayerUser(s.surface)); + if (layer != 0) { + const uint32_t what = s.what; + if (what & layer_state_t::ePositionChanged) { + if (layer->setPosition(s.x, s.y)) + flags |= eTraversalNeeded; + } + if (what & layer_state_t::eLayerChanged) { + // NOTE: index needs to be calculated before we update the state + ssize_t idx = mCurrentState.layersSortedByZ.indexOf(layer); + if (layer->setLayer(s.z)) { + mCurrentState.layersSortedByZ.removeAt(idx); + mCurrentState.layersSortedByZ.add(layer); + // we need traversal (state changed) + // AND transaction (list changed) + flags |= eTransactionNeeded|eTraversalNeeded; + } + } + if (what & layer_state_t::eSizeChanged) { + if (layer->setSize(s.w, s.h)) { + flags |= eTraversalNeeded; + } + } + if (what & layer_state_t::eAlphaChanged) { + if (layer->setAlpha(uint8_t(255.0f*s.alpha+0.5f))) + flags |= eTraversalNeeded; + } + if (what & layer_state_t::eMatrixChanged) { + if (layer->setMatrix(s.matrix)) + flags |= eTraversalNeeded; + } + if (what & layer_state_t::eTransparentRegionChanged) { + if (layer->setTransparentRegionHint(s.transparentRegion)) + flags |= eTraversalNeeded; + } + if (what & layer_state_t::eVisibilityChanged) { + if (layer->setFlags(s.flags, s.mask)) + flags |= eTraversalNeeded; + } + if (what & layer_state_t::eCropChanged) { + if (layer->setCrop(s.crop)) + flags |= eTraversalNeeded; + } + if (what & layer_state_t::eLayerStackChanged) { + // NOTE: index needs to be calculated before we update the state + ssize_t idx = mCurrentState.layersSortedByZ.indexOf(layer); + if (layer->setLayerStack(s.layerStack)) { + mCurrentState.layersSortedByZ.removeAt(idx); + mCurrentState.layersSortedByZ.add(layer); + // we need traversal (state changed) + // AND transaction (list changed) + flags |= eTransactionNeeded|eTraversalNeeded; + } + } + } + return flags; +} + +sp<ISurface> SurfaceFlinger::createLayer( ISurfaceComposerClient::surface_data_t* params, const String8& name, const sp<Client>& client, - DisplayID d, uint32_t w, uint32_t h, PixelFormat format, + uint32_t w, uint32_t h, PixelFormat format, uint32_t flags) { sp<LayerBaseClient> layer; sp<ISurface> surfaceHandle; if (int32_t(w|h) < 0) { - ALOGE("createSurface() failed, w or h is negative (w=%d, h=%d)", + ALOGE("createLayer() failed, w or h is negative (w=%d, h=%d)", int(w), int(h)); return surfaceHandle; } - //ALOGD("createSurface for (%d x %d), name=%s", w, h, name.string()); - sp<Layer> normalLayer; - switch (flags & eFXSurfaceMask) { - case eFXSurfaceNormal: - normalLayer = createNormalSurface(client, d, w, h, flags, format); - layer = normalLayer; + //ALOGD("createLayer for (%d x %d), name=%s", w, h, name.string()); + switch (flags & ISurfaceComposerClient::eFXSurfaceMask) { + case ISurfaceComposerClient::eFXSurfaceNormal: + layer = createNormalLayer(client, w, h, flags, format); break; - case eFXSurfaceBlur: - // for now we treat Blur as Dim, until we can implement it - // efficiently. - case eFXSurfaceDim: - layer = createDimSurface(client, d, w, h, flags); + case ISurfaceComposerClient::eFXSurfaceBlur: + case ISurfaceComposerClient::eFXSurfaceDim: + layer = createDimLayer(client, w, h, flags); break; - case eFXSurfaceScreenshot: - layer = createScreenshotSurface(client, d, w, h, flags); + case ISurfaceComposerClient::eFXSurfaceScreenshot: + layer = createScreenshotLayer(client, w, h, flags); break; } @@ -1204,30 +1935,24 @@ sp<ISurface> SurfaceFlinger::createSurface( layer->initStates(w, h, flags); layer->setName(name); ssize_t token = addClientLayer(client, layer); - surfaceHandle = layer->getSurface(); if (surfaceHandle != 0) { params->token = token; params->identity = layer->getIdentity(); - if (normalLayer != 0) { - Mutex::Autolock _l(mStateLock); - mLayerMap.add(layer->getSurfaceBinder(), normalLayer); - } } - setTransactionFlags(eTransactionNeeded); } return surfaceHandle; } -sp<Layer> SurfaceFlinger::createNormalSurface( - const sp<Client>& client, DisplayID display, +sp<Layer> SurfaceFlinger::createNormalLayer( + const sp<Client>& client, uint32_t w, uint32_t h, uint32_t flags, PixelFormat& format) { // initialize the surfaces - switch (format) { // TODO: take h/w into account + switch (format) { case PIXEL_FORMAT_TRANSPARENT: case PIXEL_FORMAT_TRANSLUCENT: format = PIXEL_FORMAT_RGBA_8888; @@ -1246,32 +1971,32 @@ sp<Layer> SurfaceFlinger::createNormalSurface( format = PIXEL_FORMAT_RGBA_8888; #endif - sp<Layer> layer = new Layer(this, display, client); + sp<Layer> layer = new Layer(this, client); status_t err = layer->setBuffers(w, h, format, flags); if (CC_LIKELY(err != NO_ERROR)) { - ALOGE("createNormalSurfaceLocked() failed (%s)", strerror(-err)); + ALOGE("createNormalLayer() failed (%s)", strerror(-err)); layer.clear(); } return layer; } -sp<LayerDim> SurfaceFlinger::createDimSurface( - const sp<Client>& client, DisplayID display, +sp<LayerDim> SurfaceFlinger::createDimLayer( + const sp<Client>& client, uint32_t w, uint32_t h, uint32_t flags) { - sp<LayerDim> layer = new LayerDim(this, display, client); + sp<LayerDim> layer = new LayerDim(this, client); return layer; } -sp<LayerScreenshot> SurfaceFlinger::createScreenshotSurface( - const sp<Client>& client, DisplayID display, +sp<LayerScreenshot> SurfaceFlinger::createScreenshotLayer( + const sp<Client>& client, uint32_t w, uint32_t h, uint32_t flags) { - sp<LayerScreenshot> layer = new LayerScreenshot(this, display, client); + sp<LayerScreenshot> layer = new LayerScreenshot(this, client); return layer; } -status_t SurfaceFlinger::removeSurface(const sp<Client>& client, SurfaceID sid) +status_t SurfaceFlinger::onLayerRemoved(const sp<Client>& client, SurfaceID sid) { /* * called by the window manager, when a surface should be marked for @@ -1295,7 +2020,7 @@ status_t SurfaceFlinger::removeSurface(const sp<Client>& client, SurfaceID sid) return err; } -status_t SurfaceFlinger::destroySurface(const wp<LayerBaseClient>& layer) +status_t SurfaceFlinger::onLayerDestroyed(const wp<LayerBaseClient>& layer) { // called by ~ISurface() when all references are gone status_t err = NO_ERROR; @@ -1317,104 +2042,126 @@ status_t SurfaceFlinger::destroySurface(const wp<LayerBaseClient>& layer) return err; } -uint32_t SurfaceFlinger::setClientStateLocked( - const sp<Client>& client, - const layer_state_t& s) -{ - uint32_t flags = 0; - sp<LayerBaseClient> layer(client->getLayerUser(s.surface)); - if (layer != 0) { - const uint32_t what = s.what; - if (what & ePositionChanged) { - if (layer->setPosition(s.x, s.y)) - flags |= eTraversalNeeded; - } - if (what & eLayerChanged) { - ssize_t idx = mCurrentState.layersSortedByZ.indexOf(layer); - if (layer->setLayer(s.z)) { - mCurrentState.layersSortedByZ.removeAt(idx); - mCurrentState.layersSortedByZ.add(layer); - // we need traversal (state changed) - // AND transaction (list changed) - flags |= eTransactionNeeded|eTraversalNeeded; - } - } - if (what & eSizeChanged) { - if (layer->setSize(s.w, s.h)) { - flags |= eTraversalNeeded; - } - } - if (what & eAlphaChanged) { - if (layer->setAlpha(uint8_t(255.0f*s.alpha+0.5f))) - flags |= eTraversalNeeded; - } - if (what & eMatrixChanged) { - if (layer->setMatrix(s.matrix)) - flags |= eTraversalNeeded; - } - if (what & eTransparentRegionChanged) { - if (layer->setTransparentRegionHint(s.transparentRegion)) - flags |= eTraversalNeeded; - } - if (what & eVisibilityChanged) { - if (layer->setFlags(s.flags, s.mask)) - flags |= eTraversalNeeded; - } - if (what & eCropChanged) { - if (layer->setCrop(s.crop)) - flags |= eTraversalNeeded; +// --------------------------------------------------------------------------- + +void SurfaceFlinger::onInitializeDisplays() { + // reset screen orientation + Vector<ComposerState> state; + Vector<DisplayState> displays; + DisplayState d; + d.what = DisplayState::eDisplayProjectionChanged; + d.token = mBuiltinDisplays[DisplayDevice::DISPLAY_PRIMARY]; + d.orientation = DisplayState::eOrientationDefault; + d.frame.makeInvalid(); + d.viewport.makeInvalid(); + displays.add(d); + setTransactionState(state, displays, 0); + onScreenAcquired(getDefaultDisplayDevice()); +} + +void SurfaceFlinger::initializeDisplays() { + class MessageScreenInitialized : public MessageBase { + SurfaceFlinger* flinger; + public: + MessageScreenInitialized(SurfaceFlinger* flinger) : flinger(flinger) { } + virtual bool handler() { + flinger->onInitializeDisplays(); + return true; } - } - return flags; + }; + sp<MessageBase> msg = new MessageScreenInitialized(this); + postMessageAsync(msg); // we may be called from main thread, use async message } -// --------------------------------------------------------------------------- -void SurfaceFlinger::onScreenAcquired() { - const DisplayHardware& hw(graphicPlane(0).displayHardware()); - hw.acquireScreen(); - mEventThread->onScreenAcquired(); - // this is a temporary work-around, eventually this should be called - // by the power-manager - SurfaceFlinger::turnElectronBeamOn(mElectronBeamAnimationMode); - // from this point on, SF will process updates again +void SurfaceFlinger::onScreenAcquired(const sp<const DisplayDevice>& hw) { + ALOGD("Screen acquired, type=%d flinger=%p", hw->getDisplayType(), this); + if (hw->isScreenAcquired()) { + // this is expected, e.g. when power manager wakes up during boot + ALOGD(" screen was previously acquired"); + return; + } + + hw->acquireScreen(); + int32_t type = hw->getDisplayType(); + if (type < DisplayDevice::NUM_DISPLAY_TYPES) { + // built-in display, tell the HWC + getHwComposer().acquire(type); + + if (type == DisplayDevice::DISPLAY_PRIMARY) { + // FIXME: eventthread only knows about the main display right now + mEventThread->onScreenAcquired(); + } + } + mVisibleRegionsDirty = true; repaintEverything(); } -void SurfaceFlinger::onScreenReleased() { - const DisplayHardware& hw(graphicPlane(0).displayHardware()); - if (hw.isScreenAcquired()) { - mEventThread->onScreenReleased(); - hw.releaseScreen(); - // from this point on, SF will stop drawing +void SurfaceFlinger::onScreenReleased(const sp<const DisplayDevice>& hw) { + ALOGD("Screen released, type=%d flinger=%p", hw->getDisplayType(), this); + if (!hw->isScreenAcquired()) { + ALOGD(" screen was previously released"); + return; + } + + hw->releaseScreen(); + int32_t type = hw->getDisplayType(); + if (type < DisplayDevice::NUM_DISPLAY_TYPES) { + if (type == DisplayDevice::DISPLAY_PRIMARY) { + // FIXME: eventthread only knows about the main display right now + mEventThread->onScreenReleased(); + } + + // built-in display, tell the HWC + getHwComposer().release(type); } + mVisibleRegionsDirty = true; + // from this point on, SF will stop drawing on this display } -void SurfaceFlinger::screenAcquired() { +void SurfaceFlinger::unblank(const sp<IBinder>& display) { class MessageScreenAcquired : public MessageBase { - SurfaceFlinger* flinger; + SurfaceFlinger& mFlinger; + sp<IBinder> mDisplay; public: - MessageScreenAcquired(SurfaceFlinger* flinger) : flinger(flinger) { } + MessageScreenAcquired(SurfaceFlinger& flinger, + const sp<IBinder>& disp) : mFlinger(flinger), mDisplay(disp) { } virtual bool handler() { - flinger->onScreenAcquired(); + const sp<DisplayDevice> hw(mFlinger.getDisplayDevice(mDisplay)); + if (hw == NULL) { + ALOGE("Attempt to unblank null display %p", mDisplay.get()); + } else if (hw->getDisplayType() >= DisplayDevice::NUM_DISPLAY_TYPES) { + ALOGW("Attempt to unblank virtual display"); + } else { + mFlinger.onScreenAcquired(hw); + } return true; } }; - sp<MessageBase> msg = new MessageScreenAcquired(this); + sp<MessageBase> msg = new MessageScreenAcquired(*this, display); postMessageSync(msg); } -void SurfaceFlinger::screenReleased() { +void SurfaceFlinger::blank(const sp<IBinder>& display) { class MessageScreenReleased : public MessageBase { - SurfaceFlinger* flinger; + SurfaceFlinger& mFlinger; + sp<IBinder> mDisplay; public: - MessageScreenReleased(SurfaceFlinger* flinger) : flinger(flinger) { } + MessageScreenReleased(SurfaceFlinger& flinger, + const sp<IBinder>& disp) : mFlinger(flinger), mDisplay(disp) { } virtual bool handler() { - flinger->onScreenReleased(); + const sp<DisplayDevice> hw(mFlinger.getDisplayDevice(mDisplay)); + if (hw == NULL) { + ALOGE("Attempt to blank null display %p", mDisplay.get()); + } else if (hw->getDisplayType() >= DisplayDevice::NUM_DISPLAY_TYPES) { + ALOGW("Attempt to blank virtual display"); + } else { + mFlinger.onScreenReleased(hw); + } return true; } }; - sp<MessageBase> msg = new MessageScreenReleased(this); + sp<MessageBase> msg = new MessageScreenReleased(*this, display); postMessageSync(msg); } @@ -1540,6 +2287,26 @@ void SurfaceFlinger::clearStatsLocked(const Vector<String16>& args, size_t& inde } } +/*static*/ void SurfaceFlinger::appendSfConfigString(String8& result) +{ + static const char* config = + " [sf" +#ifdef NO_RGBX_8888 + " NO_RGBX_8888" +#endif +#ifdef HAS_CONTEXT_PRIORITY + " HAS_CONTEXT_PRIORITY" +#endif +#ifdef NEVER_DEFAULT_TO_ASYNC_MODE + " NEVER_DEFAULT_TO_ASYNC_MODE" +#endif +#ifdef TARGET_DISABLE_TRIPLE_BUFFERING + " TARGET_DISABLE_TRIPLE_BUFFERING" +#endif + "]"; + result.append(config); +} + void SurfaceFlinger::dumpAllLocked( String8& result, char* buffer, size_t SIZE) const { @@ -1551,6 +2318,15 @@ void SurfaceFlinger::dumpAllLocked( nsecs_t inTransactionDuration = (inTransaction) ? now-inTransaction : 0; /* + * Dump library configuration. + */ + result.append("Build configuration:"); + appendSfConfigString(result); + appendUiConfigString(result); + appendGuiConfigString(result); + result.append("\n"); + + /* * Dump the visible layer list */ const LayerVector& currentLayers = mCurrentState.layersSortedByZ; @@ -1575,12 +2351,25 @@ void SurfaceFlinger::dumpAllLocked( } /* + * Dump Display state + */ + + snprintf(buffer, SIZE, "Displays (%d entries)\n", mDisplays.size()); + result.append(buffer); + for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) { + const sp<const DisplayDevice>& hw(mDisplays[dpy]); + hw->dump(result, buffer, SIZE); + } + + /* * Dump SurfaceFlinger global state */ snprintf(buffer, SIZE, "SurfaceFlinger global state:\n"); result.append(buffer); + HWComposer& hwc(getHwComposer()); + sp<const DisplayDevice> hw(getDefaultDisplayDevice()); const GLExtensions& extensions(GLExtensions::getInstance()); snprintf(buffer, SIZE, "GLES: %s, %s, %s\n", extensions.getVendor(), @@ -1589,18 +2378,16 @@ void SurfaceFlinger::dumpAllLocked( result.append(buffer); snprintf(buffer, SIZE, "EGL : %s\n", - eglQueryString(graphicPlane(0).getEGLDisplay(), - EGL_VERSION_HW_ANDROID)); + eglQueryString(mEGLDisplay, EGL_VERSION_HW_ANDROID)); result.append(buffer); snprintf(buffer, SIZE, "EXTS: %s\n", extensions.getExtension()); result.append(buffer); - mWormholeRegion.dump(result, "WormholeRegion"); - const DisplayHardware& hw(graphicPlane(0).displayHardware()); + hw->undefinedRegion.dump(result, "undefinedRegion"); snprintf(buffer, SIZE, " orientation=%d, canDraw=%d\n", - mCurrentState.orientation, hw.canDraw()); + hw->getOrientation(), hw->canDraw()); result.append(buffer); snprintf(buffer, SIZE, " last eglSwapBuffers() time: %f us\n" @@ -1608,15 +2395,13 @@ void SurfaceFlinger::dumpAllLocked( " transaction-flags : %08x\n" " refresh-rate : %f fps\n" " x-dpi : %f\n" - " y-dpi : %f\n" - " density : %f\n", + " y-dpi : %f\n", mLastSwapBufferTime/1000.0, mLastTransactionTime/1000.0, mTransactionFlags, - hw.getRefreshRate(), - hw.getDpiX(), - hw.getDpiY(), - hw.getDensity()); + 1e9 / hwc.getRefreshPeriod(HWC_DISPLAY_PRIMARY), + hwc.getDpiX(HWC_DISPLAY_PRIMARY), + hwc.getDpiY(HWC_DISPLAY_PRIMARY)); result.append(buffer); snprintf(buffer, SIZE, " eglSwapBuffers time: %f us\n", @@ -1635,21 +2420,43 @@ void SurfaceFlinger::dumpAllLocked( /* * Dump HWComposer state */ - HWComposer& hwc(hw.getHwComposer()); snprintf(buffer, SIZE, "h/w composer state:\n"); result.append(buffer); snprintf(buffer, SIZE, " h/w composer %s and %s\n", hwc.initCheck()==NO_ERROR ? "present" : "not present", (mDebugDisableHWC || mDebugRegion) ? "disabled" : "enabled"); result.append(buffer); - hwc.dump(result, buffer, SIZE, mVisibleLayersSortedByZ); + hwc.dump(result, buffer, SIZE); /* * Dump gralloc state */ const GraphicBufferAllocator& alloc(GraphicBufferAllocator::get()); alloc.dump(result); - hw.dump(result); +} + +const Vector< sp<LayerBase> >& +SurfaceFlinger::getLayerSortedByZForHwcDisplay(int disp) { + // Note: mStateLock is held here + return getDisplayDevice( getBuiltInDisplay(disp) )->getVisibleLayersSortedByZ(); +} + +bool SurfaceFlinger::startDdmConnection() +{ + void* libddmconnection_dso = + dlopen("libsurfaceflinger_ddmconnection.so", RTLD_NOW); + if (!libddmconnection_dso) { + return false; + } + void (*DdmConnection_start)(const char* name); + DdmConnection_start = + (typeof DdmConnection_start)dlsym(libddmconnection_dso, "DdmConnection_start"); + if (!DdmConnection_start) { + dlclose(libddmconnection_dso); + return false; + } + (*DdmConnection_start)(getServiceName()); + return true; } status_t SurfaceFlinger::onTransact( @@ -1658,10 +2465,9 @@ status_t SurfaceFlinger::onTransact( switch (code) { case CREATE_CONNECTION: case SET_TRANSACTION_STATE: - case SET_ORIENTATION: case BOOT_FINISHED: - case TURN_ELECTRON_BEAM_OFF: - case TURN_ELECTRON_BEAM_ON: + case BLANK: + case UNBLANK: { // codes that require permission check IPCThreadState* ipc = IPCThreadState::self(); @@ -1718,7 +2524,10 @@ status_t SurfaceFlinger::onTransact( return NO_ERROR; } case 1005:{ // force transaction - setTransactionFlags(eTransactionNeeded|eTraversalNeeded); + setTransactionFlags( + eTransactionNeeded| + eDisplayTransactionNeeded| + eTraversalNeeded); return NO_ERROR; } case 1006:{ // send empty update @@ -1746,8 +2555,8 @@ status_t SurfaceFlinger::onTransact( return NO_ERROR; case 1013: { Mutex::Autolock _l(mStateLock); - const DisplayHardware& hw(graphicPlane(0).displayHardware()); - reply->writeInt32(hw.getPageFlipCount()); + sp<const DisplayDevice> hw(getDefaultDisplayDevice()); + reply->writeInt32(hw->getPageFlipCount()); } return NO_ERROR; } @@ -1756,34 +2565,20 @@ status_t SurfaceFlinger::onTransact( } void SurfaceFlinger::repaintEverything() { - const DisplayHardware& hw(graphicPlane(0).displayHardware()); - const Rect bounds(hw.getBounds()); - setInvalidateRegion(Region(bounds)); + android_atomic_or(1, &mRepaintEverything); signalTransaction(); } -void SurfaceFlinger::setInvalidateRegion(const Region& reg) { - Mutex::Autolock _l(mInvalidateLock); - mInvalidateRegion = reg; -} - -Region SurfaceFlinger::getAndClearInvalidateRegion() { - Mutex::Autolock _l(mInvalidateLock); - Region reg(mInvalidateRegion); - mInvalidateRegion.clear(); - return reg; -} - // --------------------------------------------------------------------------- -status_t SurfaceFlinger::renderScreenToTexture(DisplayID dpy, +status_t SurfaceFlinger::renderScreenToTexture(uint32_t layerStack, GLuint* textureName, GLfloat* uOut, GLfloat* vOut) { Mutex::Autolock _l(mStateLock); - return renderScreenToTextureLocked(dpy, textureName, uOut, vOut); + return renderScreenToTextureLocked(layerStack, textureName, uOut, vOut); } -status_t SurfaceFlinger::renderScreenToTextureLocked(DisplayID dpy, +status_t SurfaceFlinger::renderScreenToTextureLocked(uint32_t layerStack, GLuint* textureName, GLfloat* uOut, GLfloat* vOut) { ATRACE_CALL(); @@ -1792,9 +2587,10 @@ status_t SurfaceFlinger::renderScreenToTextureLocked(DisplayID dpy, return INVALID_OPERATION; // get screen geometry - const DisplayHardware& hw(graphicPlane(dpy).displayHardware()); - const uint32_t hw_w = hw.getWidth(); - const uint32_t hw_h = hw.getHeight(); + // FIXME: figure out what it means to have a screenshot texture w/ multi-display + sp<const DisplayDevice> hw(getDefaultDisplayDevice()); + const uint32_t hw_w = hw->getWidth(); + const uint32_t hw_h = hw->getHeight(); GLfloat u = 1; GLfloat v = 1; @@ -1823,6 +2619,8 @@ status_t SurfaceFlinger::renderScreenToTextureLocked(DisplayID dpy, glFramebufferTexture2DOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_TEXTURE_2D, tname, 0); + DisplayDevice::setViewportAndProjection(hw); + // redraw the screen entirely... glDisable(GL_TEXTURE_EXTERNAL_OES); glDisable(GL_TEXTURE_2D); @@ -1830,14 +2628,14 @@ status_t SurfaceFlinger::renderScreenToTextureLocked(DisplayID dpy, glClear(GL_COLOR_BUFFER_BIT); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); - const Vector< sp<LayerBase> >& layers(mVisibleLayersSortedByZ); + const Vector< sp<LayerBase> >& layers(hw->getVisibleLayersSortedByZ()); const size_t count = layers.size(); for (size_t i=0 ; i<count ; ++i) { const sp<LayerBase>& layer(layers[i]); - layer->drawForSreenShot(); + layer->draw(hw); } - hw.compositionComplete(); + hw->compositionComplete(); // back to main framebuffer glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0); @@ -1851,472 +2649,7 @@ status_t SurfaceFlinger::renderScreenToTextureLocked(DisplayID dpy, // --------------------------------------------------------------------------- -class VSyncWaiter { - DisplayEventReceiver::Event buffer[4]; - sp<Looper> looper; - sp<IDisplayEventConnection> events; - sp<BitTube> eventTube; -public: - VSyncWaiter(const sp<EventThread>& eventThread) { - looper = new Looper(true); - events = eventThread->createEventConnection(); - eventTube = events->getDataChannel(); - looper->addFd(eventTube->getFd(), 0, ALOOPER_EVENT_INPUT, 0, 0); - events->requestNextVsync(); - } - - void wait() { - ssize_t n; - - looper->pollOnce(-1); - // we don't handle any errors here, it doesn't matter - // and we don't want to take the risk to get stuck. - - // drain the events... - while ((n = DisplayEventReceiver::getEvents( - eventTube, buffer, 4)) > 0) ; - - events->requestNextVsync(); - } -}; - -status_t SurfaceFlinger::electronBeamOffAnimationImplLocked() -{ - // get screen geometry - const DisplayHardware& hw(graphicPlane(0).displayHardware()); - const uint32_t hw_w = hw.getWidth(); - const uint32_t hw_h = hw.getHeight(); - const Region screenBounds(hw.getBounds()); - - GLfloat u, v; - GLuint tname; - status_t result = renderScreenToTextureLocked(0, &tname, &u, &v); - if (result != NO_ERROR) { - return result; - } - - GLfloat vtx[8]; - const GLfloat texCoords[4][2] = { {0,0}, {0,v}, {u,v}, {u,0} }; - glBindTexture(GL_TEXTURE_2D, tname); - glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); - glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexCoordPointer(2, GL_FLOAT, 0, texCoords); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glVertexPointer(2, GL_FLOAT, 0, vtx); - - /* - * Texture coordinate mapping - * - * u - * 1 +----------+---+ - * | | | | image is inverted - * | V | | w.r.t. the texture - * 1-v +----------+ | coordinates - * | | - * | | - * | | - * 0 +--------------+ - * 0 1 - * - */ - - class s_curve_interpolator { - const float nbFrames, s, v; - public: - s_curve_interpolator(int nbFrames, float s) - : nbFrames(1.0f / (nbFrames-1)), s(s), - v(1.0f + expf(-s + 0.5f*s)) { - } - float operator()(int f) { - const float x = f * nbFrames; - return ((1.0f/(1.0f + expf(-x*s + 0.5f*s))) - 0.5f) * v + 0.5f; - } - }; - - class v_stretch { - const GLfloat hw_w, hw_h; - public: - v_stretch(uint32_t hw_w, uint32_t hw_h) - : hw_w(hw_w), hw_h(hw_h) { - } - void operator()(GLfloat* vtx, float v) { - const GLfloat w = hw_w + (hw_w * v); - const GLfloat h = hw_h - (hw_h * v); - const GLfloat x = (hw_w - w) * 0.5f; - const GLfloat y = (hw_h - h) * 0.5f; - vtx[0] = x; vtx[1] = y; - vtx[2] = x; vtx[3] = y + h; - vtx[4] = x + w; vtx[5] = y + h; - vtx[6] = x + w; vtx[7] = y; - } - }; - - class h_stretch { - const GLfloat hw_w, hw_h; - public: - h_stretch(uint32_t hw_w, uint32_t hw_h) - : hw_w(hw_w), hw_h(hw_h) { - } - void operator()(GLfloat* vtx, float v) { - const GLfloat w = hw_w - (hw_w * v); - const GLfloat h = 1.0f; - const GLfloat x = (hw_w - w) * 0.5f; - const GLfloat y = (hw_h - h) * 0.5f; - vtx[0] = x; vtx[1] = y; - vtx[2] = x; vtx[3] = y + h; - vtx[4] = x + w; vtx[5] = y + h; - vtx[6] = x + w; vtx[7] = y; - } - }; - - VSyncWaiter vsync(mEventThread); - - // the full animation is 24 frames - char value[PROPERTY_VALUE_MAX]; - property_get("debug.sf.electron_frames", value, "24"); - int nbFrames = (atoi(value) + 1) >> 1; - if (nbFrames <= 0) // just in case - nbFrames = 24; - - s_curve_interpolator itr(nbFrames, 7.5f); - s_curve_interpolator itg(nbFrames, 8.0f); - s_curve_interpolator itb(nbFrames, 8.5f); - - v_stretch vverts(hw_w, hw_h); - - glMatrixMode(GL_TEXTURE); - glLoadIdentity(); - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - - glEnable(GL_BLEND); - glBlendFunc(GL_ONE, GL_ONE); - for (int i=0 ; i<nbFrames ; i++) { - float x, y, w, h; - const float vr = itr(i); - const float vg = itg(i); - const float vb = itb(i); - - // wait for vsync - vsync.wait(); - - // clear screen - glColorMask(1,1,1,1); - glClear(GL_COLOR_BUFFER_BIT); - glEnable(GL_TEXTURE_2D); - - // draw the red plane - vverts(vtx, vr); - glColorMask(1,0,0,1); - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - - // draw the green plane - vverts(vtx, vg); - glColorMask(0,1,0,1); - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - - // draw the blue plane - vverts(vtx, vb); - glColorMask(0,0,1,1); - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - - // draw the white highlight (we use the last vertices) - glDisable(GL_TEXTURE_2D); - glColorMask(1,1,1,1); - glColor4f(vg, vg, vg, 1); - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - hw.flip(screenBounds); - } - - h_stretch hverts(hw_w, hw_h); - glDisable(GL_BLEND); - glDisable(GL_TEXTURE_2D); - glColorMask(1,1,1,1); - for (int i=0 ; i<nbFrames ; i++) { - const float v = itg(i); - hverts(vtx, v); - - // wait for vsync - vsync.wait(); - - glClear(GL_COLOR_BUFFER_BIT); - glColor4f(1-v, 1-v, 1-v, 1); - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - hw.flip(screenBounds); - } - - glColorMask(1,1,1,1); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - glDeleteTextures(1, &tname); - glDisable(GL_TEXTURE_2D); - glDisable(GL_BLEND); - return NO_ERROR; -} - -status_t SurfaceFlinger::electronBeamOnAnimationImplLocked() -{ - status_t result = PERMISSION_DENIED; - - if (!GLExtensions::getInstance().haveFramebufferObject()) - return INVALID_OPERATION; - - - // get screen geometry - const DisplayHardware& hw(graphicPlane(0).displayHardware()); - const uint32_t hw_w = hw.getWidth(); - const uint32_t hw_h = hw.getHeight(); - const Region screenBounds(hw.bounds()); - - GLfloat u, v; - GLuint tname; - result = renderScreenToTextureLocked(0, &tname, &u, &v); - if (result != NO_ERROR) { - return result; - } - - GLfloat vtx[8]; - const GLfloat texCoords[4][2] = { {0,v}, {0,0}, {u,0}, {u,v} }; - glBindTexture(GL_TEXTURE_2D, tname); - glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexCoordPointer(2, GL_FLOAT, 0, texCoords); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glVertexPointer(2, GL_FLOAT, 0, vtx); - - class s_curve_interpolator { - const float nbFrames, s, v; - public: - s_curve_interpolator(int nbFrames, float s) - : nbFrames(1.0f / (nbFrames-1)), s(s), - v(1.0f + expf(-s + 0.5f*s)) { - } - float operator()(int f) { - const float x = f * nbFrames; - return ((1.0f/(1.0f + expf(-x*s + 0.5f*s))) - 0.5f) * v + 0.5f; - } - }; - - class v_stretch { - const GLfloat hw_w, hw_h; - public: - v_stretch(uint32_t hw_w, uint32_t hw_h) - : hw_w(hw_w), hw_h(hw_h) { - } - void operator()(GLfloat* vtx, float v) { - const GLfloat w = hw_w + (hw_w * v); - const GLfloat h = hw_h - (hw_h * v); - const GLfloat x = (hw_w - w) * 0.5f; - const GLfloat y = (hw_h - h) * 0.5f; - vtx[0] = x; vtx[1] = y; - vtx[2] = x; vtx[3] = y + h; - vtx[4] = x + w; vtx[5] = y + h; - vtx[6] = x + w; vtx[7] = y; - } - }; - - class h_stretch { - const GLfloat hw_w, hw_h; - public: - h_stretch(uint32_t hw_w, uint32_t hw_h) - : hw_w(hw_w), hw_h(hw_h) { - } - void operator()(GLfloat* vtx, float v) { - const GLfloat w = hw_w - (hw_w * v); - const GLfloat h = 1.0f; - const GLfloat x = (hw_w - w) * 0.5f; - const GLfloat y = (hw_h - h) * 0.5f; - vtx[0] = x; vtx[1] = y; - vtx[2] = x; vtx[3] = y + h; - vtx[4] = x + w; vtx[5] = y + h; - vtx[6] = x + w; vtx[7] = y; - } - }; - - VSyncWaiter vsync(mEventThread); - - // the full animation is 12 frames - int nbFrames = 8; - s_curve_interpolator itr(nbFrames, 7.5f); - s_curve_interpolator itg(nbFrames, 8.0f); - s_curve_interpolator itb(nbFrames, 8.5f); - - h_stretch hverts(hw_w, hw_h); - glDisable(GL_BLEND); - glDisable(GL_TEXTURE_2D); - glColorMask(1,1,1,1); - for (int i=nbFrames-1 ; i>=0 ; i--) { - const float v = itg(i); - hverts(vtx, v); - - // wait for vsync - vsync.wait(); - - glClear(GL_COLOR_BUFFER_BIT); - glColor4f(1-v, 1-v, 1-v, 1); - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - hw.flip(screenBounds); - } - - nbFrames = 4; - v_stretch vverts(hw_w, hw_h); - glEnable(GL_BLEND); - glBlendFunc(GL_ONE, GL_ONE); - for (int i=nbFrames-1 ; i>=0 ; i--) { - float x, y, w, h; - const float vr = itr(i); - const float vg = itg(i); - const float vb = itb(i); - - // wait for vsync - vsync.wait(); - - // clear screen - glColorMask(1,1,1,1); - glClear(GL_COLOR_BUFFER_BIT); - glEnable(GL_TEXTURE_2D); - - // draw the red plane - vverts(vtx, vr); - glColorMask(1,0,0,1); - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - - // draw the green plane - vverts(vtx, vg); - glColorMask(0,1,0,1); - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - - // draw the blue plane - vverts(vtx, vb); - glColorMask(0,0,1,1); - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - - hw.flip(screenBounds); - } - - glColorMask(1,1,1,1); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - glDeleteTextures(1, &tname); - glDisable(GL_TEXTURE_2D); - glDisable(GL_BLEND); - - return NO_ERROR; -} - -// --------------------------------------------------------------------------- - -status_t SurfaceFlinger::turnElectronBeamOffImplLocked(int32_t mode) -{ - ATRACE_CALL(); - - DisplayHardware& hw(graphicPlane(0).editDisplayHardware()); - if (!hw.canDraw()) { - // we're already off - return NO_ERROR; - } - - // turn off hwc while we're doing the animation - hw.getHwComposer().disable(); - // and make sure to turn it back on (if needed) next time we compose - invalidateHwcGeometry(); - - if (mode & ISurfaceComposer::eElectronBeamAnimationOff) { - electronBeamOffAnimationImplLocked(); - } - - // always clear the whole screen at the end of the animation - glClearColor(0,0,0,1); - glClear(GL_COLOR_BUFFER_BIT); - hw.flip( Region(hw.bounds()) ); - - return NO_ERROR; -} - -status_t SurfaceFlinger::turnElectronBeamOff(int32_t mode) -{ - class MessageTurnElectronBeamOff : public MessageBase { - SurfaceFlinger* flinger; - int32_t mode; - status_t result; - public: - MessageTurnElectronBeamOff(SurfaceFlinger* flinger, int32_t mode) - : flinger(flinger), mode(mode), result(PERMISSION_DENIED) { - } - status_t getResult() const { - return result; - } - virtual bool handler() { - Mutex::Autolock _l(flinger->mStateLock); - result = flinger->turnElectronBeamOffImplLocked(mode); - return true; - } - }; - - sp<MessageBase> msg = new MessageTurnElectronBeamOff(this, mode); - status_t res = postMessageSync(msg); - if (res == NO_ERROR) { - res = static_cast<MessageTurnElectronBeamOff*>( msg.get() )->getResult(); - - // work-around: when the power-manager calls us we activate the - // animation. eventually, the "on" animation will be called - // by the power-manager itself - mElectronBeamAnimationMode = mode; - } - return res; -} - -// --------------------------------------------------------------------------- - -status_t SurfaceFlinger::turnElectronBeamOnImplLocked(int32_t mode) -{ - DisplayHardware& hw(graphicPlane(0).editDisplayHardware()); - if (hw.canDraw()) { - // we're already on - return NO_ERROR; - } - if (mode & ISurfaceComposer::eElectronBeamAnimationOn) { - electronBeamOnAnimationImplLocked(); - } - - // make sure to redraw the whole screen when the animation is done - mDirtyRegion.set(hw.bounds()); - signalTransaction(); - - return NO_ERROR; -} - -status_t SurfaceFlinger::turnElectronBeamOn(int32_t mode) -{ - class MessageTurnElectronBeamOn : public MessageBase { - SurfaceFlinger* flinger; - int32_t mode; - status_t result; - public: - MessageTurnElectronBeamOn(SurfaceFlinger* flinger, int32_t mode) - : flinger(flinger), mode(mode), result(PERMISSION_DENIED) { - } - status_t getResult() const { - return result; - } - virtual bool handler() { - Mutex::Autolock _l(flinger->mStateLock); - result = flinger->turnElectronBeamOnImplLocked(mode); - return true; - } - }; - - postMessageAsync( new MessageTurnElectronBeamOn(this, mode) ); - return NO_ERROR; -} - -// --------------------------------------------------------------------------- - -status_t SurfaceFlinger::captureScreenImplLocked(DisplayID dpy, +status_t SurfaceFlinger::captureScreenImplLocked(const sp<IBinder>& display, sp<IMemoryHeap>* heap, uint32_t* w, uint32_t* h, PixelFormat* f, uint32_t sw, uint32_t sh, @@ -2326,27 +2659,33 @@ status_t SurfaceFlinger::captureScreenImplLocked(DisplayID dpy, status_t result = PERMISSION_DENIED; - // only one display supported for now - if (CC_UNLIKELY(uint32_t(dpy) >= DISPLAY_COUNT)) - return BAD_VALUE; - - if (!GLExtensions::getInstance().haveFramebufferObject()) + if (!GLExtensions::getInstance().haveFramebufferObject()) { return INVALID_OPERATION; + } // get screen geometry - const DisplayHardware& hw(graphicPlane(dpy).displayHardware()); - const uint32_t hw_w = hw.getWidth(); - const uint32_t hw_h = hw.getHeight(); + sp<const DisplayDevice> hw(getDisplayDevice(display)); + const uint32_t hw_w = hw->getWidth(); + const uint32_t hw_h = hw->getHeight(); - if ((sw > hw_w) || (sh > hw_h)) + // if we have secure windows on this display, never allow the screen capture + if (hw->getSecureLayerVisible()) { + ALOGW("FB is protected: PERMISSION_DENIED"); + return PERMISSION_DENIED; + } + + if ((sw > hw_w) || (sh > hw_h)) { + ALOGE("size mismatch (%d, %d) > (%d, %d)", sw, sh, hw_w, hw_h); return BAD_VALUE; + } sw = (!sw) ? hw_w : sw; sh = (!sh) ? hw_h : sh; const size_t size = sw * sh * 4; + const bool filtering = sw != hw_w || sh != hw_h; - //ALOGD("screenshot: sw=%d, sh=%d, minZ=%d, maxZ=%d", - // sw, sh, minLayerZ, maxLayerZ); +// ALOGD("screenshot: sw=%d, sh=%d, minZ=%d, maxZ=%d", +// sw, sh, minLayerZ, maxLayerZ); // make sure to clear all GL error flags while ( glGetError() != GL_NO_ERROR ) ; @@ -2367,6 +2706,8 @@ status_t SurfaceFlinger::captureScreenImplLocked(DisplayID dpy, if (status == GL_FRAMEBUFFER_COMPLETE_OES) { // invert everything, b/c glReadPixel() below will invert the FB + GLint viewport[4]; + glGetIntegerv(GL_VIEWPORT, viewport); glViewport(0, 0, sw, sh); glMatrixMode(GL_PROJECTION); glPushMatrix(); @@ -2378,16 +2719,15 @@ status_t SurfaceFlinger::captureScreenImplLocked(DisplayID dpy, glClearColor(0,0,0,1); glClear(GL_COLOR_BUFFER_BIT); - const LayerVector& layers(mDrawingState.layersSortedByZ); + const Vector< sp<LayerBase> >& layers(hw->getVisibleLayersSortedByZ()); const size_t count = layers.size(); for (size_t i=0 ; i<count ; ++i) { const sp<LayerBase>& layer(layers[i]); - const uint32_t flags = layer->drawingState().flags; - if (!(flags & ISurfaceComposer::eLayerHidden)) { - const uint32_t z = layer->drawingState().z; - if (z >= minLayerZ && z <= maxLayerZ) { - layer->drawForSreenShot(); - } + const uint32_t z = layer->drawingState().z; + if (z >= minLayerZ && z <= maxLayerZ) { + if (filtering) layer->setFiltering(true); + layer->draw(hw); + if (filtering) layer->setFiltering(false); } } @@ -2401,7 +2741,7 @@ status_t SurfaceFlinger::captureScreenImplLocked(DisplayID dpy, sp<MemoryHeapBase> base( new MemoryHeapBase(size, 0, "screen-capture") ); void* const ptr = base->getBase(); - if (ptr) { + if (ptr != MAP_FAILED) { // capture the screen with glReadPixels() ScopedTrace _t(ATRACE_TAG, "glReadPixels"); glReadPixels(0, 0, sw, sh, GL_RGBA, GL_UNSIGNED_BYTE, ptr); @@ -2416,7 +2756,7 @@ status_t SurfaceFlinger::captureScreenImplLocked(DisplayID dpy, result = NO_MEMORY; } } - glViewport(0, 0, hw_w, hw_h); + glViewport(viewport[0], viewport[1], viewport[2], viewport[3]); glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); @@ -2429,22 +2769,21 @@ status_t SurfaceFlinger::captureScreenImplLocked(DisplayID dpy, glDeleteRenderbuffersOES(1, &tname); glDeleteFramebuffersOES(1, &name); - hw.compositionComplete(); + hw->compositionComplete(); - // ALOGD("screenshot: result = %s", result<0 ? strerror(result) : "OK"); +// ALOGD("screenshot: result = %s", result<0 ? strerror(result) : "OK"); return result; } -status_t SurfaceFlinger::captureScreen(DisplayID dpy, +status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display, sp<IMemoryHeap>* heap, uint32_t* width, uint32_t* height, PixelFormat* format, uint32_t sw, uint32_t sh, uint32_t minLayerZ, uint32_t maxLayerZ) { - // only one display supported for now - if (CC_UNLIKELY(uint32_t(dpy) >= DISPLAY_COUNT)) + if (CC_UNLIKELY(display == 0)) return BAD_VALUE; if (!GLExtensions::getInstance().haveFramebufferObject()) @@ -2452,7 +2791,7 @@ status_t SurfaceFlinger::captureScreen(DisplayID dpy, class MessageCaptureScreen : public MessageBase { SurfaceFlinger* flinger; - DisplayID dpy; + sp<IBinder> display; sp<IMemoryHeap>* heap; uint32_t* w; uint32_t* h; @@ -2463,11 +2802,11 @@ status_t SurfaceFlinger::captureScreen(DisplayID dpy, uint32_t maxLayerZ; status_t result; public: - MessageCaptureScreen(SurfaceFlinger* flinger, DisplayID dpy, + MessageCaptureScreen(SurfaceFlinger* flinger, const sp<IBinder>& display, sp<IMemoryHeap>* heap, uint32_t* w, uint32_t* h, PixelFormat* f, uint32_t sw, uint32_t sh, uint32_t minLayerZ, uint32_t maxLayerZ) - : flinger(flinger), dpy(dpy), + : flinger(flinger), display(display), heap(heap), w(w), h(h), f(f), sw(sw), sh(sh), minLayerZ(minLayerZ), maxLayerZ(maxLayerZ), result(PERMISSION_DENIED) @@ -2478,20 +2817,14 @@ status_t SurfaceFlinger::captureScreen(DisplayID dpy, } virtual bool handler() { Mutex::Autolock _l(flinger->mStateLock); - - // if we have secure windows, never allow the screen capture - if (flinger->mSecureFrameBuffer) - return true; - - result = flinger->captureScreenImplLocked(dpy, + result = flinger->captureScreenImplLocked(display, heap, w, h, f, sw, sh, minLayerZ, maxLayerZ); - return true; } }; sp<MessageBase> msg = new MessageCaptureScreen(this, - dpy, heap, width, height, format, sw, sh, minLayerZ, maxLayerZ); + display, heap, width, height, format, sw, sh, minLayerZ, maxLayerZ); status_t res = postMessageSync(msg); if (res == NO_ERROR) { res = static_cast<MessageCaptureScreen*>( msg.get() )->getResult(); @@ -2501,281 +2834,43 @@ status_t SurfaceFlinger::captureScreen(DisplayID dpy, // --------------------------------------------------------------------------- -sp<Layer> SurfaceFlinger::getLayer(const sp<ISurface>& sur) const -{ - sp<Layer> result; - Mutex::Autolock _l(mStateLock); - result = mLayerMap.valueFor( sur->asBinder() ).promote(); - return result; +SurfaceFlinger::LayerVector::LayerVector() { } -// --------------------------------------------------------------------------- - -Client::Client(const sp<SurfaceFlinger>& flinger) - : mFlinger(flinger), mNameGenerator(1) -{ -} - -Client::~Client() -{ - const size_t count = mLayers.size(); - for (size_t i=0 ; i<count ; i++) { - sp<LayerBaseClient> layer(mLayers.valueAt(i).promote()); - if (layer != 0) { - mFlinger->removeLayer(layer); - } - } +SurfaceFlinger::LayerVector::LayerVector(const LayerVector& rhs) + : SortedVector<sp<LayerBase> >(rhs) { } -status_t Client::initCheck() const { - return NO_ERROR; -} - -size_t Client::attachLayer(const sp<LayerBaseClient>& layer) +int SurfaceFlinger::LayerVector::do_compare(const void* lhs, + const void* rhs) const { - Mutex::Autolock _l(mLock); - size_t name = mNameGenerator++; - mLayers.add(name, layer); - return name; -} + // sort layers per layer-stack, then by z-order and finally by sequence + const sp<LayerBase>& l(*reinterpret_cast<const sp<LayerBase>*>(lhs)); + const sp<LayerBase>& r(*reinterpret_cast<const sp<LayerBase>*>(rhs)); -void Client::detachLayer(const LayerBaseClient* layer) -{ - Mutex::Autolock _l(mLock); - // we do a linear search here, because this doesn't happen often - const size_t count = mLayers.size(); - for (size_t i=0 ; i<count ; i++) { - if (mLayers.valueAt(i) == layer) { - mLayers.removeItemsAt(i, 1); - break; - } - } -} -sp<LayerBaseClient> Client::getLayerUser(int32_t i) const -{ - Mutex::Autolock _l(mLock); - sp<LayerBaseClient> lbc; - wp<LayerBaseClient> layer(mLayers.valueFor(i)); - if (layer != 0) { - lbc = layer.promote(); - ALOGE_IF(lbc==0, "getLayerUser(name=%d) is dead", int(i)); - } - return lbc; -} + uint32_t ls = l->currentState().layerStack; + uint32_t rs = r->currentState().layerStack; + if (ls != rs) + return ls - rs; + uint32_t lz = l->currentState().z; + uint32_t rz = r->currentState().z; + if (lz != rz) + return lz - rz; -status_t Client::onTransact( - uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) -{ - // these must be checked - IPCThreadState* ipc = IPCThreadState::self(); - const int pid = ipc->getCallingPid(); - const int uid = ipc->getCallingUid(); - const int self_pid = getpid(); - if (CC_UNLIKELY(pid != self_pid && uid != AID_GRAPHICS && uid != 0)) { - // we're called from a different process, do the real check - if (!PermissionCache::checkCallingPermission(sAccessSurfaceFlinger)) - { - ALOGE("Permission Denial: " - "can't openGlobalTransaction pid=%d, uid=%d", pid, uid); - return PERMISSION_DENIED; - } - } - return BnSurfaceComposerClient::onTransact(code, data, reply, flags); -} - - -sp<ISurface> Client::createSurface( - ISurfaceComposerClient::surface_data_t* params, - const String8& name, - DisplayID display, uint32_t w, uint32_t h, PixelFormat format, - uint32_t flags) -{ - /* - * createSurface must be called from the GL thread so that it can - * have access to the GL context. - */ - - class MessageCreateSurface : public MessageBase { - sp<ISurface> result; - SurfaceFlinger* flinger; - ISurfaceComposerClient::surface_data_t* params; - Client* client; - const String8& name; - DisplayID display; - uint32_t w, h; - PixelFormat format; - uint32_t flags; - public: - MessageCreateSurface(SurfaceFlinger* flinger, - ISurfaceComposerClient::surface_data_t* params, - const String8& name, Client* client, - DisplayID display, uint32_t w, uint32_t h, PixelFormat format, - uint32_t flags) - : flinger(flinger), params(params), client(client), name(name), - display(display), w(w), h(h), format(format), flags(flags) - { - } - sp<ISurface> getResult() const { return result; } - virtual bool handler() { - result = flinger->createSurface(params, name, client, - display, w, h, format, flags); - return true; - } - }; - - sp<MessageBase> msg = new MessageCreateSurface(mFlinger.get(), - params, name, this, display, w, h, format, flags); - mFlinger->postMessageSync(msg); - return static_cast<MessageCreateSurface*>( msg.get() )->getResult(); -} -status_t Client::destroySurface(SurfaceID sid) { - return mFlinger->removeSurface(this, sid); + return l->sequence - r->sequence; } // --------------------------------------------------------------------------- -GraphicBufferAlloc::GraphicBufferAlloc() {} - -GraphicBufferAlloc::~GraphicBufferAlloc() {} - -sp<GraphicBuffer> GraphicBufferAlloc::createGraphicBuffer(uint32_t w, uint32_t h, - PixelFormat format, uint32_t usage, status_t* error) { - sp<GraphicBuffer> graphicBuffer(new GraphicBuffer(w, h, format, usage)); - status_t err = graphicBuffer->initCheck(); - *error = err; - if (err != 0 || graphicBuffer->handle == 0) { - if (err == NO_MEMORY) { - GraphicBuffer::dumpAllocationsToSystemLog(); - } - ALOGE("GraphicBufferAlloc::createGraphicBuffer(w=%d, h=%d) " - "failed (%s), handle=%p", - w, h, strerror(-err), graphicBuffer->handle); - return 0; - } - return graphicBuffer; -} - -// --------------------------------------------------------------------------- - -GraphicPlane::GraphicPlane() - : mHw(0) -{ -} - -GraphicPlane::~GraphicPlane() { - delete mHw; -} - -bool GraphicPlane::initialized() const { - return mHw ? true : false; -} - -int GraphicPlane::getWidth() const { - return mWidth; -} - -int GraphicPlane::getHeight() const { - return mHeight; -} - -void GraphicPlane::setDisplayHardware(DisplayHardware *hw) -{ - mHw = hw; - - // initialize the display orientation transform. - // it's a constant that should come from the display driver. - int displayOrientation = ISurfaceComposer::eOrientationDefault; - char property[PROPERTY_VALUE_MAX]; - if (property_get("ro.sf.hwrotation", property, NULL) > 0) { - //displayOrientation - switch (atoi(property)) { - case 90: - displayOrientation = ISurfaceComposer::eOrientation90; - break; - case 270: - displayOrientation = ISurfaceComposer::eOrientation270; - break; - } - } - - const float w = hw->getWidth(); - const float h = hw->getHeight(); - GraphicPlane::orientationToTransfrom(displayOrientation, w, h, - &mDisplayTransform); - if (displayOrientation & ISurfaceComposer::eOrientationSwapMask) { - mDisplayWidth = h; - mDisplayHeight = w; - } else { - mDisplayWidth = w; - mDisplayHeight = h; - } - - setOrientation(ISurfaceComposer::eOrientationDefault); -} - -status_t GraphicPlane::orientationToTransfrom( - int orientation, int w, int h, Transform* tr) -{ - uint32_t flags = 0; - switch (orientation) { - case ISurfaceComposer::eOrientationDefault: - flags = Transform::ROT_0; - break; - case ISurfaceComposer::eOrientation90: - flags = Transform::ROT_90; - break; - case ISurfaceComposer::eOrientation180: - flags = Transform::ROT_180; - break; - case ISurfaceComposer::eOrientation270: - flags = Transform::ROT_270; - break; - default: - return BAD_VALUE; - } - tr->set(flags, w, h); - return NO_ERROR; -} - -status_t GraphicPlane::setOrientation(int orientation) -{ - // If the rotation can be handled in hardware, this is where - // the magic should happen. - - const DisplayHardware& hw(displayHardware()); - const float w = mDisplayWidth; - const float h = mDisplayHeight; - mWidth = int(w); - mHeight = int(h); - - Transform orientationTransform; - GraphicPlane::orientationToTransfrom(orientation, w, h, - &orientationTransform); - if (orientation & ISurfaceComposer::eOrientationSwapMask) { - mWidth = int(h); - mHeight = int(w); - } - - mOrientation = orientation; - mGlobalTransform = mDisplayTransform * orientationTransform; - return NO_ERROR; -} - -const DisplayHardware& GraphicPlane::displayHardware() const { - return *mHw; -} - -DisplayHardware& GraphicPlane::editDisplayHardware() { - return *mHw; -} - -const Transform& GraphicPlane::transform() const { - return mGlobalTransform; +SurfaceFlinger::DisplayDeviceState::DisplayDeviceState() + : type(DisplayDevice::DISPLAY_ID_INVALID) { } -EGLDisplay GraphicPlane::getEGLDisplay() const { - return mHw->getEGLDisplay(); +SurfaceFlinger::DisplayDeviceState::DisplayDeviceState(DisplayDevice::DisplayType type) + : type(type), layerStack(0), orientation(0) { + viewport.makeInvalid(); + frame.makeInvalid(); } // --------------------------------------------------------------------------- diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index b20973b..1b549e4 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -20,6 +20,9 @@ #include <stdint.h> #include <sys/types.h> +#include <EGL/egl.h> +#include <GLES/gl.h> + #include <cutils/compiler.h> #include <utils/Atomic.h> @@ -33,204 +36,103 @@ #include <binder/IMemory.h> #include <ui/PixelFormat.h> -#include <gui/IGraphicBufferAlloc.h> + #include <gui/ISurfaceComposer.h> #include <gui/ISurfaceComposerClient.h> -#include "Barrier.h" -#include "Layer.h" +#include <hardware/hwcomposer_defs.h> +#include <private/gui/LayerState.h> + +#include "Barrier.h" #include "MessageQueue.h" +#include "DisplayDevice.h" + +#include "DisplayHardware/HWComposer.h" namespace android { // --------------------------------------------------------------------------- class Client; -class DisplayHardware; class DisplayEventConnection; class EventThread; +class IGraphicBufferAlloc; class Layer; +class LayerBase; +class LayerBaseClient; class LayerDim; class LayerScreenshot; -struct surface_flinger_cblk_t; - -// --------------------------------------------------------------------------- - -class Client : public BnSurfaceComposerClient -{ -public: - Client(const sp<SurfaceFlinger>& flinger); - ~Client(); - - status_t initCheck() const; - - // protected by SurfaceFlinger::mStateLock - size_t attachLayer(const sp<LayerBaseClient>& layer); - void detachLayer(const LayerBaseClient* layer); - sp<LayerBaseClient> getLayerUser(int32_t i) const; - -private: - // ISurfaceComposerClient interface - virtual sp<ISurface> createSurface( - surface_data_t* params, const String8& name, - DisplayID display, uint32_t w, uint32_t h,PixelFormat format, - uint32_t flags); - virtual status_t destroySurface(SurfaceID surfaceId); - virtual status_t onTransact( - uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags); - - // constant - sp<SurfaceFlinger> mFlinger; - - // protected by mLock - DefaultKeyedVector< size_t, wp<LayerBaseClient> > mLayers; - size_t mNameGenerator; - - // thread-safe - mutable Mutex mLock; -}; - -class GraphicBufferAlloc : public BnGraphicBufferAlloc -{ -public: - GraphicBufferAlloc(); - virtual ~GraphicBufferAlloc(); - virtual sp<GraphicBuffer> createGraphicBuffer(uint32_t w, uint32_t h, - PixelFormat format, uint32_t usage, status_t* error); -}; - -// --------------------------------------------------------------------------- - -class GraphicPlane -{ -public: - static status_t orientationToTransfrom(int orientation, int w, int h, - Transform* tr); - - GraphicPlane(); - ~GraphicPlane(); - - bool initialized() const; - - void setDisplayHardware(DisplayHardware *); - status_t setOrientation(int orientation); - int getOrientation() const { return mOrientation; } - int getWidth() const; - int getHeight() const; - - const DisplayHardware& displayHardware() const; - DisplayHardware& editDisplayHardware(); - const Transform& transform() const; - EGLDisplay getEGLDisplay() const; - -private: - GraphicPlane(const GraphicPlane&); - GraphicPlane operator = (const GraphicPlane&); - - DisplayHardware* mHw; - Transform mGlobalTransform; - Transform mDisplayTransform; - int mOrientation; - float mDisplayWidth; - float mDisplayHeight; - int mWidth; - int mHeight; -}; +class SurfaceTextureClient; // --------------------------------------------------------------------------- enum { - eTransactionNeeded = 0x01, - eTraversalNeeded = 0x02 + eTransactionNeeded = 0x01, + eTraversalNeeded = 0x02, + eDisplayTransactionNeeded = 0x04, + eTransactionMask = 0x07 }; -class SurfaceFlinger : - public BinderService<SurfaceFlinger>, - public BnSurfaceComposer, - public IBinder::DeathRecipient, - protected Thread +class SurfaceFlinger : public BinderService<SurfaceFlinger>, + public BnSurfaceComposer, + private IBinder::DeathRecipient, + private Thread, + private HWComposer::EventHandler { public: - static char const* getServiceName() { return "SurfaceFlinger"; } - - SurfaceFlinger(); - virtual ~SurfaceFlinger(); - void init(); + static char const* getServiceName() { + return "SurfaceFlinger"; + } - virtual status_t onTransact( - uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags); - - virtual status_t dump(int fd, const Vector<String16>& args); + SurfaceFlinger(); - // ISurfaceComposer interface - virtual sp<ISurfaceComposerClient> createConnection(); - virtual sp<IGraphicBufferAlloc> createGraphicBufferAlloc(); - virtual sp<IMemoryHeap> getCblk() const; - virtual void bootFinished(); - virtual void setTransactionState(const Vector<ComposerState>& state, - int orientation, uint32_t flags); - virtual bool authenticateSurfaceTexture(const sp<ISurfaceTexture>& surface) const; - virtual sp<IDisplayEventConnection> createDisplayEventConnection(); - - virtual status_t captureScreen(DisplayID dpy, - sp<IMemoryHeap>* heap, - uint32_t* width, uint32_t* height, - PixelFormat* format, uint32_t reqWidth, uint32_t reqHeight, - uint32_t minLayerZ, uint32_t maxLayerZ); + enum { + EVENT_VSYNC = HWC_EVENT_VSYNC + }; - virtual status_t turnElectronBeamOff(int32_t mode); - virtual status_t turnElectronBeamOn(int32_t mode); + // post an asynchronous message to the main thread + status_t postMessageAsync(const sp<MessageBase>& msg, nsecs_t reltime = 0, + uint32_t flags = 0); + // post a synchronous message to the main thread + status_t postMessageSync(const sp<MessageBase>& msg, nsecs_t reltime = 0, + uint32_t flags = 0); - // called when screen needs to turn off - void screenReleased(); - // called when screen is turning back on - void screenAcquired(); + // force full composition on all displays + void repaintEverything(); - // called on the main thread in response to screenReleased() - void onScreenReleased(); - // called on the main thread in response to screenAcquired() - void onScreenAcquired(); + // renders content on given display to a texture. thread-safe version. + status_t renderScreenToTexture(uint32_t layerStack, GLuint* textureName, + GLfloat* uOut, GLfloat* vOut); + // renders content on given display to a texture, w/o acquiring main lock + status_t renderScreenToTextureLocked(uint32_t layerStack, GLuint* textureName, + GLfloat* uOut, GLfloat* vOut); - status_t renderScreenToTexture(DisplayID dpy, - GLuint* textureName, GLfloat* uOut, GLfloat* vOut); - status_t renderScreenToTextureLocked(DisplayID dpy, - GLuint* textureName, GLfloat* uOut, GLfloat* vOut); + // returns the default Display + sp<const DisplayDevice> getDefaultDisplayDevice() const { + return getDisplayDevice(mBuiltinDisplays[DisplayDevice::DISPLAY_PRIMARY]); + } - void onMessageReceived(int32_t what); + // utility function to delete a texture on the main thread + void deleteTextureAsync(GLuint texture); - status_t postMessageAsync(const sp<MessageBase>& msg, - nsecs_t reltime=0, uint32_t flags = 0); + // allocate a h/w composer display id + int32_t allocateHwcDisplayId(DisplayDevice::DisplayType type); - status_t postMessageSync(const sp<MessageBase>& msg, - nsecs_t reltime=0, uint32_t flags = 0); + // enable/disable h/w composer event + // TODO: this should be made accessible only to EventThread + void eventControl(int disp, int event, int enabled); - status_t removeLayer(const sp<LayerBase>& layer); - status_t addLayer(const sp<LayerBase>& layer); - status_t invalidateLayerVisibility(const sp<LayerBase>& layer); - void invalidateHwcGeometry(); + // called on the main thread by MessageQueue when an internal message + // is received + // TODO: this should be made accessible only to MessageQueue + void onMessageReceived(int32_t what); - sp<Layer> getLayer(const sp<ISurface>& sur) const; - - GLuint getProtectedTexName() const { return mProtectedTexName; } - - - class MessageDestroyGLTexture : public MessageBase { - GLuint texture; - public: - MessageDestroyGLTexture(GLuint texture) : texture(texture) { } - virtual bool handler() { - glDeleteTextures(1, &texture); - return true; - } - }; - - -private: - // DeathRecipient interface - virtual void binderDied(const wp<IBinder>& who); + // for debugging only + // TODO: this should be made accessible only to HWComposer + const Vector< sp<LayerBase> >& getLayerSortedByZForHwcDisplay(int disp); private: friend class Client; @@ -238,191 +140,327 @@ private: friend class LayerBase; friend class LayerBaseClient; friend class Layer; + friend class LayerScreenshot; - sp<ISurface> createSurface( - ISurfaceComposerClient::surface_data_t* params, - const String8& name, - const sp<Client>& client, - DisplayID display, uint32_t w, uint32_t h, PixelFormat format, - uint32_t flags); - - sp<Layer> createNormalSurface( - const sp<Client>& client, DisplayID display, - uint32_t w, uint32_t h, uint32_t flags, - PixelFormat& format); + // We're reference counted, never destroy SurfaceFlinger directly + virtual ~SurfaceFlinger(); - sp<LayerDim> createDimSurface( - const sp<Client>& client, DisplayID display, - uint32_t w, uint32_t h, uint32_t flags); + /* ------------------------------------------------------------------------ + * Internal data structures + */ - sp<LayerScreenshot> createScreenshotSurface( - const sp<Client>& client, DisplayID display, - uint32_t w, uint32_t h, uint32_t flags); - - status_t removeSurface(const sp<Client>& client, SurfaceID sid); - status_t destroySurface(const wp<LayerBaseClient>& layer); - uint32_t setClientStateLocked(const sp<Client>& client, const layer_state_t& s); - - class LayerVector : public SortedVector< sp<LayerBase> > { + class LayerVector : public SortedVector<sp<LayerBase> > { public: - LayerVector() { } - LayerVector(const LayerVector& rhs) : SortedVector< sp<LayerBase> >(rhs) { } - virtual int do_compare(const void* lhs, const void* rhs) const { - const sp<LayerBase>& l(*reinterpret_cast<const sp<LayerBase>*>(lhs)); - const sp<LayerBase>& r(*reinterpret_cast<const sp<LayerBase>*>(rhs)); - // sort layers by Z order - uint32_t lz = l->currentState().z; - uint32_t rz = r->currentState().z; - // then by sequence, so we get a stable ordering - return (lz != rz) ? (lz - rz) : (l->sequence - r->sequence); - } + LayerVector(); + LayerVector(const LayerVector& rhs); + virtual int do_compare(const void* lhs, const void* rhs) const; + }; + + struct DisplayDeviceState { + DisplayDeviceState(); + DisplayDeviceState(DisplayDevice::DisplayType type); + bool isValid() const { return type >= 0; } + bool isMainDisplay() const { return type == DisplayDevice::DISPLAY_PRIMARY; } + bool isVirtualDisplay() const { return type >= DisplayDevice::DISPLAY_VIRTUAL; } + DisplayDevice::DisplayType type; + sp<ISurfaceTexture> surface; + uint32_t layerStack; + Rect viewport; + Rect frame; + uint8_t orientation; + String8 displayName; + bool isSecure; }; struct State { - State() - : orientation(ISurfaceComposer::eOrientationDefault), - orientationFlags(0) { - } - LayerVector layersSortedByZ; - uint8_t orientation; - uint8_t orientationFlags; + LayerVector layersSortedByZ; + DefaultKeyedVector< wp<IBinder>, DisplayDeviceState> displays; }; - virtual bool threadLoop(); - virtual status_t readyToRun(); - virtual void onFirstRef(); + /* ------------------------------------------------------------------------ + * IBinder interface + */ + virtual status_t onTransact(uint32_t code, const Parcel& data, + Parcel* reply, uint32_t flags); + virtual status_t dump(int fd, const Vector<String16>& args); + + /* ------------------------------------------------------------------------ + * ISurfaceComposer interface + */ + virtual sp<ISurfaceComposerClient> createConnection(); + virtual sp<IGraphicBufferAlloc> createGraphicBufferAlloc(); + virtual sp<IBinder> createDisplay(const String8& displayName, bool secure); + virtual sp<IBinder> getBuiltInDisplay(int32_t id); + virtual void setTransactionState(const Vector<ComposerState>& state, + const Vector<DisplayState>& displays, uint32_t flags); + virtual void bootFinished(); + virtual bool authenticateSurfaceTexture( + const sp<ISurfaceTexture>& surface) const; + virtual sp<IDisplayEventConnection> createDisplayEventConnection(); + virtual status_t captureScreen(const sp<IBinder>& display, sp<IMemoryHeap>* heap, + uint32_t* width, uint32_t* height, PixelFormat* format, + uint32_t reqWidth, uint32_t reqHeight, uint32_t minLayerZ, + uint32_t maxLayerZ); + // called when screen needs to turn off + virtual void blank(const sp<IBinder>& display); + // called when screen is turning back on + virtual void unblank(const sp<IBinder>& display); + virtual status_t getDisplayInfo(const sp<IBinder>& display, DisplayInfo* info); + + /* ------------------------------------------------------------------------ + * DeathRecipient interface + */ + virtual void binderDied(const wp<IBinder>& who); + + /* ------------------------------------------------------------------------ + * Thread interface + */ + virtual bool threadLoop(); + virtual status_t readyToRun(); + virtual void onFirstRef(); + + /* ------------------------------------------------------------------------ + * HWComposer::EventHandler interface + */ + virtual void onVSyncReceived(int type, nsecs_t timestamp); + virtual void onHotplugReceived(int disp, bool connected); + + /* ------------------------------------------------------------------------ + * Message handling + */ + void waitForEvent(); + void signalTransaction(); + void signalLayerUpdate(); + void signalRefresh(); + + // called on the main thread in response to initializeDisplays() + void onInitializeDisplays(); + // called on the main thread in response to blank() + void onScreenReleased(const sp<const DisplayDevice>& hw); + // called on the main thread in response to unblank() + void onScreenAcquired(const sp<const DisplayDevice>& hw); + + void handleMessageTransaction(); + void handleMessageInvalidate(); + void handleMessageRefresh(); + + void handleTransaction(uint32_t transactionFlags); + void handleTransactionLocked(uint32_t transactionFlags); + + /* handlePageFilp: this is were we latch a new buffer + * if available and compute the dirty region. + */ + void handlePageFlip(); + + /* ------------------------------------------------------------------------ + * Transactions + */ + uint32_t getTransactionFlags(uint32_t flags); + uint32_t peekTransactionFlags(uint32_t flags); + uint32_t setTransactionFlags(uint32_t flags); + void commitTransaction(); + uint32_t setClientStateLocked(const sp<Client>& client, + const layer_state_t& s); + uint32_t setDisplayStateLocked(const DisplayState& s); + + /* ------------------------------------------------------------------------ + * Layer management + */ + sp<ISurface> createLayer(ISurfaceComposerClient::surface_data_t* params, + const String8& name, const sp<Client>& client, + uint32_t w, uint32_t h, PixelFormat format, uint32_t flags); + + sp<Layer> createNormalLayer(const sp<Client>& client, + uint32_t w, uint32_t h, uint32_t flags, PixelFormat& format); + + sp<LayerDim> createDimLayer(const sp<Client>& client, + uint32_t w, uint32_t h, uint32_t flags); -public: // hack to work around gcc 4.0.3 bug - const GraphicPlane& graphicPlane(int dpy) const; - GraphicPlane& graphicPlane(int dpy); + sp<LayerScreenshot> createScreenshotLayer(const sp<Client>& client, + uint32_t w, uint32_t h, uint32_t flags); - void signalTransaction(); - void signalLayerUpdate(); - void signalRefresh(); - void repaintEverything(); + // called in response to the window-manager calling + // ISurfaceComposerClient::destroySurface() + // The specified layer is first placed in a purgatory list + // until all references from the client are released. + status_t onLayerRemoved(const sp<Client>& client, SurfaceID sid); -private: - void waitForEvent(); - void handleTransaction(uint32_t transactionFlags); - void handleTransactionLocked(uint32_t transactionFlags); - - void computeVisibleRegions( - const LayerVector& currentLayers, - Region& dirtyRegion, - Region& wormholeRegion); - - void handlePageFlip(); - bool lockPageFlip(const LayerVector& currentLayers); - void unlockPageFlip(const LayerVector& currentLayers); - void handleRefresh(); - void handleWorkList(); - void handleRepaint(); - void postFramebuffer(); - void setupHardwareComposer(); - void composeSurfaces(const Region& dirty); - - - void setInvalidateRegion(const Region& reg); - Region getAndClearInvalidateRegion(); - - ssize_t addClientLayer(const sp<Client>& client, - const sp<LayerBaseClient>& lbc); - status_t addLayer_l(const sp<LayerBase>& layer); - status_t removeLayer_l(const sp<LayerBase>& layer); - status_t purgatorizeLayer_l(const sp<LayerBase>& layer); - - uint32_t getTransactionFlags(uint32_t flags); - uint32_t peekTransactionFlags(uint32_t flags); - uint32_t setTransactionFlags(uint32_t flags); - void commitTransaction(); - - - status_t captureScreenImplLocked(DisplayID dpy, - sp<IMemoryHeap>* heap, - uint32_t* width, uint32_t* height, PixelFormat* format, - uint32_t reqWidth, uint32_t reqHeight, - uint32_t minLayerZ, uint32_t maxLayerZ); - - status_t turnElectronBeamOffImplLocked(int32_t mode); - status_t turnElectronBeamOnImplLocked(int32_t mode); - status_t electronBeamOffAnimationImplLocked(); - status_t electronBeamOnAnimationImplLocked(); - - void debugFlashRegions(); - void drawWormhole() const; - - void startBootAnim(); - - void listLayersLocked(const Vector<String16>& args, size_t& index, - String8& result, char* buffer, size_t SIZE) const; - void dumpStatsLocked(const Vector<String16>& args, size_t& index, - String8& result, char* buffer, size_t SIZE) const; - void clearStatsLocked(const Vector<String16>& args, size_t& index, - String8& result, char* buffer, size_t SIZE) const; - void dumpAllLocked(String8& result, char* buffer, size_t SIZE) const; - - mutable MessageQueue mEventQueue; - - // access must be protected by mStateLock - mutable Mutex mStateLock; - State mCurrentState; - volatile int32_t mTransactionFlags; - Condition mTransactionCV; - SortedVector< sp<LayerBase> > mLayerPurgatory; - bool mTransationPending; - Vector< sp<LayerBase> > mLayersPendingRemoval; - - // protected by mStateLock (but we could use another lock) - GraphicPlane mGraphicPlanes[1]; - bool mLayersRemoved; - DefaultKeyedVector< wp<IBinder>, wp<Layer> > mLayerMap; - - // access must be protected by mInvalidateLock - mutable Mutex mInvalidateLock; - Region mInvalidateRegion; - - // constant members (no synchronization needed for access) - sp<IMemoryHeap> mServerHeap; - surface_flinger_cblk_t* mServerCblk; - GLuint mWormholeTexName; - GLuint mProtectedTexName; - nsecs_t mBootTime; - sp<EventThread> mEventThread; - - // Can only accessed from the main thread, these members - // don't need synchronization - State mDrawingState; - Region mDirtyRegion; - Region mDirtyRegionRemovedLayer; - Region mSwapRegion; - Region mWormholeRegion; - bool mVisibleRegionsDirty; - bool mHwWorkListDirty; - int32_t mElectronBeamAnimationMode; - Vector< sp<LayerBase> > mVisibleLayersSortedByZ; - - - // don't use a lock for these, we don't care - int mDebugRegion; - int mDebugDDMS; - int mDebugDisableHWC; - int mDebugDisableTransformHint; - volatile nsecs_t mDebugInSwapBuffers; - nsecs_t mLastSwapBufferTime; - volatile nsecs_t mDebugInTransaction; - nsecs_t mLastTransactionTime; - bool mBootFinished; - - // these are thread safe - mutable Barrier mReadyToRunBarrier; - - - // protected by mDestroyedLayerLock; - mutable Mutex mDestroyedLayerLock; - Vector<LayerBase const *> mDestroyedLayers; - - // only written in the main thread, only read in other threads - volatile int32_t mSecureFrameBuffer; + // called when all clients have released all their references to + // this layer meaning it is entirely safe to destroy all + // resources associated to this layer. + status_t onLayerDestroyed(const wp<LayerBaseClient>& layer); + + // remove a layer from SurfaceFlinger immediately + status_t removeLayer(const sp<LayerBase>& layer); + + // add a layer to SurfaceFlinger + ssize_t addClientLayer(const sp<Client>& client, + const sp<LayerBaseClient>& lbc); + + status_t removeLayer_l(const sp<LayerBase>& layer); + status_t purgatorizeLayer_l(const sp<LayerBase>& layer); + + /* ------------------------------------------------------------------------ + * Boot animation, on/off animations and screen capture + */ + + void startBootAnim(); + + status_t captureScreenImplLocked(const sp<IBinder>& display, sp<IMemoryHeap>* heap, + uint32_t* width, uint32_t* height, PixelFormat* format, + uint32_t reqWidth, uint32_t reqHeight, uint32_t minLayerZ, + uint32_t maxLayerZ); + + /* ------------------------------------------------------------------------ + * EGL + */ + static status_t selectConfigForAttribute(EGLDisplay dpy, + EGLint const* attrs, EGLint attribute, EGLint value, EGLConfig* outConfig); + static EGLConfig selectEGLConfig(EGLDisplay disp, EGLint visualId); + static EGLContext createGLContext(EGLDisplay disp, EGLConfig config); + void initializeGL(EGLDisplay display); + uint32_t getMaxTextureSize() const; + uint32_t getMaxViewportDims() const; + + /* ------------------------------------------------------------------------ + * Display and layer stack management + */ + // called when starting, or restarting after system_server death + void initializeDisplays(); + + // Create an IBinder for a builtin display and add it to current state + void createBuiltinDisplayLocked(DisplayDevice::DisplayType type); + + // NOTE: can only be called from the main thread or with mStateLock held + sp<const DisplayDevice> getDisplayDevice(const wp<IBinder>& dpy) const { + return mDisplays.valueFor(dpy); + } + + // NOTE: can only be called from the main thread or with mStateLock held + sp<DisplayDevice> getDisplayDevice(const wp<IBinder>& dpy) { + return mDisplays.valueFor(dpy); + } + + // mark a region of a layer stack dirty. this updates the dirty + // region of all screens presenting this layer stack. + void invalidateLayerStack(uint32_t layerStack, const Region& dirty); + + /* ------------------------------------------------------------------------ + * H/W composer + */ + + HWComposer& getHwComposer() const { return *mHwc; } + + /* ------------------------------------------------------------------------ + * Compositing + */ + void invalidateHwcGeometry(); + static void computeVisibleRegions( + const LayerVector& currentLayers, uint32_t layerStack, + Region& dirtyRegion, Region& opaqueRegion); + + void preComposition(); + void postComposition(); + void rebuildLayerStacks(); + void setUpHWComposer(); + void doComposition(); + void doDebugFlashRegions(); + void doDisplayComposition(const sp<const DisplayDevice>& hw, + const Region& dirtyRegion); + void doComposeSurfaces(const sp<const DisplayDevice>& hw, + const Region& dirty); + + void postFramebuffer(); + void drawWormhole(const sp<const DisplayDevice>& hw, + const Region& region) const; + GLuint getProtectedTexName() const { + return mProtectedTexName; + } + + /* ------------------------------------------------------------------------ + * Display management + */ + + + /* ------------------------------------------------------------------------ + * Debugging & dumpsys + */ + void listLayersLocked(const Vector<String16>& args, size_t& index, + String8& result, char* buffer, size_t SIZE) const; + void dumpStatsLocked(const Vector<String16>& args, size_t& index, + String8& result, char* buffer, size_t SIZE) const; + void clearStatsLocked(const Vector<String16>& args, size_t& index, + String8& result, char* buffer, size_t SIZE) const; + void dumpAllLocked(String8& result, char* buffer, size_t SIZE) const; + bool startDdmConnection(); + static void appendSfConfigString(String8& result); + + /* ------------------------------------------------------------------------ + * Attributes + */ + + // access must be protected by mStateLock + mutable Mutex mStateLock; + State mCurrentState; + volatile int32_t mTransactionFlags; + Condition mTransactionCV; + SortedVector<sp<LayerBase> > mLayerPurgatory; + bool mTransactionPending; + bool mAnimTransactionPending; + Vector<sp<LayerBase> > mLayersPendingRemoval; + + // protected by mStateLock (but we could use another lock) + bool mLayersRemoved; + + // access must be protected by mInvalidateLock + volatile int32_t mRepaintEverything; + + // constant members (no synchronization needed for access) + HWComposer* mHwc; + GLuint mProtectedTexName; + nsecs_t mBootTime; + sp<EventThread> mEventThread; + GLint mMaxViewportDims[2]; + GLint mMaxTextureSize; + EGLContext mEGLContext; + EGLConfig mEGLConfig; + EGLDisplay mEGLDisplay; + sp<IBinder> mBuiltinDisplays[DisplayDevice::NUM_DISPLAY_TYPES]; + + // Can only accessed from the main thread, these members + // don't need synchronization + State mDrawingState; + bool mVisibleRegionsDirty; + bool mHwWorkListDirty; + + // this may only be written from the main thread with mStateLock held + // it may be read from other threads with mStateLock held + DefaultKeyedVector< wp<IBinder>, sp<DisplayDevice> > mDisplays; + + // don't use a lock for these, we don't care + int mDebugRegion; + int mDebugDDMS; + int mDebugDisableHWC; + int mDebugDisableTransformHint; + volatile nsecs_t mDebugInSwapBuffers; + nsecs_t mLastSwapBufferTime; + volatile nsecs_t mDebugInTransaction; + nsecs_t mLastTransactionTime; + bool mBootFinished; + + // these are thread safe + mutable MessageQueue mEventQueue; + mutable Barrier mReadyToRunBarrier; + + // protected by mDestroyedLayerLock; + mutable Mutex mDestroyedLayerLock; + Vector<LayerBase const *> mDestroyedLayers; + + /* ------------------------------------------------------------------------ + * Feature prototyping + */ + + sp<IBinder> mExtDisplayToken; }; // --------------------------------------------------------------------------- diff --git a/services/surfaceflinger/Transform.cpp b/services/surfaceflinger/Transform.cpp index ca3fa6e..aca90e0 100644 --- a/services/surfaceflinger/Transform.cpp +++ b/services/surfaceflinger/Transform.cpp @@ -192,7 +192,6 @@ Transform::vec3 Transform::transform(const vec3& v) const { void Transform::transform(float* point, int x, int y) const { - const mat33& M(mMatrix); vec2 v(x, y); v = transform(v); point[0] = v[0]; diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp index 84ae0d9..0592c5b 100644 --- a/services/surfaceflinger/tests/Transaction_test.cpp +++ b/services/surfaceflinger/tests/Transaction_test.cpp @@ -24,6 +24,7 @@ #include <private/gui/ComposerService.h> #include <utils/String8.h> +#include <ui/DisplayInfo.h> namespace android { @@ -56,7 +57,8 @@ public: uint32_t w=0, h=0; PixelFormat fmt=0; sp<ISurfaceComposer> sf(ComposerService::getComposerService()); - ASSERT_EQ(NO_ERROR, sf->captureScreen(0, &heap, &w, &h, &fmt, 0, 0, + sp<IBinder> display(sf->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain)); + ASSERT_EQ(NO_ERROR, sf->captureScreen(display, &heap, &w, &h, &fmt, 0, 0, 0, INT_MAX)); ASSERT_TRUE(heap != NULL); ASSERT_EQ(PIXEL_FORMAT_RGBA_8888, fmt); @@ -92,12 +94,17 @@ protected: mComposerClient = new SurfaceComposerClient; ASSERT_EQ(NO_ERROR, mComposerClient->initCheck()); - ssize_t displayWidth = mComposerClient->getDisplayWidth(0); - ssize_t displayHeight = mComposerClient->getDisplayHeight(0); + sp<IBinder> display(SurfaceComposerClient::getBuiltInDisplay( + ISurfaceComposer::eDisplayIdMain)); + DisplayInfo info; + SurfaceComposerClient::getDisplayInfo(display, &info); + + ssize_t displayWidth = info.w; + ssize_t displayHeight = info.h; // Background surface mBGSurfaceControl = mComposerClient->createSurface( - String8("BG Test Surface"), 0, displayWidth, displayHeight, + String8("BG Test Surface"), displayWidth, displayHeight, PIXEL_FORMAT_RGBA_8888, 0); ASSERT_TRUE(mBGSurfaceControl != NULL); ASSERT_TRUE(mBGSurfaceControl->isValid()); @@ -105,7 +112,7 @@ protected: // Foreground surface mFGSurfaceControl = mComposerClient->createSurface( - String8("FG Test Surface"), 0, 64, 64, PIXEL_FORMAT_RGBA_8888, 0); + String8("FG Test Surface"), 64, 64, PIXEL_FORMAT_RGBA_8888, 0); ASSERT_TRUE(mFGSurfaceControl != NULL); ASSERT_TRUE(mFGSurfaceControl->isValid()); @@ -113,7 +120,7 @@ protected: // Synchronization surface mSyncSurfaceControl = mComposerClient->createSurface( - String8("Sync Test Surface"), 0, 1, 1, PIXEL_FORMAT_RGBA_8888, 0); + String8("Sync Test Surface"), 1, 1, PIXEL_FORMAT_RGBA_8888, 0); ASSERT_TRUE(mSyncSurfaceControl != NULL); ASSERT_TRUE(mSyncSurfaceControl->isValid()); diff --git a/services/surfaceflinger/tests/resize/resize.cpp b/services/surfaceflinger/tests/resize/resize.cpp index c143b3d..d61ea70 100644 --- a/services/surfaceflinger/tests/resize/resize.cpp +++ b/services/surfaceflinger/tests/resize/resize.cpp @@ -38,8 +38,8 @@ int main(int argc, char** argv) // create a client to surfaceflinger sp<SurfaceComposerClient> client = new SurfaceComposerClient(); - sp<Surface> surface = client->createSurface(0, 160, 240, - PIXEL_FORMAT_RGB_565); + sp<Surface> surface = client->createSurface(String8("resize"), + 160, 240, PIXEL_FORMAT_RGB_565, 0); SurfaceComposerClient::openGlobalTransaction(); diff --git a/services/surfaceflinger/tests/screencap/screencap.cpp b/services/surfaceflinger/tests/screencap/screencap.cpp index 53566e0..f842fc3 100644 --- a/services/surfaceflinger/tests/screencap/screencap.cpp +++ b/services/surfaceflinger/tests/screencap/screencap.cpp @@ -42,7 +42,8 @@ int main(int argc, char** argv) sp<IMemoryHeap> heap; uint32_t w, h; PixelFormat f; - status_t err = composer->captureScreen(0, &heap, &w, &h, &f, 0, 0); + sp<IBinder> display(composer->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain)); + status_t err = composer->captureScreen(display, &heap, &w, &h, &f, 0, 0); if (err != NO_ERROR) { fprintf(stderr, "screen capture failed: %s\n", strerror(-err)); exit(0); diff --git a/services/surfaceflinger/tests/surface/surface.cpp b/services/surfaceflinger/tests/surface/surface.cpp index a8878f7..9c41cc3 100644 --- a/services/surfaceflinger/tests/surface/surface.cpp +++ b/services/surfaceflinger/tests/surface/surface.cpp @@ -37,7 +37,7 @@ int main(int argc, char** argv) sp<SurfaceComposerClient> client = new SurfaceComposerClient(); sp<SurfaceControl> surfaceControl = client->createSurface( - 0, 160, 240, PIXEL_FORMAT_RGB_565); + String8("surface"), 160, 240, PIXEL_FORMAT_RGB_565, 0); SurfaceComposerClient::openGlobalTransaction(); surfaceControl->setLayer(100000); SurfaceComposerClient::closeGlobalTransaction(); |