}
static void usage() {
- fprintf(stderr, "usage: dumpstate [-b soundfile] [-e soundfile] [-o file [-d] [-p] [-z]] [-s]\n"
+ fprintf(stderr, "usage: dumpstate [-b soundfile] [-e soundfile] [-o file [-d] [-p] [-z]] [-s] [-q]\n"
" -o: write to file (instead of stdout)\n"
" -d: append date to filename (requires -o)\n"
" -z: gzip output (requires -o)\n"
" -s: write output to control socket (for init)\n"
" -b: play sound file instead of vibrate, at beginning of job\n"
" -e: play sound file instead of vibrate, at end of job\n"
+ " -q: disable vibrate\n"
);
}
int main(int argc, char *argv[]) {
int do_add_date = 0;
int do_compress = 0;
+ int do_vibrate = 1;
char* use_outfile = 0;
char* begin_sound = 0;
char* end_sound = 0;
dump_traces_path = dump_traces();
int c;
- while ((c = getopt(argc, argv, "b:de:ho:svzp")) != -1) {
+ while ((c = getopt(argc, argv, "b:de:ho:svqzp")) != -1) {
switch (c) {
case 'b': begin_sound = optarg; break;
case 'd': do_add_date = 1; break;
case 'o': use_outfile = optarg; break;
case 's': use_socket = 1; break;
case 'v': break; // compatibility no-op
+ case 'q': do_vibrate = 0; break;
case 'z': do_compress = 6; break;
case 'p': do_fb = 1; break;
case '?': printf("\n");
}
}
- /* open the vibrator before dropping root */
- FILE *vibrator = fopen("/sys/class/timed_output/vibrator/enable", "w");
- if (vibrator) fcntl(fileno(vibrator), F_SETFD, FD_CLOEXEC);
+ FILE *vibrator = 0;
+ if (do_vibrate) {
+ /* open the vibrator before dropping root */
+ vibrator = fopen("/sys/class/timed_output/vibrator/enable", "w");
+ if (vibrator) fcntl(fileno(vibrator), F_SETFD, FD_CLOEXEC);
+ }
/* read /proc/cmdline before dropping root */
FILE *cmdline = fopen("/proc/cmdline", "r");
Rect mCrop;
// mTransform is the current transform flags for this buffer slot.
+ // (example: NATIVE_WINDOW_TRANSFORM_ROT_90)
uint32_t mTransform;
// mScalingMode is the current scaling mode for this buffer slot.
+ // (example: NATIVE_WINDOW_SCALING_MODE_FREEZE)
uint32_t mScalingMode;
// mTimestamp is the current timestamp for this buffer slot. This gets
}
status_t BufferQueue::setTransformHint(uint32_t hint) {
+ ST_LOGV("setTransformHint: %02x", hint);
Mutex::Autolock lock(mMutex);
mTransformHint = hint;
return OK;
snprintf(buffer, SIZE,
"%s-BufferQueue maxBufferCount=%d, mSynchronousMode=%d, default-size=[%dx%d], "
- "default-format=%d, FIFO(%d)={%s}\n",
+ "default-format=%d, transform-hint=%02x, FIFO(%d)={%s}\n",
prefix, maxBufferCount, mSynchronousMode, mDefaultWidth,
- mDefaultHeight, mDefaultBufferFormat, fifoSize, fifo.string());
+ mDefaultHeight, mDefaultBufferFormat, mTransformHint,
+ fifoSize, fifo.string());
result.append(buffer);
EGLContext mProducerEglContext;
};
+TEST_F(SurfaceTextureGLToGLTest, TransformHintGetsRespected) {
+ const uint32_t texWidth = 32;
+ const uint32_t texHeight = 64;
+
+ mST->setDefaultBufferSize(texWidth, texHeight);
+ mST->setTransformHint(NATIVE_WINDOW_TRANSFORM_ROT_90);
+
+ // This test requires 3 buffers to avoid deadlock because we're
+ // both producer and consumer, and only using one thread.
+ mST->setDefaultMaxBufferCount(3);
+
+ // Do the producer side of things
+ EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mProducerEglSurface,
+ mProducerEglSurface, mProducerEglContext));
+ ASSERT_EQ(EGL_SUCCESS, eglGetError());
+
+ // Start a buffer with our chosen size and transform hint moving
+ // through the system.
+ glClear(GL_COLOR_BUFFER_BIT); // give the driver something to do
+ eglSwapBuffers(mEglDisplay, mProducerEglSurface);
+ mST->updateTexImage(); // consume it
+ // Swap again.
+ glClear(GL_COLOR_BUFFER_BIT);
+ eglSwapBuffers(mEglDisplay, mProducerEglSurface);
+ mST->updateTexImage();
+
+ // The current buffer should either show the effects of the transform
+ // hint (in the form of an inverse transform), or show that the
+ // transform hint has been ignored.
+ sp<GraphicBuffer> buf = mST->getCurrentBuffer();
+ if (mST->getCurrentTransform() == NATIVE_WINDOW_TRANSFORM_ROT_270) {
+ ASSERT_EQ(texWidth, buf->getHeight());
+ ASSERT_EQ(texHeight, buf->getWidth());
+ } else {
+ ASSERT_EQ(texWidth, buf->getWidth());
+ ASSERT_EQ(texHeight, buf->getHeight());
+ }
+
+ // Reset the transform hint and confirm that it takes.
+ mST->setTransformHint(0);
+ glClear(GL_COLOR_BUFFER_BIT);
+ eglSwapBuffers(mEglDisplay, mProducerEglSurface);
+ mST->updateTexImage();
+ glClear(GL_COLOR_BUFFER_BIT);
+ eglSwapBuffers(mEglDisplay, mProducerEglSurface);
+ mST->updateTexImage();
+
+ buf = mST->getCurrentBuffer();
+ ASSERT_EQ((uint32_t) 0, mST->getCurrentTransform());
+ ASSERT_EQ(texWidth, buf->getWidth());
+ ASSERT_EQ(texHeight, buf->getHeight());
+}
+
TEST_F(SurfaceTextureGLToGLTest, TexturingFromGLFilledRGBABufferPow2) {
const int texWidth = 64;
const int texHeight = 64;
return nanoseconds_to_milliseconds(elapsedRealtimeNano());
}
+#define METHOD_CLOCK_GETTIME 0
+#define METHOD_IOCTL 1
+#define METHOD_SYSTEMTIME 2
+
+static const char *gettime_method_names[] = {
+ "clock_gettime",
+ "ioctl",
+ "systemTime",
+};
+
+static inline void checkTimeStamps(int64_t timestamp,
+ int64_t volatile *prevTimestampPtr,
+ int volatile *prevMethodPtr,
+ int curMethod)
+{
+ /*
+ * Disable the check for SDK since the prebuilt toolchain doesn't contain
+ * gettid, and int64_t is different on the ARM platform
+ * (ie long vs long long).
+ */
+#ifdef ARCH_ARM
+ int64_t prevTimestamp = *prevTimestampPtr;
+ int prevMethod = *prevMethodPtr;
+
+ if (timestamp < prevTimestamp) {
+ ALOGW("time going backwards: prev %lld(%s) vs now %lld(%s), tid=%d",
+ prevTimestamp, gettime_method_names[prevMethod],
+ timestamp, gettime_method_names[curMethod],
+ gettid());
+ }
+ // NOTE - not atomic and may generate spurious warnings if the 64-bit
+ // write is interrupted or not observed as a whole.
+ *prevTimestampPtr = timestamp;
+ *prevMethodPtr = curMethod;
+#endif
+}
+
/*
* native public static long elapsedRealtimeNano();
*/
#ifdef HAVE_ANDROID_OS
struct timespec ts;
int result = clock_gettime(CLOCK_BOOTTIME, &ts);
+ int64_t timestamp;
+ static volatile int64_t prevTimestamp;
+ static volatile int prevMethod;
+
if (result == 0) {
- return seconds_to_nanoseconds(ts.tv_sec) + ts.tv_nsec;
+ timestamp = seconds_to_nanoseconds(ts.tv_sec) + ts.tv_nsec;
+ checkTimeStamps(timestamp, &prevTimestamp, &prevMethod,
+ METHOD_CLOCK_GETTIME);
+ return timestamp;
}
// CLOCK_BOOTTIME doesn't exist, fallback to /dev/alarm
if (android_atomic_cmpxchg(-1, fd, &s_fd)) {
close(fd);
}
- result = ioctl(s_fd,
- ANDROID_ALARM_GET_TIME(ANDROID_ALARM_ELAPSED_REALTIME), &ts);
}
+ result = ioctl(s_fd,
+ ANDROID_ALARM_GET_TIME(ANDROID_ALARM_ELAPSED_REALTIME), &ts);
+
if (result == 0) {
- return seconds_to_nanoseconds(ts.tv_sec) + ts.tv_nsec;
+ timestamp = seconds_to_nanoseconds(ts.tv_sec) + ts.tv_nsec;
+ checkTimeStamps(timestamp, &prevTimestamp, &prevMethod, METHOD_IOCTL);
+ return timestamp;
}
// XXX: there was an error, probably because the driver didn't
// exist ... this should return
// a real error, like an exception!
- return systemTime(SYSTEM_TIME_MONOTONIC);
+ timestamp = systemTime(SYSTEM_TIME_MONOTONIC);
+ checkTimeStamps(timestamp, &prevTimestamp, &prevMethod,
+ METHOD_SYSTEMTIME);
+ return timestamp;
#else
return systemTime(SYSTEM_TIME_MONOTONIC);
#endif
#else
mSurfaceTexture->setDefaultMaxBufferCount(3);
#endif
+
+ updateTransformHint();
}
Layer::~Layer()
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,
}
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,
Reject r(mDrawingState, currentState(), recomputeVisibleRegions);
- // XXX: not sure if setTransformHint belongs here
- // it should only be needed when the main screen orientation changes
- mSurfaceTexture->setTransformHint(getTransformHint());
-
if (mSurfaceTexture->updateTexImage(&r) < NO_ERROR) {
// something happened!
recomputeVisibleRegions = true;
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);
return usage;
}
-uint32_t Layer::getTransformHint() const {
+void Layer::updateTransformHint() const {
uint32_t orientation = 0;
if (!mFlinger->mDebugDisableTransformHint) {
// The transform hint is used to improve performance on the main
orientation = 0;
}
}
- return orientation;
+ mSurfaceTexture->setTransformHint(orientation);
}
// ---------------------------------------------------------------------------
// 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 default display device.
+ virtual void updateTransformHint() const;
+
protected:
virtual void onFirstRef();
virtual void dump(String8& result, char* scratch, size_t size) const;
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);
*/
virtual void onPostComposition() { }
+ /**
+ * Updates the SurfaceTexture's transform hint, for layers that have
+ * a SurfaceTexture.
+ */
+ virtual void updateTransformHint() 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;
disp->setProjection(state.orientation,
state.viewport, state.frame);
}
+
+ // Walk through all the layers in currentLayers,
+ // and update their transform hint.
+ //
+ // TODO: we could be much more clever about which
+ // layers we touch and how often we do these updates
+ // (e.g. only touch the layers associated with this
+ // display, and only on a rotation).
+ for (size_t i = 0; i < count; i++) {
+ const sp<LayerBase>& layerBase = currentLayers[i];
+ layerBase->updateTransformHint();
+ }
}
}
}