Merge "refactored screenshot code" into gingerbread
This commit is contained in:
commit
566b728c93
|
@ -115,7 +115,8 @@ public:
|
|||
*/
|
||||
virtual status_t captureScreen(DisplayID dpy,
|
||||
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
|
||||
* This is an ASYNCHRONOUS call.
|
||||
|
|
|
@ -169,6 +169,36 @@ private:
|
|||
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
|
||||
|
||||
|
|
|
@ -126,11 +126,14 @@ public:
|
|||
|
||||
virtual status_t captureScreen(DisplayID dpy,
|
||||
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;
|
||||
data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
|
||||
data.writeInt32(dpy);
|
||||
data.writeInt32(reqWidth);
|
||||
data.writeInt32(reqHeight);
|
||||
remote()->transact(BnSurfaceComposer::CAPTURE_SCREEN, data, &reply);
|
||||
*heap = interface_cast<IMemoryHeap>(reply.readStrongBinder());
|
||||
*width = reply.readInt32();
|
||||
|
@ -208,10 +211,13 @@ status_t BnSurfaceComposer::onTransact(
|
|||
case CAPTURE_SCREEN: {
|
||||
CHECK_INTERFACE(ISurfaceComposer, data, reply);
|
||||
DisplayID dpy = data.readInt32();
|
||||
uint32_t reqWidth = data.readInt32();
|
||||
uint32_t reqHeight = data.readInt32();
|
||||
sp<IMemoryHeap> heap;
|
||||
uint32_t w, h;
|
||||
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->writeInt32(w);
|
||||
reply->writeInt32(h);
|
||||
|
|
|
@ -544,6 +544,56 @@ status_t SurfaceComposerClient::setFreezeTint(SurfaceID id, uint32_t tint)
|
|||
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
|
||||
|
||||
|
|
|
@ -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
|
||||
{
|
||||
Texture tex(mBufferManager.getActiveTexture());
|
||||
|
|
|
@ -68,6 +68,7 @@ public:
|
|||
bool isFixedSize() const;
|
||||
|
||||
// LayerBase interface
|
||||
virtual void drawForSreenShot() const;
|
||||
virtual void onDraw(const Region& clip) const;
|
||||
virtual uint32_t doTransaction(uint32_t transactionFlags);
|
||||
virtual void lockPageFlip(bool& recomputeVisibleRegions);
|
||||
|
|
|
@ -317,6 +317,12 @@ void LayerBase::draw(const Region& clip) const
|
|||
onDraw(clip);
|
||||
}
|
||||
|
||||
void LayerBase::drawForSreenShot() const
|
||||
{
|
||||
const DisplayHardware& hw(graphicPlane(0).displayHardware());
|
||||
onDraw( Region(hw.bounds()) );
|
||||
}
|
||||
|
||||
void LayerBase::clearWithOpenGL(const Region& clip, GLclampf red,
|
||||
GLclampf green, GLclampf blue,
|
||||
GLclampf alpha) const
|
||||
|
|
|
@ -115,6 +115,7 @@ public:
|
|||
* to perform the actual drawing.
|
||||
*/
|
||||
virtual void draw(const Region& clip) const;
|
||||
virtual void drawForSreenShot() const;
|
||||
|
||||
/**
|
||||
* onDraw - draws the surface.
|
||||
|
|
|
@ -132,6 +132,12 @@ void LayerBuffer::unlockPageFlip(const Transform& planeTransform,
|
|||
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
|
||||
{
|
||||
sp<Source> source(getSource());
|
||||
|
|
|
@ -64,6 +64,7 @@ public:
|
|||
virtual sp<LayerBaseClient::Surface> createSurface() const;
|
||||
virtual status_t ditch();
|
||||
virtual void onDraw(const Region& clip) const;
|
||||
virtual void drawForSreenShot() const;
|
||||
virtual uint32_t doTransaction(uint32_t flags);
|
||||
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,
|
||||
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
|
||||
if (UNLIKELY(uint32_t(dpy) >= DISPLAY_COUNT))
|
||||
|
@ -1564,12 +1672,15 @@ status_t SurfaceFlinger::captureScreen(DisplayID dpy,
|
|||
uint32_t* w;
|
||||
uint32_t* h;
|
||||
PixelFormat* f;
|
||||
uint32_t sw;
|
||||
uint32_t sh;
|
||||
status_t result;
|
||||
public:
|
||||
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),
|
||||
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 {
|
||||
|
@ -1582,94 +1693,15 @@ status_t SurfaceFlinger::captureScreen(DisplayID dpy,
|
|||
if (flinger->mSecureFrameBuffer)
|
||||
return true;
|
||||
|
||||
// make sure to clear all GL error flags
|
||||
while ( glGetError() != GL_NO_ERROR ) ;
|
||||
result = flinger->captureScreenImplLocked(dpy,
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
||||
sp<MessageBase> msg = new MessageCaptureScreen(this,
|
||||
dpy, heap, width, height, format);
|
||||
dpy, heap, width, height, format, sw, sh);
|
||||
status_t res = postMessageSync(msg);
|
||||
if (res == NO_ERROR) {
|
||||
res = static_cast<MessageCaptureScreen*>( msg.get() )->getResult();
|
||||
|
|
|
@ -197,7 +197,9 @@ public:
|
|||
sp<IMemoryHeap>* heap,
|
||||
uint32_t* width,
|
||||
uint32_t* height,
|
||||
PixelFormat* format);
|
||||
PixelFormat* format,
|
||||
uint32_t reqWidth,
|
||||
uint32_t reqHeight);
|
||||
|
||||
void screenReleased(DisplayID dpy);
|
||||
void screenAcquired(DisplayID dpy);
|
||||
|
@ -318,6 +320,11 @@ private:
|
|||
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;
|
||||
sp<FreezeLock> getFreezeLock() const;
|
||||
inline void incFreezeCount() {
|
||||
|
|
|
@ -42,7 +42,7 @@ int main(int argc, char** argv)
|
|||
sp<IMemoryHeap> heap;
|
||||
uint32_t w, h;
|
||||
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) {
|
||||
fprintf(stderr, "screen capture failed: %s\n", strerror(-err));
|
||||
exit(0);
|
||||
|
|
Loading…
Reference in New Issue