am 19058877: Merge "refactored screenshot code" into gingerbread
Merge commit '19058877df9bf94f197a72855f810f7f6bf8d068' into gingerbread-plus-aosp * commit '19058877df9bf94f197a72855f810f7f6bf8d068': refactored screenshot code
This commit is contained in:
@@ -17,32 +17,21 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
|
||||||
#include <utils/Log.h>
|
|
||||||
|
|
||||||
#include <binder/IPCThreadState.h>
|
|
||||||
#include <binder/ProcessState.h>
|
|
||||||
#include <binder/IServiceManager.h>
|
|
||||||
|
|
||||||
#include <binder/IMemory.h>
|
#include <binder/IMemory.h>
|
||||||
#include <surfaceflinger/ISurfaceComposer.h>
|
#include <surfaceflinger/SurfaceComposerClient.h>
|
||||||
|
|
||||||
using namespace android;
|
using namespace android;
|
||||||
|
|
||||||
int main(int argc, char** argv)
|
int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
const String16 name("SurfaceFlinger");
|
ScreenshotClient screenshot;
|
||||||
sp<ISurfaceComposer> composer;
|
if (screenshot.update() != NO_ERROR)
|
||||||
if (getService(name, &composer) != NO_ERROR)
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
sp<IMemoryHeap> heap;
|
void const* base = screenshot.getPixels();
|
||||||
uint32_t w, h;
|
uint32_t w = screenshot.getWidth();
|
||||||
PixelFormat f;
|
uint32_t h = screenshot.getHeight();
|
||||||
status_t err = composer->captureScreen(0, &heap, &w, &h, &f);
|
uint32_t f = screenshot.getFormat();
|
||||||
if (err != NO_ERROR)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
uint8_t* base = (uint8_t*)heap->getBase();
|
|
||||||
int fd = dup(STDOUT_FILENO);
|
int fd = dup(STDOUT_FILENO);
|
||||||
write(fd, &w, 4);
|
write(fd, &w, 4);
|
||||||
write(fd, &h, 4);
|
write(fd, &h, 4);
|
||||||
|
|||||||
@@ -115,7 +115,8 @@ public:
|
|||||||
*/
|
*/
|
||||||
virtual status_t captureScreen(DisplayID dpy,
|
virtual status_t captureScreen(DisplayID dpy,
|
||||||
sp<IMemoryHeap>* heap,
|
sp<IMemoryHeap>* heap,
|
||||||
uint32_t* width, uint32_t* height, PixelFormat* format) = 0;
|
uint32_t* width, uint32_t* height, PixelFormat* format,
|
||||||
|
uint32_t reqWidth, uint32_t reqHeight) = 0;
|
||||||
|
|
||||||
/* Signal surfaceflinger that there might be some work to do
|
/* Signal surfaceflinger that there might be some work to do
|
||||||
* This is an ASYNCHRONOUS call.
|
* This is an ASYNCHRONOUS call.
|
||||||
|
|||||||
@@ -169,6 +169,36 @@ private:
|
|||||||
sp<ISurfaceComposerClient> mClient;
|
sp<ISurfaceComposerClient> mClient;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
class ScreenshotClient
|
||||||
|
{
|
||||||
|
sp<IMemoryHeap> mHeap;
|
||||||
|
uint32_t mWidth;
|
||||||
|
uint32_t mHeight;
|
||||||
|
PixelFormat mFormat;
|
||||||
|
public:
|
||||||
|
ScreenshotClient();
|
||||||
|
|
||||||
|
// frees the previous screenshot and capture a new one
|
||||||
|
status_t update();
|
||||||
|
status_t update(uint32_t reqWidth, uint32_t reqHeight);
|
||||||
|
|
||||||
|
// release memory occupied by the screenshot
|
||||||
|
void release();
|
||||||
|
|
||||||
|
// pixels are valid until this object is freed or
|
||||||
|
// release() or update() is called
|
||||||
|
void const* getPixels() const;
|
||||||
|
|
||||||
|
uint32_t getWidth() const;
|
||||||
|
uint32_t getHeight() const;
|
||||||
|
PixelFormat getFormat() const;
|
||||||
|
uint32_t getStride() const;
|
||||||
|
// size of allocated memory in bytes
|
||||||
|
size_t getSize() const;
|
||||||
|
};
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
}; // namespace android
|
}; // namespace android
|
||||||
|
|
||||||
|
|||||||
@@ -126,11 +126,14 @@ public:
|
|||||||
|
|
||||||
virtual status_t captureScreen(DisplayID dpy,
|
virtual status_t captureScreen(DisplayID dpy,
|
||||||
sp<IMemoryHeap>* heap,
|
sp<IMemoryHeap>* heap,
|
||||||
uint32_t* width, uint32_t* height, PixelFormat* format)
|
uint32_t* width, uint32_t* height, PixelFormat* format,
|
||||||
|
uint32_t reqWidth, uint32_t reqHeight)
|
||||||
{
|
{
|
||||||
Parcel data, reply;
|
Parcel data, reply;
|
||||||
data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
|
data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
|
||||||
data.writeInt32(dpy);
|
data.writeInt32(dpy);
|
||||||
|
data.writeInt32(reqWidth);
|
||||||
|
data.writeInt32(reqHeight);
|
||||||
remote()->transact(BnSurfaceComposer::CAPTURE_SCREEN, data, &reply);
|
remote()->transact(BnSurfaceComposer::CAPTURE_SCREEN, data, &reply);
|
||||||
*heap = interface_cast<IMemoryHeap>(reply.readStrongBinder());
|
*heap = interface_cast<IMemoryHeap>(reply.readStrongBinder());
|
||||||
*width = reply.readInt32();
|
*width = reply.readInt32();
|
||||||
@@ -208,10 +211,13 @@ status_t BnSurfaceComposer::onTransact(
|
|||||||
case CAPTURE_SCREEN: {
|
case CAPTURE_SCREEN: {
|
||||||
CHECK_INTERFACE(ISurfaceComposer, data, reply);
|
CHECK_INTERFACE(ISurfaceComposer, data, reply);
|
||||||
DisplayID dpy = data.readInt32();
|
DisplayID dpy = data.readInt32();
|
||||||
|
uint32_t reqWidth = data.readInt32();
|
||||||
|
uint32_t reqHeight = data.readInt32();
|
||||||
sp<IMemoryHeap> heap;
|
sp<IMemoryHeap> heap;
|
||||||
uint32_t w, h;
|
uint32_t w, h;
|
||||||
PixelFormat f;
|
PixelFormat f;
|
||||||
status_t res = captureScreen(dpy, &heap, &w, &h, &f);
|
status_t res = captureScreen(dpy, &heap, &w, &h, &f,
|
||||||
|
reqWidth, reqHeight);
|
||||||
reply->writeStrongBinder(heap->asBinder());
|
reply->writeStrongBinder(heap->asBinder());
|
||||||
reply->writeInt32(w);
|
reply->writeInt32(w);
|
||||||
reply->writeInt32(h);
|
reply->writeInt32(h);
|
||||||
|
|||||||
@@ -544,6 +544,56 @@ status_t SurfaceComposerClient::setFreezeTint(SurfaceID id, uint32_t tint)
|
|||||||
return NO_ERROR;
|
return NO_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
ScreenshotClient::ScreenshotClient()
|
||||||
|
: mWidth(0), mHeight(0), mFormat(PIXEL_FORMAT_NONE) {
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t ScreenshotClient::update() {
|
||||||
|
sp<ISurfaceComposer> s(ComposerService::getComposerService());
|
||||||
|
if (s == NULL) return NO_INIT;
|
||||||
|
mHeap = 0;
|
||||||
|
return s->captureScreen(0, &mHeap,
|
||||||
|
&mWidth, &mHeight, &mFormat, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t ScreenshotClient::update(uint32_t reqWidth, uint32_t reqHeight) {
|
||||||
|
sp<ISurfaceComposer> s(ComposerService::getComposerService());
|
||||||
|
if (s == NULL) return NO_INIT;
|
||||||
|
mHeap = 0;
|
||||||
|
return s->captureScreen(0, &mHeap,
|
||||||
|
&mWidth, &mHeight, &mFormat, reqWidth, reqHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScreenshotClient::release() {
|
||||||
|
mHeap = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void const* ScreenshotClient::getPixels() const {
|
||||||
|
return mHeap->getBase();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t ScreenshotClient::getWidth() const {
|
||||||
|
return mWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t ScreenshotClient::getHeight() const {
|
||||||
|
return mHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
PixelFormat ScreenshotClient::getFormat() const {
|
||||||
|
return mFormat;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t ScreenshotClient::getStride() const {
|
||||||
|
return mWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t ScreenshotClient::getSize() const {
|
||||||
|
return mHeap->getSize();
|
||||||
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
}; // namespace android
|
}; // namespace android
|
||||||
|
|
||||||
|
|||||||
@@ -214,6 +214,17 @@ slowpath:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Layer::drawForSreenShot() const
|
||||||
|
{
|
||||||
|
bool currentFixedSize = mFixedSize;
|
||||||
|
bool currentBlending = mNeedsBlending;
|
||||||
|
const_cast<Layer*>(this)->mFixedSize = false;
|
||||||
|
const_cast<Layer*>(this)->mFixedSize = true;
|
||||||
|
LayerBase::drawForSreenShot();
|
||||||
|
const_cast<Layer*>(this)->mFixedSize = currentFixedSize;
|
||||||
|
const_cast<Layer*>(this)->mNeedsBlending = currentBlending;
|
||||||
|
}
|
||||||
|
|
||||||
void Layer::onDraw(const Region& clip) const
|
void Layer::onDraw(const Region& clip) const
|
||||||
{
|
{
|
||||||
Texture tex(mBufferManager.getActiveTexture());
|
Texture tex(mBufferManager.getActiveTexture());
|
||||||
|
|||||||
@@ -68,6 +68,7 @@ public:
|
|||||||
bool isFixedSize() const;
|
bool isFixedSize() const;
|
||||||
|
|
||||||
// LayerBase interface
|
// LayerBase interface
|
||||||
|
virtual void drawForSreenShot() const;
|
||||||
virtual void onDraw(const Region& clip) const;
|
virtual void onDraw(const Region& clip) const;
|
||||||
virtual uint32_t doTransaction(uint32_t transactionFlags);
|
virtual uint32_t doTransaction(uint32_t transactionFlags);
|
||||||
virtual void lockPageFlip(bool& recomputeVisibleRegions);
|
virtual void lockPageFlip(bool& recomputeVisibleRegions);
|
||||||
|
|||||||
@@ -317,6 +317,12 @@ void LayerBase::draw(const Region& clip) const
|
|||||||
onDraw(clip);
|
onDraw(clip);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LayerBase::drawForSreenShot() const
|
||||||
|
{
|
||||||
|
const DisplayHardware& hw(graphicPlane(0).displayHardware());
|
||||||
|
onDraw( Region(hw.bounds()) );
|
||||||
|
}
|
||||||
|
|
||||||
void LayerBase::clearWithOpenGL(const Region& clip, GLclampf red,
|
void LayerBase::clearWithOpenGL(const Region& clip, GLclampf red,
|
||||||
GLclampf green, GLclampf blue,
|
GLclampf green, GLclampf blue,
|
||||||
GLclampf alpha) const
|
GLclampf alpha) const
|
||||||
|
|||||||
@@ -115,6 +115,7 @@ public:
|
|||||||
* to perform the actual drawing.
|
* to perform the actual drawing.
|
||||||
*/
|
*/
|
||||||
virtual void draw(const Region& clip) const;
|
virtual void draw(const Region& clip) const;
|
||||||
|
virtual void drawForSreenShot() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* onDraw - draws the surface.
|
* onDraw - draws the surface.
|
||||||
|
|||||||
@@ -132,6 +132,12 @@ void LayerBuffer::unlockPageFlip(const Transform& planeTransform,
|
|||||||
LayerBase::unlockPageFlip(planeTransform, outDirtyRegion);
|
LayerBase::unlockPageFlip(planeTransform, outDirtyRegion);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LayerBuffer::drawForSreenShot() const
|
||||||
|
{
|
||||||
|
const DisplayHardware& hw(graphicPlane(0).displayHardware());
|
||||||
|
clearWithOpenGL( Region(hw.bounds()) );
|
||||||
|
}
|
||||||
|
|
||||||
void LayerBuffer::onDraw(const Region& clip) const
|
void LayerBuffer::onDraw(const Region& clip) const
|
||||||
{
|
{
|
||||||
sp<Source> source(getSource());
|
sp<Source> source(getSource());
|
||||||
|
|||||||
@@ -64,6 +64,7 @@ public:
|
|||||||
virtual sp<LayerBaseClient::Surface> createSurface() const;
|
virtual sp<LayerBaseClient::Surface> createSurface() const;
|
||||||
virtual status_t ditch();
|
virtual status_t ditch();
|
||||||
virtual void onDraw(const Region& clip) const;
|
virtual void onDraw(const Region& clip) const;
|
||||||
|
virtual void drawForSreenShot() const;
|
||||||
virtual uint32_t doTransaction(uint32_t flags);
|
virtual uint32_t doTransaction(uint32_t flags);
|
||||||
virtual void unlockPageFlip(const Transform& planeTransform, Region& outDirtyRegion);
|
virtual void unlockPageFlip(const Transform& planeTransform, Region& outDirtyRegion);
|
||||||
|
|
||||||
|
|||||||
@@ -1546,9 +1546,117 @@ status_t SurfaceFlinger::onTransact(
|
|||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
status_t SurfaceFlinger::captureScreenImplLocked(DisplayID dpy,
|
||||||
|
sp<IMemoryHeap>* heap,
|
||||||
|
uint32_t* w, uint32_t* h, PixelFormat* f,
|
||||||
|
uint32_t sw, uint32_t sh)
|
||||||
|
{
|
||||||
|
status_t result = PERMISSION_DENIED;
|
||||||
|
|
||||||
|
// only one display supported for now
|
||||||
|
if (UNLIKELY(uint32_t(dpy) >= DISPLAY_COUNT))
|
||||||
|
return BAD_VALUE;
|
||||||
|
|
||||||
|
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();
|
||||||
|
|
||||||
|
if ((sw > hw_w) || (sh > hw_h))
|
||||||
|
return BAD_VALUE;
|
||||||
|
|
||||||
|
sw = (!sw) ? hw_w : sw;
|
||||||
|
sh = (!sh) ? hw_h : sh;
|
||||||
|
const size_t size = sw * sh * 4;
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
glGenFramebuffersOES(1, &name);
|
||||||
|
glBindFramebufferOES(GL_FRAMEBUFFER_OES, name);
|
||||||
|
glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES,
|
||||||
|
GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, tname);
|
||||||
|
|
||||||
|
GLenum status = glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES);
|
||||||
|
if (status == GL_FRAMEBUFFER_COMPLETE_OES) {
|
||||||
|
|
||||||
|
// invert everything, b/c glReadPixel() below will invert the FB
|
||||||
|
glViewport(0, 0, sw, sh);
|
||||||
|
glMatrixMode(GL_PROJECTION);
|
||||||
|
glPushMatrix();
|
||||||
|
glLoadIdentity();
|
||||||
|
glOrthof(0, hw_w, 0, hw_h, 0, 1);
|
||||||
|
glMatrixMode(GL_MODELVIEW);
|
||||||
|
|
||||||
|
// redraw the screen entirely...
|
||||||
|
glClearColor(0,0,0,1);
|
||||||
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
|
const Vector< sp<LayerBase> >& layers(mVisibleLayersSortedByZ);
|
||||||
|
const size_t count = layers.size();
|
||||||
|
for (size_t i=0 ; i<count ; ++i) {
|
||||||
|
const sp<LayerBase>& layer(layers[i]);
|
||||||
|
layer->drawForSreenShot();
|
||||||
|
}
|
||||||
|
|
||||||
|
// XXX: this is needed on tegra
|
||||||
|
glScissor(0, 0, sw, sh);
|
||||||
|
|
||||||
|
// check for errors and return screen capture
|
||||||
|
if (glGetError() != GL_NO_ERROR) {
|
||||||
|
// error while rendering
|
||||||
|
result = INVALID_OPERATION;
|
||||||
|
} else {
|
||||||
|
// allocate shared memory large enough to hold the
|
||||||
|
// screen capture
|
||||||
|
sp<MemoryHeapBase> base(
|
||||||
|
new MemoryHeapBase(size, 0, "screen-capture") );
|
||||||
|
void* const ptr = base->getBase();
|
||||||
|
if (ptr) {
|
||||||
|
// capture the screen with glReadPixels()
|
||||||
|
glReadPixels(0, 0, sw, sh, GL_RGBA, GL_UNSIGNED_BYTE, ptr);
|
||||||
|
if (glGetError() == GL_NO_ERROR) {
|
||||||
|
*heap = base;
|
||||||
|
*w = sw;
|
||||||
|
*h = sh;
|
||||||
|
*f = PIXEL_FORMAT_RGBA_8888;
|
||||||
|
result = NO_ERROR;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
result = NO_MEMORY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
glEnable(GL_SCISSOR_TEST);
|
||||||
|
glViewport(0, 0, hw_w, hw_h);
|
||||||
|
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);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t SurfaceFlinger::captureScreen(DisplayID dpy,
|
status_t SurfaceFlinger::captureScreen(DisplayID dpy,
|
||||||
sp<IMemoryHeap>* heap,
|
sp<IMemoryHeap>* heap,
|
||||||
uint32_t* width, uint32_t* height, PixelFormat* format)
|
uint32_t* width, uint32_t* height, PixelFormat* format,
|
||||||
|
uint32_t sw, uint32_t sh)
|
||||||
{
|
{
|
||||||
// only one display supported for now
|
// only one display supported for now
|
||||||
if (UNLIKELY(uint32_t(dpy) >= DISPLAY_COUNT))
|
if (UNLIKELY(uint32_t(dpy) >= DISPLAY_COUNT))
|
||||||
@@ -1564,12 +1672,15 @@ status_t SurfaceFlinger::captureScreen(DisplayID dpy,
|
|||||||
uint32_t* w;
|
uint32_t* w;
|
||||||
uint32_t* h;
|
uint32_t* h;
|
||||||
PixelFormat* f;
|
PixelFormat* f;
|
||||||
|
uint32_t sw;
|
||||||
|
uint32_t sh;
|
||||||
status_t result;
|
status_t result;
|
||||||
public:
|
public:
|
||||||
MessageCaptureScreen(SurfaceFlinger* flinger, DisplayID dpy,
|
MessageCaptureScreen(SurfaceFlinger* flinger, DisplayID dpy,
|
||||||
sp<IMemoryHeap>* heap, uint32_t* w, uint32_t* h, PixelFormat* f)
|
sp<IMemoryHeap>* heap, uint32_t* w, uint32_t* h, PixelFormat* f,
|
||||||
|
uint32_t sw, uint32_t sh)
|
||||||
: flinger(flinger), dpy(dpy),
|
: flinger(flinger), dpy(dpy),
|
||||||
heap(heap), w(w), h(h), f(f), result(PERMISSION_DENIED)
|
heap(heap), w(w), h(h), f(f), sw(sw), sh(sh), result(PERMISSION_DENIED)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
status_t getResult() const {
|
status_t getResult() const {
|
||||||
@@ -1582,94 +1693,15 @@ status_t SurfaceFlinger::captureScreen(DisplayID dpy,
|
|||||||
if (flinger->mSecureFrameBuffer)
|
if (flinger->mSecureFrameBuffer)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// make sure to clear all GL error flags
|
result = flinger->captureScreenImplLocked(dpy,
|
||||||
while ( glGetError() != GL_NO_ERROR ) ;
|
heap, w, h, f, sw, sh);
|
||||||
|
|
||||||
// get screen geometry
|
|
||||||
const DisplayHardware& hw(flinger->graphicPlane(dpy).displayHardware());
|
|
||||||
const uint32_t sw = hw.getWidth();
|
|
||||||
const uint32_t sh = hw.getHeight();
|
|
||||||
const Region screenBounds(hw.bounds());
|
|
||||||
const size_t size = sw * sh * 4;
|
|
||||||
|
|
||||||
// create a FBO
|
|
||||||
GLuint name, tname;
|
|
||||||
glGenRenderbuffersOES(1, &tname);
|
|
||||||
glBindRenderbufferOES(GL_RENDERBUFFER_OES, tname);
|
|
||||||
glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_RGBA8_OES, sw, sh);
|
|
||||||
glGenFramebuffersOES(1, &name);
|
|
||||||
glBindFramebufferOES(GL_FRAMEBUFFER_OES, name);
|
|
||||||
glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES,
|
|
||||||
GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, tname);
|
|
||||||
|
|
||||||
GLenum status = glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES);
|
|
||||||
if (status == GL_FRAMEBUFFER_COMPLETE_OES) {
|
|
||||||
|
|
||||||
// invert everything, b/c glReadPixel() below will invert the FB
|
|
||||||
glMatrixMode(GL_PROJECTION);
|
|
||||||
glPushMatrix();
|
|
||||||
glLoadIdentity();
|
|
||||||
glOrthof(0, sw, 0, sh, 0, 1);
|
|
||||||
glMatrixMode(GL_MODELVIEW);
|
|
||||||
|
|
||||||
// redraw the screen entirely...
|
|
||||||
glClearColor(0,0,0,1);
|
|
||||||
glClear(GL_COLOR_BUFFER_BIT);
|
|
||||||
const Vector< sp<LayerBase> >& layers(
|
|
||||||
flinger->mVisibleLayersSortedByZ);
|
|
||||||
const size_t count = layers.size();
|
|
||||||
for (size_t i=0 ; i<count ; ++i) {
|
|
||||||
const sp<LayerBase>& layer(layers[i]);
|
|
||||||
if (!strcmp(layer->getTypeId(), "LayerBuffer")) {
|
|
||||||
// we cannot render LayerBuffer because it doens't
|
|
||||||
// use OpenGL, and won't show-up in the FBO.
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
layer->draw(screenBounds);
|
|
||||||
}
|
|
||||||
|
|
||||||
glMatrixMode(GL_PROJECTION);
|
|
||||||
glPopMatrix();
|
|
||||||
glMatrixMode(GL_MODELVIEW);
|
|
||||||
|
|
||||||
// check for errors and return screen capture
|
|
||||||
if (glGetError() != GL_NO_ERROR) {
|
|
||||||
// error while rendering
|
|
||||||
result = INVALID_OPERATION;
|
|
||||||
} else {
|
|
||||||
// allocate shared memory large enough to hold the
|
|
||||||
// screen capture
|
|
||||||
sp<MemoryHeapBase> base(
|
|
||||||
new MemoryHeapBase(size, 0, "screen-capture") );
|
|
||||||
void* const ptr = base->getBase();
|
|
||||||
if (ptr) {
|
|
||||||
// capture the screen with glReadPixels()
|
|
||||||
glReadPixels(0, 0, sw, sh, GL_RGBA, GL_UNSIGNED_BYTE, ptr);
|
|
||||||
if (glGetError() == GL_NO_ERROR) {
|
|
||||||
*heap = base;
|
|
||||||
*w = sw;
|
|
||||||
*h = sh;
|
|
||||||
*f = PIXEL_FORMAT_RGBA_8888;
|
|
||||||
result = NO_ERROR;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
result = NO_MEMORY;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
result = BAD_VALUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// release FBO resources
|
|
||||||
glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0);
|
|
||||||
glDeleteRenderbuffersOES(1, &tname);
|
|
||||||
glDeleteFramebuffersOES(1, &name);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
sp<MessageBase> msg = new MessageCaptureScreen(this,
|
sp<MessageBase> msg = new MessageCaptureScreen(this,
|
||||||
dpy, heap, width, height, format);
|
dpy, heap, width, height, format, sw, sh);
|
||||||
status_t res = postMessageSync(msg);
|
status_t res = postMessageSync(msg);
|
||||||
if (res == NO_ERROR) {
|
if (res == NO_ERROR) {
|
||||||
res = static_cast<MessageCaptureScreen*>( msg.get() )->getResult();
|
res = static_cast<MessageCaptureScreen*>( msg.get() )->getResult();
|
||||||
|
|||||||
@@ -197,7 +197,9 @@ public:
|
|||||||
sp<IMemoryHeap>* heap,
|
sp<IMemoryHeap>* heap,
|
||||||
uint32_t* width,
|
uint32_t* width,
|
||||||
uint32_t* height,
|
uint32_t* height,
|
||||||
PixelFormat* format);
|
PixelFormat* format,
|
||||||
|
uint32_t reqWidth,
|
||||||
|
uint32_t reqHeight);
|
||||||
|
|
||||||
void screenReleased(DisplayID dpy);
|
void screenReleased(DisplayID dpy);
|
||||||
void screenAcquired(DisplayID dpy);
|
void screenAcquired(DisplayID dpy);
|
||||||
@@ -318,6 +320,11 @@ private:
|
|||||||
void commitTransaction();
|
void commitTransaction();
|
||||||
|
|
||||||
|
|
||||||
|
status_t captureScreenImplLocked(DisplayID dpy,
|
||||||
|
sp<IMemoryHeap>* heap,
|
||||||
|
uint32_t* width, uint32_t* height, PixelFormat* format,
|
||||||
|
uint32_t reqWidth = 0, uint32_t reqHeight = 0);
|
||||||
|
|
||||||
friend class FreezeLock;
|
friend class FreezeLock;
|
||||||
sp<FreezeLock> getFreezeLock() const;
|
sp<FreezeLock> getFreezeLock() const;
|
||||||
inline void incFreezeCount() {
|
inline void incFreezeCount() {
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ int main(int argc, char** argv)
|
|||||||
sp<IMemoryHeap> heap;
|
sp<IMemoryHeap> heap;
|
||||||
uint32_t w, h;
|
uint32_t w, h;
|
||||||
PixelFormat f;
|
PixelFormat f;
|
||||||
status_t err = composer->captureScreen(0, &heap, &w, &h, &f);
|
status_t err = composer->captureScreen(0, &heap, &w, &h, &f, 0, 0);
|
||||||
if (err != NO_ERROR) {
|
if (err != NO_ERROR) {
|
||||||
fprintf(stderr, "screen capture failed: %s\n", strerror(-err));
|
fprintf(stderr, "screen capture failed: %s\n", strerror(-err));
|
||||||
exit(0);
|
exit(0);
|
||||||
|
|||||||
Reference in New Issue
Block a user