Merge "SurfaceFlinger: Add sourceCrop to screenshot"

This commit is contained in:
Dan Stoza 2014-05-28 18:31:39 +00:00 committed by Android (Google) Code Review
commit 3d5c8a98c1
13 changed files with 104 additions and 43 deletions

View File

@ -41,6 +41,7 @@ class DisplayState;
class DisplayInfo;
class IDisplayEventConnection;
class IMemoryHeap;
class Rect;
/*
* This class defines the Binder IPC interface for accessing various
@ -131,11 +132,10 @@ public:
*/
virtual status_t captureScreen(const sp<IBinder>& display,
const sp<IGraphicBufferProducer>& producer,
uint32_t reqWidth, uint32_t reqHeight,
Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
uint32_t minLayerZ, uint32_t maxLayerZ,
bool useIdentityTransform) = 0;
/* Clears the frame statistics for animations.
*
* Requires the ACCESS_SURFACE_FLINGER permission.

View File

@ -180,10 +180,12 @@ private:
class ScreenshotClient
{
public:
// if cropping isn't required, callers may pass in a default Rect, e.g.:
// capture(display, producer, Rect(), reqWidth, ...);
static status_t capture(
const sp<IBinder>& display,
const sp<IGraphicBufferProducer>& producer,
uint32_t reqWidth, uint32_t reqHeight,
Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
uint32_t minLayerZ, uint32_t maxLayerZ,
bool useIdentityTransform);
@ -197,13 +199,16 @@ public:
ScreenshotClient();
~ScreenshotClient();
// frees the previous screenshot and capture a new one
status_t update(const sp<IBinder>& display, bool useIdentityTransform);
// frees the previous screenshot and captures a new one
// if cropping isn't required, callers may pass in a default Rect, e.g.:
// update(display, Rect(), useIdentityTransform);
status_t update(const sp<IBinder>& display,
uint32_t reqWidth, uint32_t reqHeight,
Rect sourceCrop, bool useIdentityTransform);
status_t update(const sp<IBinder>& display,
Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
bool useIdentityTransform);
status_t update(const sp<IBinder>& display,
uint32_t reqWidth, uint32_t reqHeight,
Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
uint32_t minLayerZ, uint32_t maxLayerZ,
bool useIdentityTransform);

View File

@ -104,7 +104,7 @@ public:
virtual status_t captureScreen(const sp<IBinder>& display,
const sp<IGraphicBufferProducer>& producer,
uint32_t reqWidth, uint32_t reqHeight,
Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
uint32_t minLayerZ, uint32_t maxLayerZ,
bool useIdentityTransform)
{
@ -112,6 +112,7 @@ public:
data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
data.writeStrongBinder(display);
data.writeStrongBinder(producer->asBinder());
data.write(sourceCrop);
data.writeInt32(reqWidth);
data.writeInt32(reqHeight);
data.writeInt32(minLayerZ);
@ -328,6 +329,8 @@ status_t BnSurfaceComposer::onTransact(
sp<IBinder> display = data.readStrongBinder();
sp<IGraphicBufferProducer> producer =
interface_cast<IGraphicBufferProducer>(data.readStrongBinder());
Rect sourceCrop;
data.read(sourceCrop);
uint32_t reqWidth = data.readInt32();
uint32_t reqHeight = data.readInt32();
uint32_t minLayerZ = data.readInt32();
@ -335,7 +338,7 @@ status_t BnSurfaceComposer::onTransact(
bool useIdentityTransform = static_cast<bool>(data.readInt32());
status_t res = captureScreen(display, producer,
reqWidth, reqHeight, minLayerZ, maxLayerZ,
sourceCrop, reqWidth, reqHeight, minLayerZ, maxLayerZ,
useIdentityTransform);
reply->writeInt32(res);
return NO_ERROR;

View File

@ -676,11 +676,11 @@ status_t SurfaceComposerClient::getAnimationFrameStats(FrameStats* outStats) {
status_t ScreenshotClient::capture(
const sp<IBinder>& display,
const sp<IGraphicBufferProducer>& producer,
uint32_t reqWidth, uint32_t reqHeight,
Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
uint32_t minLayerZ, uint32_t maxLayerZ, bool useIdentityTransform) {
sp<ISurfaceComposer> s(ComposerService::getComposerService());
if (s == NULL) return NO_INIT;
return s->captureScreen(display, producer,
return s->captureScreen(display, producer, sourceCrop,
reqWidth, reqHeight, minLayerZ, maxLayerZ, useIdentityTransform);
}
@ -704,7 +704,7 @@ sp<CpuConsumer> ScreenshotClient::getCpuConsumer() const {
}
status_t ScreenshotClient::update(const sp<IBinder>& display,
uint32_t reqWidth, uint32_t reqHeight,
Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
uint32_t minLayerZ, uint32_t maxLayerZ,
bool useIdentityTransform) {
sp<ISurfaceComposer> s(ComposerService::getComposerService());
@ -717,7 +717,7 @@ status_t ScreenshotClient::update(const sp<IBinder>& display,
mHaveBuffer = false;
}
status_t err = s->captureScreen(display, mProducer,
status_t err = s->captureScreen(display, mProducer, sourceCrop,
reqWidth, reqHeight, minLayerZ, maxLayerZ, useIdentityTransform);
if (err == NO_ERROR) {
@ -729,16 +729,16 @@ status_t ScreenshotClient::update(const sp<IBinder>& display,
return err;
}
status_t ScreenshotClient::update(const sp<IBinder>& display,
status_t ScreenshotClient::update(const sp<IBinder>& display, Rect sourceCrop,
bool useIdentityTransform) {
return ScreenshotClient::update(display, 0, 0, 0, -1UL,
return ScreenshotClient::update(display, sourceCrop, 0, 0, 0, -1UL,
useIdentityTransform);
}
status_t ScreenshotClient::update(const sp<IBinder>& display,
status_t ScreenshotClient::update(const sp<IBinder>& display, Rect sourceCrop,
uint32_t reqWidth, uint32_t reqHeight, bool useIdentityTransform) {
return ScreenshotClient::update(display, reqWidth, reqHeight, 0, -1UL,
useIdentityTransform);
return ScreenshotClient::update(display, sourceCrop, reqWidth, reqHeight,
0, -1UL, useIdentityTransform);
}
void ScreenshotClient::release() {

View File

@ -21,6 +21,7 @@
#include <gui/Surface.h>
#include <gui/SurfaceComposerClient.h>
#include <gui/BufferItemConsumer.h>
#include <ui/Rect.h>
#include <utils/String8.h>
#include <private/gui/ComposerService.h>
@ -94,7 +95,7 @@ TEST_F(SurfaceTest, ScreenshotsOfProtectedBuffersSucceed) {
sp<CpuConsumer> cpuConsumer = new CpuConsumer(consumer, 1);
sp<ISurfaceComposer> sf(ComposerService::getComposerService());
sp<IBinder> display(sf->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
ASSERT_EQ(NO_ERROR, sf->captureScreen(display, producer,
ASSERT_EQ(NO_ERROR, sf->captureScreen(display, producer, Rect(),
64, 64, 0, 0x7fffffff, false));
// Set the PROTECTED usage bit and verify that the screenshot fails. Note
@ -123,7 +124,7 @@ TEST_F(SurfaceTest, ScreenshotsOfProtectedBuffersSucceed) {
&buf));
ASSERT_EQ(NO_ERROR, anw->queueBuffer(anw.get(), buf, -1));
}
ASSERT_EQ(NO_ERROR, sf->captureScreen(display, producer,
ASSERT_EQ(NO_ERROR, sf->captureScreen(display, producer, Rect(),
64, 64, 0, 0x7fffffff, false));
}

View File

@ -283,7 +283,8 @@ EGLBoolean DisplayDevice::makeCurrent(EGLDisplay dpy, EGLContext ctx) const {
void DisplayDevice::setViewportAndProjection() const {
size_t w = mDisplayWidth;
size_t h = mDisplayHeight;
mFlinger->getRenderEngine().setViewportAndProjection(w, h, w, h, false);
Rect sourceCrop(0, 0, w, h);
mFlinger->getRenderEngine().setViewportAndProjection(w, h, sourceCrop, h, false);
}
// ----------------------------------------------------------------------------

View File

@ -17,6 +17,8 @@
#include <GLES/gl.h>
#include <GLES/glext.h>
#include <ui/Rect.h>
#include <utils/String8.h>
#include <cutils/compiler.h>
@ -72,13 +74,23 @@ size_t GLES11RenderEngine::getMaxViewportDims() const {
}
void GLES11RenderEngine::setViewportAndProjection(
size_t vpw, size_t vph, size_t w, size_t h, bool yswap) {
size_t vpw, size_t vph, Rect sourceCrop, size_t hwh, bool yswap) {
glViewport(0, 0, vpw, vph);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
// put the origin in the left-bottom corner
if (yswap) glOrthof(0, w, h, 0, 0, 1);
else glOrthof(0, w, 0, h, 0, 1);
size_t l = sourceCrop.left;
size_t r = sourceCrop.right;
// In GL, (0, 0) is the bottom-left corner, so flip y coordinates
size_t t = hwh - sourceCrop.top;
size_t b = hwh - sourceCrop.bottom;
if (yswap) {
glOrthof(l, r, t, b, 0, 1);
} else {
glOrthof(l, r, b, t, 0, 1);
}
glMatrixMode(GL_MODELVIEW);
}

View File

@ -49,7 +49,8 @@ protected:
virtual ~GLES11RenderEngine();
virtual void dump(String8& result);
virtual void setViewportAndProjection(size_t vpw, size_t vph, size_t w, size_t h, bool yswap);
virtual void setViewportAndProjection(size_t vpw, size_t vph,
Rect sourceCrop, size_t hwh, bool yswap);
virtual void setupLayerBlending(bool premultipliedAlpha, bool opaque, int alpha);
virtual void setupDimLayerBlending(int alpha);
virtual void setupLayerTexturing(const Texture& texture);

View File

@ -19,6 +19,8 @@
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
#include <ui/Rect.h>
#include <utils/String8.h>
#include <utils/Trace.h>
@ -78,10 +80,21 @@ size_t GLES20RenderEngine::getMaxViewportDims() const {
}
void GLES20RenderEngine::setViewportAndProjection(
size_t vpw, size_t vph, size_t w, size_t h, bool yswap) {
size_t vpw, size_t vph, Rect sourceCrop, size_t hwh, bool yswap) {
size_t l = sourceCrop.left;
size_t r = sourceCrop.right;
// In GL, (0, 0) is the bottom-left corner, so flip y coordinates
size_t t = hwh - sourceCrop.top;
size_t b = hwh - sourceCrop.bottom;
mat4 m;
if (yswap) m = mat4::ortho(0, w, h, 0, 0, 1);
else m = mat4::ortho(0, w, 0, h, 0, 1);
if (yswap) {
m = mat4::ortho(l, r, t, b, 0, 1);
} else {
m = mat4::ortho(l, r, b, t, 0, 1);
}
glViewport(0, 0, vpw, vph);
mState.setProjectionMatrix(m);

View File

@ -64,7 +64,8 @@ protected:
virtual ~GLES20RenderEngine();
virtual void dump(String8& result);
virtual void setViewportAndProjection(size_t vpw, size_t vph, size_t w, size_t h, bool yswap);
virtual void setViewportAndProjection(size_t vpw, size_t vph,
Rect sourceCrop, size_t hwh, bool yswap);
virtual void setupLayerBlending(bool premultipliedAlpha, bool opaque, int alpha);
virtual void setupDimLayerBlending(int alpha);
virtual void setupLayerTexturing(const Texture& texture);

View File

@ -89,7 +89,8 @@ public:
// set-up
virtual void checkErrors() const;
virtual void setViewportAndProjection(size_t vpw, size_t vph, size_t w, size_t h, bool yswap) = 0;
virtual void setViewportAndProjection(size_t vpw, size_t vph,
Rect sourceCrop, size_t hwh, bool yswap) = 0;
virtual void setupLayerBlending(bool premultipliedAlpha, bool opaque, int alpha) = 0;
virtual void setupDimLayerBlending(int alpha) = 0;
virtual void setupLayerTexturing(const Texture& texture) = 0;

View File

@ -2790,7 +2790,7 @@ public:
status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
const sp<IGraphicBufferProducer>& producer,
uint32_t reqWidth, uint32_t reqHeight,
Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
uint32_t minLayerZ, uint32_t maxLayerZ,
bool useIdentityTransform) {
@ -2816,6 +2816,7 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
SurfaceFlinger* flinger;
sp<IBinder> display;
sp<IGraphicBufferProducer> producer;
Rect sourceCrop;
uint32_t reqWidth, reqHeight;
uint32_t minLayerZ,maxLayerZ;
bool useIdentityTransform;
@ -2824,11 +2825,11 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
MessageCaptureScreen(SurfaceFlinger* flinger,
const sp<IBinder>& display,
const sp<IGraphicBufferProducer>& producer,
uint32_t reqWidth, uint32_t reqHeight,
Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
uint32_t minLayerZ, uint32_t maxLayerZ,
bool useIdentityTransform)
: flinger(flinger), display(display), producer(producer),
reqWidth(reqWidth), reqHeight(reqHeight),
sourceCrop(sourceCrop), reqWidth(reqWidth), reqHeight(reqHeight),
minLayerZ(minLayerZ), maxLayerZ(maxLayerZ),
useIdentityTransform(useIdentityTransform),
result(PERMISSION_DENIED)
@ -2841,7 +2842,7 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
Mutex::Autolock _l(flinger->mStateLock);
sp<const DisplayDevice> hw(flinger->getDisplayDevice(display));
result = flinger->captureScreenImplLocked(hw, producer,
reqWidth, reqHeight, minLayerZ, maxLayerZ,
sourceCrop, reqWidth, reqHeight, minLayerZ, maxLayerZ,
useIdentityTransform);
static_cast<GraphicProducerWrapper*>(producer->asBinder().get())->exit(result);
return true;
@ -2864,7 +2865,8 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
// which does the marshaling work forwards to our "fake remote" above.
sp<MessageBase> msg = new MessageCaptureScreen(this,
display, IGraphicBufferProducer::asInterface( wrapper ),
reqWidth, reqHeight, minLayerZ, maxLayerZ, useIdentityTransform);
sourceCrop, reqWidth, reqHeight, minLayerZ, maxLayerZ,
useIdentityTransform);
status_t res = postMessageAsync(msg);
if (res == NO_ERROR) {
@ -2876,7 +2878,7 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
void SurfaceFlinger::renderScreenImplLocked(
const sp<const DisplayDevice>& hw,
uint32_t reqWidth, uint32_t reqHeight,
Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
uint32_t minLayerZ, uint32_t maxLayerZ,
bool yswap, bool useIdentityTransform)
{
@ -2888,11 +2890,32 @@ void SurfaceFlinger::renderScreenImplLocked(
const uint32_t hw_h = hw->getHeight();
const bool filtering = reqWidth != hw_w || reqWidth != hw_h;
// if a default or invalid sourceCrop is passed in, set reasonable values
if (sourceCrop.width() == 0 || sourceCrop.height() == 0 ||
!sourceCrop.isValid()) {
sourceCrop.setLeftTop(Point(0, 0));
sourceCrop.setRightBottom(Point(hw_w, hw_h));
}
// ensure that sourceCrop is inside screen
if (sourceCrop.left < 0) {
ALOGE("Invalid crop rect: l = %d (< 0)", sourceCrop.left);
}
if (sourceCrop.right >= hw_w) {
ALOGE("Invalid crop rect: r = %d (>= %d)", sourceCrop.right, hw_w);
}
if (sourceCrop.top < 0) {
ALOGE("Invalid crop rect: t = %d (< 0)", sourceCrop.top);
}
if (sourceCrop.bottom >= hw_h) {
ALOGE("Invalid crop rect: b = %d (>= %d)", sourceCrop.bottom, hw_h);
}
// make sure to clear all GL error flags
engine.checkErrors();
// set-up our viewport
engine.setViewportAndProjection(reqWidth, reqHeight, hw_w, hw_h, yswap);
engine.setViewportAndProjection(reqWidth, reqHeight, sourceCrop, hw_h, yswap);
engine.disableTexturing();
// redraw the screen entirely...
@ -2923,7 +2946,7 @@ void SurfaceFlinger::renderScreenImplLocked(
status_t SurfaceFlinger::captureScreenImplLocked(
const sp<const DisplayDevice>& hw,
const sp<IGraphicBufferProducer>& producer,
uint32_t reqWidth, uint32_t reqHeight,
Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
uint32_t minLayerZ, uint32_t maxLayerZ,
bool useIdentityTransform)
{
@ -2978,7 +3001,7 @@ status_t SurfaceFlinger::captureScreenImplLocked(
// via an FBO, which means we didn't have to create
// an EGLSurface and therefore we're not
// dependent on the context's EGLConfig.
renderScreenImplLocked(hw, reqWidth, reqHeight,
renderScreenImplLocked(hw, sourceCrop, reqWidth, reqHeight,
minLayerZ, maxLayerZ, true, useIdentityTransform);
// Create a sync point and wait on it, so we know the buffer is

View File

@ -202,7 +202,7 @@ private:
virtual sp<IDisplayEventConnection> createDisplayEventConnection();
virtual status_t captureScreen(const sp<IBinder>& display,
const sp<IGraphicBufferProducer>& producer,
uint32_t reqWidth, uint32_t reqHeight,
Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
uint32_t minLayerZ, uint32_t maxLayerZ,
bool useIdentityTransform);
// called when screen needs to turn off
@ -311,14 +311,14 @@ private:
void renderScreenImplLocked(
const sp<const DisplayDevice>& hw,
uint32_t reqWidth, uint32_t reqHeight,
Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
uint32_t minLayerZ, uint32_t maxLayerZ,
bool yswap, bool useIdentityTransform);
status_t captureScreenImplLocked(
const sp<const DisplayDevice>& hw,
const sp<IGraphicBufferProducer>& producer,
uint32_t reqWidth, uint32_t reqHeight,
Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
uint32_t minLayerZ, uint32_t maxLayerZ,
bool useIdentityTransform);