Merge "CpuConsumer_test: Extend test with new formats RGBA8888 and optional Y8/Y16" into jb-mr2-dev
diff --git a/include/gui/ISurfaceComposer.h b/include/gui/ISurfaceComposer.h
index 4862949..08eddcb 100644
--- a/include/gui/ISurfaceComposer.h
+++ b/include/gui/ISurfaceComposer.h
@@ -103,7 +103,6 @@
uint32_t reqWidth, uint32_t reqHeight,
uint32_t minLayerZ, uint32_t maxLayerZ) = 0;
-
/* triggers screen off and waits for it to complete */
virtual void blank(const sp<IBinder>& display) = 0;
@@ -113,6 +112,11 @@
/* returns information about a display
* intended to be used to get information about built-in displays */
virtual status_t getDisplayInfo(const sp<IBinder>& display, DisplayInfo* info) = 0;
+
+ virtual status_t captureScreen(const sp<IBinder>& display,
+ const sp<IGraphicBufferProducer>& producer,
+ uint32_t reqWidth, uint32_t reqHeight,
+ uint32_t minLayerZ, uint32_t maxLayerZ) = 0;
};
// ----------------------------------------------------------------------------
@@ -130,11 +134,12 @@
GET_BUILT_IN_DISPLAY,
SET_TRANSACTION_STATE,
AUTHENTICATE_SURFACE,
- CAPTURE_SCREEN,
+ CAPTURE_SCREEN_DEPRECATED,
BLANK,
UNBLANK,
GET_DISPLAY_INFO,
CONNECT_DISPLAY,
+ CAPTURE_SCREEN,
};
virtual status_t onTransact(uint32_t code, const Parcel& data,
diff --git a/include/gui/SurfaceComposerClient.h b/include/gui/SurfaceComposerClient.h
index 9e4d6fc..38c931d 100644
--- a/include/gui/SurfaceComposerClient.h
+++ b/include/gui/SurfaceComposerClient.h
@@ -156,10 +156,19 @@
class ScreenshotClient
{
+public:
+ static status_t capture(
+ const sp<IBinder>& display,
+ const sp<IGraphicBufferProducer>& producer,
+ uint32_t reqWidth, uint32_t reqHeight,
+ uint32_t minLayerZ, uint32_t maxLayerZ);
+
+private:
sp<IMemoryHeap> mHeap;
uint32_t mWidth;
uint32_t mHeight;
PixelFormat mFormat;
+
public:
ScreenshotClient();
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index 72b6277..0a79ff7 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -115,7 +115,7 @@
data.writeInt32(reqHeight);
data.writeInt32(minLayerZ);
data.writeInt32(maxLayerZ);
- remote()->transact(BnSurfaceComposer::CAPTURE_SCREEN, data, &reply);
+ remote()->transact(BnSurfaceComposer::CAPTURE_SCREEN_DEPRECATED, data, &reply);
*heap = interface_cast<IMemoryHeap>(reply.readStrongBinder());
*width = reply.readInt32();
*height = reply.readInt32();
@@ -123,6 +123,23 @@
return reply.readInt32();
}
+ virtual status_t captureScreen(const sp<IBinder>& display,
+ const sp<IGraphicBufferProducer>& producer,
+ uint32_t reqWidth, uint32_t reqHeight,
+ uint32_t minLayerZ, uint32_t maxLayerZ)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+ data.writeStrongBinder(display);
+ data.writeStrongBinder(producer->asBinder());
+ data.writeInt32(reqWidth);
+ data.writeInt32(reqHeight);
+ data.writeInt32(minLayerZ);
+ data.writeInt32(maxLayerZ);
+ remote()->transact(BnSurfaceComposer::CAPTURE_SCREEN, data, &reply);
+ return reply.readInt32();
+ }
+
virtual bool authenticateSurfaceTexture(
const sp<IGraphicBufferProducer>& bufferProducer) const
{
@@ -268,7 +285,7 @@
CHECK_INTERFACE(ISurfaceComposer, data, reply);
bootFinished();
} break;
- case CAPTURE_SCREEN: {
+ case CAPTURE_SCREEN_DEPRECATED: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
sp<IBinder> display = data.readStrongBinder();
uint32_t reqWidth = data.readInt32();
@@ -286,6 +303,19 @@
reply->writeInt32(f);
reply->writeInt32(res);
} break;
+ case CAPTURE_SCREEN: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
+ sp<IBinder> display = data.readStrongBinder();
+ sp<IGraphicBufferProducer> producer =
+ interface_cast<IGraphicBufferProducer>(data.readStrongBinder());
+ uint32_t reqWidth = data.readInt32();
+ uint32_t reqHeight = data.readInt32();
+ uint32_t minLayerZ = data.readInt32();
+ uint32_t maxLayerZ = data.readInt32();
+ status_t res = captureScreen(display, producer,
+ reqWidth, reqHeight, minLayerZ, maxLayerZ);
+ reply->writeInt32(res);
+ } break;
case AUTHENTICATE_SURFACE: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
sp<IGraphicBufferProducer> bufferProducer =
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index 410ad5d..950d16a 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -735,7 +735,7 @@
sp<Surface> Surface::readFromParcel(const Parcel& data) {
sp<IBinder> binder(data.readStrongBinder());
sp<IGraphicBufferProducer> bp(interface_cast<IGraphicBufferProducer>(binder));
- return new Surface(bp);
+ return bp != NULL ? new Surface(bp): NULL;
}
// ----------------------------------------------------------------------------
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index e8e208f..edfa78a 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -606,6 +606,17 @@
// ----------------------------------------------------------------------------
+status_t ScreenshotClient::capture(
+ const sp<IBinder>& display,
+ const sp<IGraphicBufferProducer>& producer,
+ uint32_t reqWidth, uint32_t reqHeight,
+ uint32_t minLayerZ, uint32_t maxLayerZ) {
+ sp<ISurfaceComposer> s(ComposerService::getComposerService());
+ if (s == NULL) return NO_INIT;
+ return s->captureScreen(display, producer,
+ reqWidth, reqHeight, minLayerZ, maxLayerZ);
+}
+
ScreenshotClient::ScreenshotClient()
: mWidth(0), mHeight(0), mFormat(PIXEL_FORMAT_NONE) {
}
diff --git a/opengl/include/EGL/eglext.h b/opengl/include/EGL/eglext.h
index 8578874..c8d228c 100644
--- a/opengl/include/EGL/eglext.h
+++ b/opengl/include/EGL/eglext.h
@@ -311,6 +311,18 @@
#define EGL_FRAMEBUFFER_TARGET_ANDROID 0x3147
#endif
+/* EGL_ANDROID_presentation_time
+ */
+#ifndef EGL_ANDROID_presentation_time
+#define EGL_ANDROID_presentation_time 1
+typedef khronos_stime_nanoseconds_t EGLnsecsANDROID;
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean eglPresentationTimeANDROID(EGLDisplay dpy, EGLSurface sur, EGLnsecsANDROID time);
+#else
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLPRESENTATIONTIMEANDROID) (EGLDisplay dpy, EGLSurface sur, EGLnsecsANDROID time);
+#endif
+#endif
+
#ifdef __cplusplus
}
#endif
diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp
index ed9db94..978ab04 100644
--- a/opengl/libs/EGL/eglApi.cpp
+++ b/opengl/libs/EGL/eglApi.cpp
@@ -1307,6 +1307,28 @@
return result;
}
+EGLBoolean eglPresentationTimeANDROID(EGLDisplay dpy, EGLSurface surface,
+ EGLnsecsANDROID time)
+{
+ clearError();
+
+ const egl_display_ptr dp = validate_display(dpy);
+ if (!dp) {
+ return EGL_FALSE;
+ }
+
+ SurfaceRef _s(dp.get(), surface);
+ if (!_s.get()) {
+ setError(EGL_BAD_SURFACE, EGL_FALSE);
+ return EGL_FALSE;
+ }
+
+ egl_surface_t const * const s = get_surface(surface);
+ native_window_set_buffers_timestamp(s->win.get(), time);
+
+ return EGL_TRUE;
+}
+
// ----------------------------------------------------------------------------
// NVIDIA extensions
// ----------------------------------------------------------------------------
diff --git a/opengl/tools/glgen/specs/egl/EGL14.spec b/opengl/tools/glgen/specs/egl/EGL14.spec
index 828e114..aef0bcb 100644
--- a/opengl/tools/glgen/specs/egl/EGL14.spec
+++ b/opengl/tools/glgen/specs/egl/EGL14.spec
@@ -31,3 +31,4 @@
EGLBoolean eglWaitNative ( EGLint engine )
EGLBoolean eglSwapBuffers ( EGLDisplay dpy, EGLSurface surface )
EGLBoolean eglCopyBuffers ( EGLDisplay dpy, EGLSurface surface, EGLNativePixmapType target )
+EGLBoolean eglPresentationTimeANDROID ( EGLDisplay dpy, EGLSurface sur, EGLnsecsANDROID time )
diff --git a/opengl/tools/glgen/src/JType.java b/opengl/tools/glgen/src/JType.java
index 3f7cb73..994e609 100644
--- a/opengl/tools/glgen/src/JType.java
+++ b/opengl/tools/glgen/src/JType.java
@@ -56,6 +56,7 @@
typeMapping.put(new CType("EGLNativeWindowType"), new JType("int"));
typeMapping.put(new CType("EGLNativeDisplayType"), new JType("int"));
typeMapping.put(new CType("EGLClientBuffer"), new JType("int"));
+ typeMapping.put(new CType("EGLnsecsANDROID"), new JType("long"));
// EGL nonprimitive types
typeMapping.put(new CType("EGLConfig"), new JType("EGLConfig", true, false));
diff --git a/opengl/tools/glgen/src/JniCodeEmitter.java b/opengl/tools/glgen/src/JniCodeEmitter.java
index 01c5c48..ffe3767 100644
--- a/opengl/tools/glgen/src/JniCodeEmitter.java
+++ b/opengl/tools/glgen/src/JniCodeEmitter.java
@@ -54,7 +54,7 @@
} else if (baseType.equals("short")) {
jniName += "S";
} else if (baseType.equals("long")) {
- jniName += "L";
+ jniName += "J";
} else if (baseType.equals("byte")) {
jniName += "B";
} else if (baseType.equals("String")) {
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index 9466944..ed2768c 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -89,7 +89,7 @@
mIsSecure(isSecure),
mSecureLayerVisible(false),
mScreenAcquired(false),
- mLayerStack(0),
+ mLayerStack(NO_LAYER_STACK),
mOrientation()
{
init(config);
@@ -196,13 +196,13 @@
EGLDisplay dpy = mDisplay;
EGLSurface surface = mSurface;
-#ifdef EGL_ANDROID_swap_rectangle
+#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++;
@@ -287,7 +287,8 @@
mSecureLayerVisible = false;
size_t count = layers.size();
for (size_t i=0 ; i<count ; i++) {
- if (layers[i]->isSecure()) {
+ const sp<LayerBase>& layer(layers[i]);
+ if (layer->isSecure()) {
mSecureLayerVisible = true;
}
}
@@ -365,74 +366,72 @@
}
void DisplayDevice::setProjection(int orientation,
- const Rect& viewport, const Rect& frame) {
+ const Rect& newViewport, const Rect& newFrame) {
+ Rect viewport(newViewport);
+ Rect frame(newFrame);
+
+ const int w = mDisplayWidth;
+ const int h = mDisplayHeight;
+
+ Transform R;
+ DisplayDevice::orientationToTransfrom(orientation, w, h, &R);
+
+ 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);
+ }
+ }
+
+ dirtyRegion.set(getBounds());
+
+ Transform TL, TP, S;
+ 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));
+
+ mScissor = mGlobalTransform.transform(viewport);
+ if (mScissor.isEmpty()) {
+ mScissor.set(getBounds());
+ }
+
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));
-
- mScissor = mGlobalTransform.transform(mViewport);
- if (mScissor.isEmpty()) {
- mScissor.set(getBounds());
- }
- }
}
void DisplayDevice::dump(String8& result, char* buffer, size_t SIZE) const {
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index bb6eb70..91f34db 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -65,6 +65,10 @@
SWAP_RECTANGLE = 0x00080000,
};
+ enum {
+ NO_LAYER_STACK = 0xFFFFFFFF,
+ };
+
DisplayDevice(
const sp<SurfaceFlinger>& flinger,
DisplayType type,
@@ -105,8 +109,8 @@
int getOrientation() const { return mOrientation; }
const Transform& getTransform() const { return mGlobalTransform; }
- const Rect& getViewport() const { return mViewport; }
- const Rect& getFrame() const { return mFrame; }
+ const Rect getViewport() const { return mViewport; }
+ const Rect getFrame() const { return mFrame; }
const Rect& getScissor() const { return mScissor; }
bool needsFiltering() const { return mNeedsFiltering; }
@@ -117,7 +121,7 @@
void swapBuffers(HWComposer& hwc) const;
status_t compositionComplete() const;
-
+
// called after h/w composer has completed its set() call
void onSwapBuffersCompleted(HWComposer& hwc) const;
@@ -197,8 +201,6 @@
static status_t orientationToTransfrom(int orientation,
int w, int h, Transform* tr);
- void updateGeometryTransform();
-
uint32_t mLayerStack;
int mOrientation;
// user-provided visible area of the layer stack
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 439acb5..c9f1eb5 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -19,7 +19,6 @@
#include <stdlib.h>
#include <stdint.h>
#include <sys/types.h>
-#include <math.h>
#include <cutils/compiler.h>
#include <cutils/native_handle.h>
@@ -200,48 +199,27 @@
return NO_ERROR;
}
-Rect Layer::computeBufferCrop() const {
- // Start with the SurfaceFlingerConsumer's buffer crop...
+Rect Layer::getContentCrop() const {
+ // this is the crop rectangle that applies to the buffer
+ // itself (as opposed to the window)
Rect crop;
if (!mCurrentCrop.isEmpty()) {
+ // if the buffer crop is defined, we use that
crop = mCurrentCrop;
- } else if (mActiveBuffer != NULL){
- crop = Rect(mActiveBuffer->getWidth(), mActiveBuffer->getHeight());
+ } else if (mActiveBuffer != NULL) {
+ // otherwise we use the whole buffer
+ crop = mActiveBuffer->getBounds();
} else {
+ // if we don't have a buffer yet, we use an empty/invalid crop
crop.makeInvalid();
- return crop;
}
-
- // ... then reduce that in the same proportions as the window crop reduces
- // the window size.
- const State& s(drawingState());
- if (!s.active.crop.isEmpty()) {
- // Transform the window crop to match the buffer coordinate system,
- // which means using the inverse of the current transform set on the
- // SurfaceFlingerConsumer.
- uint32_t invTransform = mCurrentTransform;
- int winWidth = s.active.w;
- int winHeight = s.active.h;
- if (invTransform & NATIVE_WINDOW_TRANSFORM_ROT_90) {
- invTransform ^= NATIVE_WINDOW_TRANSFORM_FLIP_V |
- NATIVE_WINDOW_TRANSFORM_FLIP_H;
- winWidth = s.active.h;
- winHeight = s.active.w;
- }
- Rect winCrop = s.active.crop.transform(invTransform,
- s.active.w, s.active.h);
-
- float xScale = float(crop.width()) / float(winWidth);
- float yScale = float(crop.height()) / float(winHeight);
- crop.left += int(ceilf(float(winCrop.left) * xScale));
- crop.top += int(ceilf(float(winCrop.top) * yScale));
- crop.right -= int(ceilf(float(winWidth - winCrop.right) * xScale));
- crop.bottom -= int(ceilf(float(winHeight - winCrop.bottom) * yScale));
- }
-
return crop;
}
+uint32_t Layer::getContentTransform() const {
+ return mCurrentTransform;
+}
+
void Layer::setGeometry(
const sp<const DisplayDevice>& hw,
HWComposer::HWCLayerInterface& layer)
@@ -278,7 +256,6 @@
} else {
layer.setTransform(finalTransform);
}
- layer.setCrop(computeBufferCrop());
}
void Layer::setPerFrameData(const sp<const DisplayDevice>& hw,
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index a82767b..e57fb59 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -103,19 +103,25 @@
// the current orientation of the display device.
virtual void updateTransformHint(const sp<const DisplayDevice>& hw) const;
+ virtual Rect getContentCrop() const;
+ virtual uint32_t getContentTransform() const;
+
protected:
virtual void onFirstRef();
virtual void dump(String8& result, char* scratch, size_t size) const;
virtual void dumpStats(String8& result, char* buffer, size_t SIZE) const;
virtual void clearStats();
+ sp<SurfaceFlingerConsumer> getConsumer() const {
+ return mSurfaceFlingerConsumer;
+ }
+
private:
// Creates an instance of ISurface for this Layer.
virtual sp<ISurface> createSurface();
uint32_t getEffectiveUsage(uint32_t usage) const;
bool isCropped() const;
- Rect computeBufferCrop() const;
static bool getOpacityForFormat(uint32_t format);
// Interface implementation for SurfaceFlingerConsumer::FrameAvailableListener
diff --git a/services/surfaceflinger/LayerBase.cpp b/services/surfaceflinger/LayerBase.cpp
index dfdbf30..db2b20e 100644
--- a/services/surfaceflinger/LayerBase.cpp
+++ b/services/surfaceflinger/LayerBase.cpp
@@ -17,6 +17,7 @@
#include <stdlib.h>
#include <stdint.h>
#include <sys/types.h>
+#include <math.h>
#include <utils/Errors.h>
#include <utils/Log.h>
@@ -259,7 +260,7 @@
if (!s.active.crop.isEmpty()) {
win.intersect(s.active.crop, &win);
}
- return s.transform.transform(win);
+ return win;
}
Region LayerBase::latchBuffer(bool& recomputeVisibleRegions) {
@@ -267,6 +268,83 @@
return result;
}
+
+Rect LayerBase::getContentCrop() const {
+ // regular layers just use their active area as the content crop
+ const State& s(drawingState());
+ return Rect(s.active.w, s.active.h);
+}
+
+uint32_t LayerBase::getContentTransform() const {
+ // regular layers don't have a content transform
+ return 0;
+}
+
+Rect LayerBase::computeCrop(const sp<const DisplayDevice>& hw) const {
+ /*
+ * The way we compute the crop (aka. texture coordinates when we have a
+ * Layer) produces a different output from the GL code in
+ * drawWithOpenGL() due to HWC being limited to integers. The difference
+ * can be large if getContentTransform() contains a large scale factor.
+ * See comments in drawWithOpenGL() for more details.
+ */
+
+ // the content crop is the area of the content that gets scaled to the
+ // layer's size.
+ Rect crop(getContentCrop());
+
+ // the active.crop is the area of the window that gets cropped, but not
+ // scaled in any ways.
+ const State& s(drawingState());
+
+ // apply the projection's clipping to the window crop in
+ // layerstack space, and convert-back to layer space.
+ // if there are no window scaling (or content scaling) involved,
+ // this operation will map to full pixels in the buffer.
+ // NOTE: should we revert to GL composition if a scaling is involved
+ // since it cannot be represented in the HWC API?
+ Rect activeCrop(s.transform.transform(s.active.crop));
+ activeCrop.intersect(hw->getViewport(), &activeCrop);
+ activeCrop = s.transform.inverse().transform(activeCrop);
+
+ // paranoia: make sure the window-crop is constrained in the
+ // window's bounds
+ activeCrop.intersect(Rect(s.active.w, s.active.h), &activeCrop);
+
+ if (!activeCrop.isEmpty()) {
+ // Transform the window crop to match the buffer coordinate system,
+ // which means using the inverse of the current transform set on the
+ // SurfaceFlingerConsumer.
+ uint32_t invTransform = getContentTransform();
+ int winWidth = s.active.w;
+ int winHeight = s.active.h;
+ if (invTransform & NATIVE_WINDOW_TRANSFORM_ROT_90) {
+ invTransform ^= NATIVE_WINDOW_TRANSFORM_FLIP_V |
+ NATIVE_WINDOW_TRANSFORM_FLIP_H;
+ winWidth = s.active.h;
+ winHeight = s.active.w;
+ }
+ const Rect winCrop = activeCrop.transform(
+ invTransform, s.active.w, s.active.h);
+
+ // the code below essentially performs a scaled intersection
+ // of crop and winCrop
+ float xScale = float(crop.width()) / float(winWidth);
+ float yScale = float(crop.height()) / float(winHeight);
+
+ int insetL = int(ceilf( winCrop.left * xScale));
+ int insetT = int(ceilf( winCrop.top * yScale));
+ int insetR = int(ceilf((winWidth - winCrop.right ) * xScale));
+ int insetB = int(ceilf((winHeight - winCrop.bottom) * yScale));
+
+ crop.left += insetL;
+ crop.top += insetT;
+ crop.right -= insetR;
+ crop.bottom -= insetB;
+ }
+ return crop;
+}
+
void LayerBase::setGeometry(
const sp<const DisplayDevice>& hw,
HWComposer::HWCLayerInterface& layer)
@@ -289,13 +367,15 @@
HWC_BLENDING_COVERAGE);
}
- 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());
+ // apply the layer's transform, followed by the display's global transform
+ // here we're guaranteed that the layer's transform preserves rects
+
+ Rect frame(s.transform.transform(computeBounds()));
+ frame.intersect(hw->getViewport(), &frame);
+ const Transform& tr(hw->getTransform());
+ layer.setFrame(tr.transform(frame));
+ layer.setCrop(computeCrop(hw));
}
void LayerBase::setPerFrameData(const sp<const DisplayDevice>& hw,
@@ -303,8 +383,11 @@
// 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.
+ // Apply this display's projection's viewport to the visible region
+ // before giving it to the HWC HAL.
const Transform& tr = hw->getTransform();
- layer.setVisibleRegionScreen(tr.transform(visibleRegion));
+ Region visible = tr.transform(visibleRegion.intersect(hw->getViewport()));
+ layer.setVisibleRegionScreen(visible);
}
void LayerBase::setAcquireFence(const sp<const DisplayDevice>& hw,
@@ -404,10 +487,22 @@
GLfloat v;
};
- Rect win(s.active.w, s.active.h);
- if (!s.active.crop.isEmpty()) {
- win.intersect(s.active.crop, &win);
- }
+
+ /*
+ * NOTE: the way we compute the texture coordinates here produces
+ * different results than when we take the HWC path -- in the later case
+ * the "source crop" is rounded to texel boundaries.
+ * This can produce significantly different results when the texture
+ * is scaled by a large amount.
+ *
+ * The GL code below is more logical (imho), and the difference with
+ * HWC is due to a limitation of the HWC API to integers -- a question
+ * is suspend is wether we should ignore this problem or revert to
+ * GL composition when a buffer scaling is applied (maybe with some
+ * minimal value)? Or, we could make GL behave like HWC -- but this feel
+ * like more of a hack.
+ */
+ const Rect win(computeBounds());
GLfloat left = GLfloat(win.left) / GLfloat(s.active.w);
GLfloat top = GLfloat(win.top) / GLfloat(s.active.h);
diff --git a/services/surfaceflinger/LayerBase.h b/services/surfaceflinger/LayerBase.h
index c2624df..ecae2d9 100644
--- a/services/surfaceflinger/LayerBase.h
+++ b/services/surfaceflinger/LayerBase.h
@@ -260,6 +260,18 @@
*/
virtual void updateTransformHint(const sp<const DisplayDevice>& hw) const { }
+ /**
+ * returns the rectangle that crops the content of the layer and scales it
+ * to the layer's size.
+ */
+ virtual Rect getContentCrop() const;
+
+ /*
+ * returns the transform bits (90 rotation / h-flip / v-flip) of the
+ * layer's content
+ */
+ virtual uint32_t getContentTransform() 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;
@@ -282,6 +294,9 @@
void setFiltering(bool filtering);
bool getFiltering() const;
+private:
+ Rect computeCrop(const sp<const DisplayDevice>& hw) const;
+
protected:
void clearWithOpenGL(const sp<const DisplayDevice>& hw, const Region& clip,
GLclampf r, GLclampf g, GLclampf b, GLclampf alpha) const;
diff --git a/services/surfaceflinger/LayerScreenshot.cpp b/services/surfaceflinger/LayerScreenshot.cpp
index f8009b3..3470d67 100644
--- a/services/surfaceflinger/LayerScreenshot.cpp
+++ b/services/surfaceflinger/LayerScreenshot.cpp
@@ -18,152 +18,28 @@
#include <stdint.h>
#include <sys/types.h>
-#include <GLES/gl.h>
-#include <GLES/glext.h>
-
-#include <utils/Errors.h>
-#include <utils/Log.h>
-
-#include <ui/GraphicBuffer.h>
-
#include "LayerScreenshot.h"
#include "SurfaceFlinger.h"
#include "DisplayDevice.h"
-
namespace android {
// ---------------------------------------------------------------------------
LayerScreenshot::LayerScreenshot(SurfaceFlinger* flinger,
const sp<Client>& client)
- : LayerBaseClient(flinger, client),
- mTextureName(0), mFlinger(flinger), mIsSecure(false)
+ : Layer(flinger, client)
{
}
-LayerScreenshot::~LayerScreenshot()
+void LayerScreenshot::onFirstRef()
{
- if (mTextureName) {
- mFlinger->deleteTextureAsync(mTextureName);
- }
-}
+ Layer::onFirstRef();
-status_t LayerScreenshot::captureLocked(int32_t layerStack) {
- GLfloat 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;
-}
-
-status_t LayerScreenshot::capture() {
- GLfloat u, v;
- status_t result = mFlinger->renderScreenToTexture(0, &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;
-}
-
-void LayerScreenshot::initTexture(GLfloat u, GLfloat v) {
- glBindTexture(GL_TEXTURE_2D, mTextureName);
- glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- mTexCoords[0] = 0; mTexCoords[1] = v;
- mTexCoords[2] = 0; mTexCoords[3] = 0;
- mTexCoords[4] = u; mTexCoords[5] = 0;
- mTexCoords[6] = u; mTexCoords[7] = v;
-}
-
-void LayerScreenshot::initStates(uint32_t w, uint32_t h, uint32_t flags) {
- LayerBaseClient::initStates(w, h, flags);
- 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 LayerBase::State& draw(drawingState());
- const LayerBase::State& curr(currentState());
-
- 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(curr.layerStack);
- if (err != NO_ERROR) {
- ALOGW("createScreenshotSurface failed (%s)", strerror(-err));
- }
- }
- } else if (curr.flags & layer_state_t::eLayerHidden) {
- // we're going from visible to hidden
- if (mTextureName) {
- glDeleteTextures(1, &mTextureName);
- mTextureName = 0;
- }
- }
- return LayerBaseClient::doTransaction(flags);
-}
-
-void LayerScreenshot::onDraw(const sp<const DisplayDevice>& hw, const Region& clip) const
-{
- const State& s(drawingState());
- if (s.alpha>0) {
- const GLfloat alpha = s.alpha/255.0f;
- 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_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();
- }
-
- LayerMesh mesh;
- computeGeometry(hw, &mesh);
-
- glColor4f(alpha, alpha, alpha, alpha);
-
- glDisable(GL_TEXTURE_EXTERNAL_OES);
- glEnable(GL_TEXTURE_2D);
-
- 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, mesh.getVertices());
- glDrawArrays(GL_TRIANGLE_FAN, 0, mesh.getVertexCount());
-
- glDisable(GL_BLEND);
- glDisable(GL_TEXTURE_2D);
- glDisableClientState(GL_TEXTURE_COORD_ARRAY);
- }
+ // FIXME: we currently hardcode the default display
+ // it's unclear what should we do instead.
+ sp<const DisplayDevice> hw(mFlinger->getDefaultDisplayDevice());
+ mFlinger->captureScreenImplLocked(hw, getConsumer()->getBufferQueue(),
+ 0, 0, 0, 0x7FFFFFFF);
}
// ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/LayerScreenshot.h b/services/surfaceflinger/LayerScreenshot.h
index 38cbd88..a2ae03f 100644
--- a/services/surfaceflinger/LayerScreenshot.h
+++ b/services/surfaceflinger/LayerScreenshot.h
@@ -20,39 +20,18 @@
#include <stdint.h>
#include <sys/types.h>
-#include <EGL/egl.h>
-#include <EGL/eglext.h>
-
-#include "LayerBase.h"
+#include "Layer.h"
// ---------------------------------------------------------------------------
namespace android {
-class LayerScreenshot : public LayerBaseClient
+class LayerScreenshot : public Layer
{
- GLuint mTextureName;
- GLfloat mTexCoords[8];
- sp<SurfaceFlinger> mFlinger;
- bool mIsSecure;
public:
- 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 sp<const DisplayDevice>& hw, const Region& clip) const;
- virtual bool isOpaque() 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(int32_t layerStack);
- void initTexture(GLfloat u, GLfloat v);
+ LayerScreenshot(SurfaceFlinger* flinger, const sp<Client>& client);
+protected:
+ virtual void onFirstRef();
};
// ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index ee3e93b..8fa0800 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1347,7 +1347,7 @@
// start with the whole surface at its current location
const Layer::State& s(layer->drawingState());
- // only consider the layers on the given later stack
+ // only consider the layers on the given layer stack
if (s.layerStack != layerStack)
continue;
@@ -1384,7 +1384,7 @@
// handle hidden surfaces by setting the visible region to empty
if (CC_LIKELY(layer->isVisible())) {
const bool translucent = !layer->isOpaque();
- Rect bounds(layer->computeBounds());
+ Rect bounds(s.transform.transform(layer->computeBounds()));
visibleRegion.set(bounds);
if (!visibleRegion.isEmpty()) {
// Remove the transparent area from the visible region
@@ -2020,6 +2020,7 @@
uint32_t w, uint32_t h, uint32_t flags)
{
sp<LayerScreenshot> layer = new LayerScreenshot(this, client);
+ layer->setBuffers(w, h, PIXEL_FORMAT_RGBA_8888, flags);
return layer;
}
@@ -2072,12 +2073,14 @@
// ---------------------------------------------------------------------------
void SurfaceFlinger::onInitializeDisplays() {
- // reset screen orientation
+ // reset screen orientation and use primary layer stack
Vector<ComposerState> state;
Vector<DisplayState> displays;
DisplayState d;
- d.what = DisplayState::eDisplayProjectionChanged;
+ d.what = DisplayState::eDisplayProjectionChanged |
+ DisplayState::eLayerStackChanged;
d.token = mBuiltinDisplays[DisplayDevice::DISPLAY_PRIMARY];
+ d.layerStack = 0;
d.orientation = DisplayState::eOrientationDefault;
d.frame.makeInvalid();
d.viewport.makeInvalid();
@@ -2603,101 +2606,69 @@
}
// ---------------------------------------------------------------------------
-
-status_t SurfaceFlinger::renderScreenToTexture(uint32_t layerStack,
- GLuint* textureName, GLfloat* uOut, GLfloat* vOut)
-{
- Mutex::Autolock _l(mStateLock);
- return renderScreenToTextureLocked(layerStack, textureName, uOut, vOut);
-}
-
-status_t SurfaceFlinger::renderScreenToTextureLocked(uint32_t layerStack,
- GLuint* textureName, GLfloat* uOut, GLfloat* vOut)
-{
- ATRACE_CALL();
-
- if (!GLExtensions::getInstance().haveFramebufferObject())
- return INVALID_OPERATION;
-
- // get screen geometry
- // 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;
-
- // make sure to clear all GL error flags
- while ( glGetError() != GL_NO_ERROR ) ;
-
- // create a FBO
- GLuint name, tname;
- glGenTextures(1, &tname);
- glBindTexture(GL_TEXTURE_2D, tname);
- glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB,
- hw_w, hw_h, 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
- if (glGetError() != GL_NO_ERROR) {
- while ( glGetError() != GL_NO_ERROR ) ;
- GLint tw = (2 << (31 - clz(hw_w)));
- GLint th = (2 << (31 - clz(hw_h)));
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB,
- tw, th, 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
- u = GLfloat(hw_w) / tw;
- v = GLfloat(hw_h) / th;
- }
- glGenFramebuffersOES(1, &name);
- glBindFramebufferOES(GL_FRAMEBUFFER_OES, name);
- 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);
- glClearColor(0,0,0,1);
- glClear(GL_COLOR_BUFFER_BIT);
- glMatrixMode(GL_MODELVIEW);
- glLoadIdentity();
- 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->draw(hw);
- }
-
- hw->compositionComplete();
-
- // back to main framebuffer
- glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0);
- glDeleteFramebuffersOES(1, &name);
-
- *textureName = tname;
- *uOut = u;
- *vOut = v;
- return NO_ERROR;
-}
-
+// Capture screen into an IGraphiBufferProducer
// ---------------------------------------------------------------------------
-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,
+status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
+ const sp<IGraphicBufferProducer>& producer,
+ uint32_t reqWidth, uint32_t reqHeight,
+ uint32_t minLayerZ, uint32_t maxLayerZ) {
+
+ if (CC_UNLIKELY(display == 0))
+ return BAD_VALUE;
+
+ if (CC_UNLIKELY(producer == 0))
+ return BAD_VALUE;
+
+ class MessageCaptureScreen : public MessageBase {
+ SurfaceFlinger* flinger;
+ sp<IBinder> display;
+ sp<IGraphicBufferProducer> producer;
+ uint32_t reqWidth, reqHeight;
+ uint32_t minLayerZ,maxLayerZ;
+ status_t result;
+ public:
+ MessageCaptureScreen(SurfaceFlinger* flinger,
+ const sp<IBinder>& display,
+ const sp<IGraphicBufferProducer>& producer,
+ uint32_t reqWidth, uint32_t reqHeight,
+ uint32_t minLayerZ, uint32_t maxLayerZ)
+ : flinger(flinger), display(display), producer(producer),
+ reqWidth(reqWidth), reqHeight(reqHeight),
+ minLayerZ(minLayerZ), maxLayerZ(maxLayerZ),
+ result(PERMISSION_DENIED)
+ {
+ }
+ status_t getResult() const {
+ return result;
+ }
+ virtual bool handler() {
+ Mutex::Autolock _l(flinger->mStateLock);
+ sp<const DisplayDevice> hw(flinger->getDisplayDevice(display));
+ result = flinger->captureScreenImplLocked(hw, producer,
+ reqWidth, reqHeight, minLayerZ, maxLayerZ);
+ return true;
+ }
+ };
+
+ sp<MessageBase> msg = new MessageCaptureScreen(this,
+ display, producer, reqWidth, reqHeight, minLayerZ, maxLayerZ);
+ status_t res = postMessageSync(msg);
+ if (res == NO_ERROR) {
+ res = static_cast<MessageCaptureScreen*>( msg.get() )->getResult();
+ }
+ return res;
+}
+
+status_t SurfaceFlinger::captureScreenImplLocked(
+ const sp<const DisplayDevice>& hw,
+ const sp<IGraphicBufferProducer>& producer,
+ uint32_t reqWidth, uint32_t reqHeight,
uint32_t minLayerZ, uint32_t maxLayerZ)
{
ATRACE_CALL();
- status_t result = PERMISSION_DENIED;
-
- if (!GLExtensions::getInstance().haveFramebufferObject()) {
- return INVALID_OPERATION;
- }
-
// get screen geometry
- sp<const DisplayDevice> hw(getDisplayDevice(display));
const uint32_t hw_w = hw->getWidth();
const uint32_t hw_h = hw->getHeight();
@@ -2707,68 +2678,128 @@
return PERMISSION_DENIED;
}
- if ((sw > hw_w) || (sh > hw_h)) {
- ALOGE("size mismatch (%d, %d) > (%d, %d)", sw, sh, hw_w, hw_h);
+ if ((reqWidth > hw_w) || (reqHeight > hw_h)) {
+ ALOGE("size mismatch (%d, %d) > (%d, %d)",
+ reqWidth, reqHeight, 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;
+ reqWidth = (!reqWidth) ? hw_w : reqWidth;
+ reqHeight = (!reqHeight) ? hw_h : reqHeight;
+ const bool filtering = reqWidth != hw_w || reqWidth != hw_h;
-// ALOGD("screenshot: sw=%d, sh=%d, minZ=%d, maxZ=%d",
-// sw, sh, minLayerZ, maxLayerZ);
+ // Create a surface to render into
+ sp<Surface> surface = new Surface(producer);
+ ANativeWindow* const window = surface.get();
+
+ // set the buffer size to what the user requested
+ native_window_set_buffers_user_dimensions(window, reqWidth, reqHeight);
+
+ // and create the corresponding EGLSurface
+ EGLSurface eglSurface = eglCreateWindowSurface(
+ mEGLDisplay, mEGLConfig, window, NULL);
+ if (eglSurface == EGL_NO_SURFACE) {
+ ALOGE("captureScreenImplLocked: eglCreateWindowSurface() failed 0x%4x",
+ eglGetError());
+ return BAD_VALUE;
+ }
+
+ if (!eglMakeCurrent(mEGLDisplay, eglSurface, eglSurface, mEGLContext)) {
+ ALOGE("captureScreenImplLocked: eglMakeCurrent() failed 0x%4x",
+ eglGetError());
+ eglDestroySurface(mEGLDisplay, eglSurface);
+ return BAD_VALUE;
+ }
// make sure to clear all GL error flags
while ( glGetError() != GL_NO_ERROR ) ;
- // create a FBO
- GLuint name, tname;
- glGenRenderbuffersOES(1, &tname);
- glBindRenderbufferOES(GL_RENDERBUFFER_OES, tname);
- glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_RGBA8_OES, sw, sh);
+ // set-up our viewport
+ glViewport(0, 0, reqWidth, reqHeight);
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glOrthof(0, hw_w, 0, hw_h, 0, 1);
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
- glGenFramebuffersOES(1, &name);
- glBindFramebufferOES(GL_FRAMEBUFFER_OES, name);
- glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES,
- GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, tname);
+ // redraw the screen entirely...
+ glDisable(GL_TEXTURE_EXTERNAL_OES);
+ glDisable(GL_TEXTURE_2D);
+ glClearColor(0,0,0,1);
+ glClear(GL_COLOR_BUFFER_BIT);
- GLenum status = glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES);
-
- 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();
- glLoadIdentity();
- glOrthof(0, hw_w, hw_h, 0, 0, 1);
- glMatrixMode(GL_MODELVIEW);
-
- // redraw the screen entirely...
- glClearColor(0,0,0,1);
- glClear(GL_COLOR_BUFFER_BIT);
-
- 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 z = layer->drawingState().z;
- if (z >= minLayerZ && z <= maxLayerZ) {
- if (filtering) layer->setFiltering(true);
- layer->draw(hw);
- if (filtering) layer->setFiltering(false);
- }
+ 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 z = layer->drawingState().z;
+ if (z >= minLayerZ && z <= maxLayerZ) {
+ if (filtering) layer->setFiltering(true);
+ layer->draw(hw);
+ if (filtering) layer->setFiltering(false);
}
+ }
- // check for errors and return screen capture
- if (glGetError() != GL_NO_ERROR) {
- // error while rendering
- result = INVALID_OPERATION;
- } else {
+ // and finishing things up...
+ if (eglSwapBuffers(mEGLDisplay, eglSurface) != EGL_TRUE) {
+ ALOGE("captureScreenImplLocked: eglSwapBuffers() failed 0x%4x",
+ eglGetError());
+ eglDestroySurface(mEGLDisplay, eglSurface);
+ return BAD_VALUE;
+ }
+
+ eglDestroySurface(mEGLDisplay, eglSurface);
+ return NO_ERROR;
+}
+
+// ---------------------------------------------------------------------------
+// Capture screen into an IMemoryHeap (legacy)
+// ---------------------------------------------------------------------------
+
+status_t SurfaceFlinger::captureScreenImplLocked(
+ const sp<const DisplayDevice>& hw,
+ sp<IMemoryHeap>* heap,
+ uint32_t* w, uint32_t* h, PixelFormat* f,
+ uint32_t sw, uint32_t sh,
+ uint32_t minLayerZ, uint32_t maxLayerZ)
+{
+ ATRACE_CALL();
+
+ if (!GLExtensions::getInstance().haveFramebufferObject()) {
+ return INVALID_OPERATION;
+ }
+
+ // create the texture that will receive the screenshot, later we'll
+ // attach a FBO to it so we can call glReadPixels().
+ GLuint tname;
+ glGenTextures(1, &tname);
+ glBindTexture(GL_TEXTURE_2D, tname);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+ // the GLConsumer will provide the BufferQueue
+ sp<GLConsumer> consumer = new GLConsumer(tname, true, GL_TEXTURE_2D);
+ consumer->getBufferQueue()->setDefaultBufferFormat(HAL_PIXEL_FORMAT_RGBA_8888);
+
+ // call the new screenshot taking code, passing a BufferQueue to it
+ status_t result = captureScreenImplLocked(hw,
+ consumer->getBufferQueue(), sw, sh, minLayerZ, maxLayerZ);
+
+ if (result == NO_ERROR) {
+ result = consumer->updateTexImage();
+ if (result == NO_ERROR) {
+ // create a FBO
+ GLuint name;
+ glGenFramebuffersOES(1, &name);
+ glBindFramebufferOES(GL_FRAMEBUFFER_OES, name);
+ glFramebufferTexture2DOES(GL_FRAMEBUFFER_OES,
+ GL_COLOR_ATTACHMENT0_OES, GL_TEXTURE_2D, tname, 0);
+
+ sp<GraphicBuffer> buf(consumer->getCurrentBuffer());
+ sw = buf->getWidth();
+ sh = buf->getHeight();
+ size_t size = buf->getStride() * sh * 4;
+
// allocate shared memory large enough to hold the
// screen capture
sp<MemoryHeapBase> base(
@@ -2788,59 +2819,48 @@
} else {
result = NO_MEMORY;
}
+
+ // back to main framebuffer
+ glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0);
+ glDeleteFramebuffersOES(1, &name);
}
- glViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
- glMatrixMode(GL_PROJECTION);
- glPopMatrix();
- glMatrixMode(GL_MODELVIEW);
- } else {
- result = BAD_VALUE;
}
- // release FBO resources
- glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0);
- glDeleteRenderbuffersOES(1, &tname);
- glDeleteFramebuffersOES(1, &name);
-
- hw->compositionComplete();
-
-// ALOGD("screenshot: result = %s", result<0 ? strerror(result) : "OK");
+ glDeleteTextures(1, &tname);
return result;
}
-
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* outWidth, uint32_t* outHeight, PixelFormat* outFormat,
+ uint32_t reqWidth, uint32_t reqHeight,
uint32_t minLayerZ, uint32_t maxLayerZ)
{
if (CC_UNLIKELY(display == 0))
return BAD_VALUE;
- if (!GLExtensions::getInstance().haveFramebufferObject())
- return INVALID_OPERATION;
-
class MessageCaptureScreen : public MessageBase {
SurfaceFlinger* flinger;
sp<IBinder> display;
sp<IMemoryHeap>* heap;
- uint32_t* w;
- uint32_t* h;
- PixelFormat* f;
- uint32_t sw;
- uint32_t sh;
+ uint32_t* outWidth;
+ uint32_t* outHeight;
+ PixelFormat* outFormat;
+ uint32_t reqWidth;
+ uint32_t reqHeight;
uint32_t minLayerZ;
uint32_t maxLayerZ;
status_t result;
public:
- MessageCaptureScreen(SurfaceFlinger* flinger, const sp<IBinder>& display,
- sp<IMemoryHeap>* heap, uint32_t* w, uint32_t* h, PixelFormat* f,
- uint32_t sw, uint32_t sh,
+ MessageCaptureScreen(SurfaceFlinger* flinger,
+ const sp<IBinder>& display, sp<IMemoryHeap>* heap,
+ uint32_t* outWidth, uint32_t* outHeight, PixelFormat* outFormat,
+ uint32_t reqWidth, uint32_t reqHeight,
uint32_t minLayerZ, uint32_t maxLayerZ)
- : flinger(flinger), display(display),
- heap(heap), w(w), h(h), f(f), sw(sw), sh(sh),
+ : flinger(flinger), display(display), heap(heap),
+ outWidth(outWidth), outHeight(outHeight), outFormat(outFormat),
+ reqWidth(reqWidth), reqHeight(reqHeight),
minLayerZ(minLayerZ), maxLayerZ(maxLayerZ),
result(PERMISSION_DENIED)
{
@@ -2850,14 +2870,17 @@
}
virtual bool handler() {
Mutex::Autolock _l(flinger->mStateLock);
- result = flinger->captureScreenImplLocked(display,
- heap, w, h, f, sw, sh, minLayerZ, maxLayerZ);
+ sp<const DisplayDevice> hw(flinger->getDisplayDevice(display));
+ result = flinger->captureScreenImplLocked(hw, heap,
+ outWidth, outHeight, outFormat,
+ reqWidth, reqHeight, minLayerZ, maxLayerZ);
return true;
}
};
- sp<MessageBase> msg = new MessageCaptureScreen(this,
- display, heap, width, height, format, sw, sh, minLayerZ, maxLayerZ);
+ sp<MessageBase> msg = new MessageCaptureScreen(this, display, heap,
+ outWidth, outHeight, outFormat,
+ reqWidth, reqHeight, minLayerZ, maxLayerZ);
status_t res = postMessageSync(msg);
if (res == NO_ERROR) {
res = static_cast<MessageCaptureScreen*>( msg.get() )->getResult();
@@ -2901,7 +2924,7 @@
}
SurfaceFlinger::DisplayDeviceState::DisplayDeviceState(DisplayDevice::DisplayType type)
- : type(type), layerStack(0), orientation(0) {
+ : type(type), layerStack(DisplayDevice::NO_LAYER_STACK), orientation(0) {
viewport.makeInvalid();
frame.makeInvalid();
}
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index e67f3f1..d1221dc 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -103,14 +103,6 @@
// force full composition on all displays
void repaintEverything();
- // 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);
-
// returns the default Display
sp<const DisplayDevice> getDefaultDisplayDevice() const {
return getDisplayDevice(mBuiltinDisplays[DisplayDevice::DISPLAY_PRIMARY]);
@@ -202,6 +194,10 @@
uint32_t* width, uint32_t* height, PixelFormat* format,
uint32_t reqWidth, uint32_t reqHeight, uint32_t minLayerZ,
uint32_t maxLayerZ);
+ virtual status_t captureScreen(const sp<IBinder>& display,
+ const sp<IGraphicBufferProducer>& producer,
+ 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
@@ -306,10 +302,18 @@
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);
+ status_t captureScreenImplLocked(
+ const sp<const DisplayDevice>& hw,
+ 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 captureScreenImplLocked(
+ const sp<const DisplayDevice>& hw,
+ const sp<IGraphicBufferProducer>& producer,
+ uint32_t reqWidth, uint32_t reqHeight,
+ uint32_t minLayerZ, uint32_t maxLayerZ);
/* ------------------------------------------------------------------------
* EGL
diff --git a/services/surfaceflinger/Transform.cpp b/services/surfaceflinger/Transform.cpp
index aca90e0..315720e 100644
--- a/services/surfaceflinger/Transform.cpp
+++ b/services/surfaceflinger/Transform.cpp
@@ -298,6 +298,44 @@
return mType;
}
+Transform Transform::inverse() const {
+ // our 3x3 matrix is always of the form of a 2x2 transformation
+ // followed by a translation: T*M, therefore:
+ // (T*M)^-1 = M^-1 * T^-1
+ Transform result;
+ if (mType <= TRANSLATE) {
+ // 1 0 x
+ // 0 1 y
+ // 0 0 1
+ result = *this;
+ result.mMatrix[2][0] = -result.mMatrix[2][0];
+ result.mMatrix[2][1] = -result.mMatrix[2][1];
+ } else {
+ // a c x
+ // b d y
+ // 0 0 1
+ const mat33& M(mMatrix);
+ const float a = M[0][0];
+ const float b = M[1][0];
+ const float c = M[0][1];
+ const float d = M[1][1];
+ const float x = M[2][0];
+ const float y = M[2][1];
+
+ Transform R, T;
+ const float idet = 1.0 / (a*d - b*c);
+ R.mMatrix[0][0] = d*idet; R.mMatrix[0][1] = -c*idet;
+ R.mMatrix[1][0] = -b*idet; R.mMatrix[1][1] = a*idet;
+ R.mType = mType &= ~TRANSLATE;
+
+ T.mMatrix[2][0] = -x;
+ T.mMatrix[2][1] = -y;
+ T.mType = TRANSLATE;
+ result = R * T;
+ }
+ return result;
+}
+
uint32_t Transform::getType() const {
return type() & 0xFF;
}
diff --git a/services/surfaceflinger/Transform.h b/services/surfaceflinger/Transform.h
index 4fe261a..c4efade 100644
--- a/services/surfaceflinger/Transform.h
+++ b/services/surfaceflinger/Transform.h
@@ -80,6 +80,8 @@
Rect transform(const Rect& bounds) const;
Transform operator * (const Transform& rhs) const;
+ Transform inverse() const;
+
// for debugging
void dump(const char* name) const;