#include "DisplayHardware/FramebufferSurface.h"
#include "DisplayHardware/HWComposer.h"
+#include "clz.h"
#include "DisplayDevice.h"
#include "GLExtensions.h"
#include "SurfaceFlinger.h"
DisplayDevice::DisplayDevice(
const sp<SurfaceFlinger>& flinger,
- int display,
+ DisplayType type,
+ bool isSecure,
+ const wp<IBinder>& displayToken,
const sp<ANativeWindow>& nativeWindow,
const sp<FramebufferSurface>& framebufferSurface,
EGLConfig config)
: mFlinger(flinger),
- mId(display),
+ mType(type), mHwcDisplayId(-1),
mNativeWindow(nativeWindow),
mFramebufferSurface(framebufferSurface),
mDisplay(EGL_NO_DISPLAY),
mDisplayWidth(), mDisplayHeight(), mFormat(),
mFlags(),
mPageFlipCount(),
+ mIsSecure(isSecure),
mSecureLayerVisible(false),
mScreenAcquired(false),
- mOrientation(),
- mLayerStack(0)
+ mLayerStack(0),
+ mOrientation()
{
init(config);
}
mSurface = surface;
mFormat = format;
mPageFlipCount = 0;
+ mViewport.makeInvalid();
+ mFrame.makeInvalid();
// external displays are always considered enabled
- mScreenAcquired = mId >= DisplayDevice::DISPLAY_ID_COUNT;
+ 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.
- DisplayDevice::setOrientation(DisplayState::eOrientationDefault);
+ 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 {
b.left, b.top, b.width(), b.height());
}
#endif
-
+
mPageFlipCount++;
}
-uint32_t DisplayDevice::getFlags() const
-{
- return mFlags;
+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::dump(String8& res) const
-{
- if (mFramebufferSurface != NULL) {
- mFramebufferSurface->dump(res);
+void DisplayDevice::onSwapBuffersCompleted(HWComposer& hwc) const {
+ if (hwc.initCheck() == NO_ERROR) {
+ if (hwc.supportsFramebufferTarget()) {
+ int fd = hwc.getAndResetReleaseFenceFd(mType);
+ mFramebufferSurface->setReleaseFenceFd(fd);
+ }
}
}
-void DisplayDevice::makeCurrent(const sp<const DisplayDevice>& hw, EGLContext ctx) {
+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) {
- EGLDisplay dpy = eglGetCurrentDisplay();
- eglMakeCurrent(dpy, hw->mSurface, hw->mSurface, ctx);
+ 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);
}
// ----------------------------------------------------------------------------
}
}
-Vector< sp<LayerBase> > DisplayDevice::getVisibleLayersSortedByZ() const {
+const Vector< sp<LayerBase> >& DisplayDevice::getVisibleLayersSortedByZ() const {
return mVisibleLayersSortedByZ;
}
Region DisplayDevice::getDirtyRegion(bool repaintEverything) const {
Region dirty;
- const Transform& planeTransform(mGlobalTransform);
if (repaintEverything) {
dirty.set(getBounds());
} else {
+ const Transform& planeTransform(mGlobalTransform);
dirty = planeTransform.transform(this->dirtyRegion);
dirty.andSelf(getBounds());
}
return NO_ERROR;
}
-status_t DisplayDevice::setOrientation(int orientation) {
+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);
+ }
- DisplayDevice::orientationToTransfrom(
- orientation, w, h, &mGlobalTransform);
- if (orientation & DisplayState::eOrientationSwapMask) {
- int tmp = w;
- w = h;
- h = tmp;
+ 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);
}
- mOrientation = orientation;
- dirtyRegion.set(bounds());
- return NO_ERROR;
}