From fd1fb639a1dd9325a9bebb0cd3ca6ebd7d48931d Mon Sep 17 00:00:00 2001
From: Pawit Pornkitprasan
Date: Tue, 18 Nov 2014 08:38:33 +0700
Subject: [PATCH] Bring back support for glReadPixels screenshot path
Squashed commit of the following:
commit 012d3fe41d1d6cd38a0858b59145e9a4447641fa
Author: Hashcode
Date: Sun Dec 8 19:36:50 2013 +0000
sf: Always use opengles for screen capture
Go back to the usage of GRALLOC_USAGE_HW_TEXTURE and GRALLOC_USAGE_HW_RENDERER
in captureScreenImplLocked regardless of useReadPixels value
This fixes the EGL_NO_IMAGE_KHR error returned from
eglCreateImageKHR (blank images returned from screenshot path)
Change-Id: I62fe90a081607b9e89c67f3dcfd34c84efc89d35
commit 4866ddf98ac98d8e22a1cd6a21894bb17f274588
Author: Ricardo Cerqueira
Date: Thu Oct 31 03:53:39 2013 +0000
Revert "remove support for glReadPixels screenshot path"
This reverts commit 3ca76f416bc8665a97636ca8a2d0128b9da9d92c.
Conflicts:
include/gui/ISurfaceComposer.h
libs/gui/ISurfaceComposer.cpp
libs/gui/SurfaceComposerClient.cpp
services/surfaceflinger/SurfaceFlinger.cpp
services/surfaceflinger/SurfaceFlinger.h
Change-Id: I8c239e533757af770e418dbb198f5a86c736961f
Change-Id: I8c239e533757af770e418dbb198f5a86c736961f
---
include/gui/ISurfaceComposer.h | 3 +-
libs/gui/ISurfaceComposer.cpp | 8 +++-
libs/gui/SurfaceComposerClient.cpp | 5 ++-
.../RenderEngine/GLES11RenderEngine.cpp | 42 +++++++++++++------
.../RenderEngine/GLES11RenderEngine.h | 5 ++-
.../RenderEngine/GLES20RenderEngine.cpp | 39 ++++++++++++-----
.../RenderEngine/GLES20RenderEngine.h | 5 ++-
.../RenderEngine/RenderEngine.cpp | 8 ++--
.../RenderEngine/RenderEngine.h | 11 +++--
services/surfaceflinger/SurfaceFlinger.cpp | 28 ++++++++++---
services/surfaceflinger/SurfaceFlinger.h | 6 ++-
11 files changed, 114 insertions(+), 46 deletions(-)
diff --git a/include/gui/ISurfaceComposer.h b/include/gui/ISurfaceComposer.h
index d5570ea00..84ddb278d 100644
--- a/include/gui/ISurfaceComposer.h
+++ b/include/gui/ISurfaceComposer.h
@@ -145,7 +145,8 @@ public:
Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
uint32_t minLayerZ, uint32_t maxLayerZ,
bool useIdentityTransform,
- Rotation rotation = eRotateNone) = 0;
+ Rotation rotation = eRotateNone,
+ bool isCpuConsumer = false) = 0;
/* Clears the frame statistics for animations.
*
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index 78886d5bb..0ad63394c 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -103,7 +103,8 @@ public:
Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
uint32_t minLayerZ, uint32_t maxLayerZ,
bool useIdentityTransform,
- ISurfaceComposer::Rotation rotation)
+ ISurfaceComposer::Rotation rotation,
+ bool isCpuConsumer)
{
Parcel data, reply;
data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
@@ -116,6 +117,7 @@ public:
data.writeUint32(maxLayerZ);
data.writeInt32(static_cast(useIdentityTransform));
data.writeInt32(static_cast(rotation));
+ data.writeInt32(isCpuConsumer);
remote()->transact(BnSurfaceComposer::CAPTURE_SCREEN, data, &reply);
return reply.readInt32();
}
@@ -361,11 +363,13 @@ status_t BnSurfaceComposer::onTransact(
uint32_t maxLayerZ = data.readUint32();
bool useIdentityTransform = static_cast(data.readInt32());
int32_t rotation = data.readInt32();
+ bool isCpuConsumer = data.readInt32();
status_t res = captureScreen(display, producer,
sourceCrop, reqWidth, reqHeight, minLayerZ, maxLayerZ,
useIdentityTransform,
- static_cast(rotation));
+ static_cast(rotation),
+ isCpuConsumer);
reply->writeInt32(res);
return NO_ERROR;
}
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 6ad47d8b7..fe82e3baf 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -691,7 +691,8 @@ status_t ScreenshotClient::capture(
sp s(ComposerService::getComposerService());
if (s == NULL) return NO_INIT;
return s->captureScreen(display, producer, sourceCrop,
- reqWidth, reqHeight, minLayerZ, maxLayerZ, useIdentityTransform);
+ reqWidth, reqHeight, minLayerZ, maxLayerZ, useIdentityTransform,
+ ISurfaceComposer::eRotateNone, false);
}
ScreenshotClient::ScreenshotClient()
@@ -729,7 +730,7 @@ status_t ScreenshotClient::update(const sp& display,
status_t err = s->captureScreen(display, mProducer, sourceCrop,
reqWidth, reqHeight, minLayerZ, maxLayerZ, useIdentityTransform,
- static_cast(rotation));
+ static_cast(rotation), true);
if (err == NO_ERROR) {
err = mCpuConsumer->lockNextBuffer(&mBuffer);
diff --git a/services/surfaceflinger/RenderEngine/GLES11RenderEngine.cpp b/services/surfaceflinger/RenderEngine/GLES11RenderEngine.cpp
index 1a9f59b58..aded96fa4 100644
--- a/services/surfaceflinger/RenderEngine/GLES11RenderEngine.cpp
+++ b/services/surfaceflinger/RenderEngine/GLES11RenderEngine.cpp
@@ -210,28 +210,46 @@ void GLES11RenderEngine::disableBlending() {
}
void GLES11RenderEngine::bindImageAsFramebuffer(EGLImageKHR image,
- uint32_t* texName, uint32_t* fbName, uint32_t* status) {
+ uint32_t* texName, uint32_t* fbName, uint32_t* status,
+ bool useReadPixels, int reqWidth, int reqHeight) {
GLuint tname, name;
- // turn our EGLImage into a texture
- glGenTextures(1, &tname);
- glBindTexture(GL_TEXTURE_2D, tname);
- glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, (GLeglImageOES)image);
+ if (!useReadPixels) {
+ // turn our EGLImage into a texture
+ glGenTextures(1, &tname);
+ glBindTexture(GL_TEXTURE_2D, tname);
+ glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, (GLeglImageOES)image);
- // create a Framebuffer Object to render into
- glGenFramebuffersOES(1, &name);
- glBindFramebufferOES(GL_FRAMEBUFFER_OES, name);
- glFramebufferTexture2DOES(GL_FRAMEBUFFER_OES,
- GL_COLOR_ATTACHMENT0_OES, GL_TEXTURE_2D, tname, 0);
+ // create a Framebuffer Object to render into
+ glGenFramebuffersOES(1, &name);
+ glBindFramebufferOES(GL_FRAMEBUFFER_OES, name);
+ glFramebufferTexture2DOES(GL_FRAMEBUFFER_OES,
+ GL_COLOR_ATTACHMENT0_OES, GL_TEXTURE_2D, tname, 0);
+ } else {
+ // since we're going to use glReadPixels() anyways,
+ // use an intermediate renderbuffer instead
+ glGenRenderbuffersOES(1, &tname);
+ glBindRenderbufferOES(GL_RENDERBUFFER_OES, tname);
+ glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_RGBA8_OES, reqWidth, reqHeight);
+ // create a FBO to render into
+ glGenFramebuffersOES(1, &name);
+ glBindFramebufferOES(GL_FRAMEBUFFER_OES, name);
+ glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES,
+ GL_RENDERBUFFER_OES, tname);
+ }
*status = glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES);
*texName = tname;
*fbName = name;
}
-void GLES11RenderEngine::unbindFramebuffer(uint32_t texName, uint32_t fbName) {
+void GLES11RenderEngine::unbindFramebuffer(uint32_t texName, uint32_t fbName,
+ bool useReadPixels) {
glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0);
glDeleteFramebuffersOES(1, &fbName);
- glDeleteTextures(1, &texName);
+ if (!useReadPixels)
+ glDeleteTextures(1, &texName);
+ else
+ glDeleteRenderbuffersOES(1, &texName);
}
void GLES11RenderEngine::setupFillWithColor(float r, float g, float b, float a) {
diff --git a/services/surfaceflinger/RenderEngine/GLES11RenderEngine.h b/services/surfaceflinger/RenderEngine/GLES11RenderEngine.h
index 08de6465f..77824ce4d 100644
--- a/services/surfaceflinger/RenderEngine/GLES11RenderEngine.h
+++ b/services/surfaceflinger/RenderEngine/GLES11RenderEngine.h
@@ -40,8 +40,9 @@ class GLES11RenderEngine : public RenderEngine {
GLint mMaxTextureSize;
virtual void bindImageAsFramebuffer(EGLImageKHR image,
- uint32_t* texName, uint32_t* fbName, uint32_t* status);
- virtual void unbindFramebuffer(uint32_t texName, uint32_t fbName);
+ uint32_t* texName, uint32_t* fbName, uint32_t* status, bool useReadPixels,
+ int reqWidth, int reqHeight);
+ virtual void unbindFramebuffer(uint32_t texName, uint32_t fbName, bool useReadPixels);
public:
GLES11RenderEngine();
diff --git a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp
index 1fabaf5be..a35aa7863 100644
--- a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp
+++ b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp
@@ -185,27 +185,44 @@ void GLES20RenderEngine::disableBlending() {
void GLES20RenderEngine::bindImageAsFramebuffer(EGLImageKHR image,
- uint32_t* texName, uint32_t* fbName, uint32_t* status) {
+ uint32_t* texName, uint32_t* fbName, uint32_t* status,
+ bool useReadPixels, int reqWidth, int reqHeight) {
GLuint tname, name;
- // turn our EGLImage into a texture
- glGenTextures(1, &tname);
- glBindTexture(GL_TEXTURE_2D, tname);
- glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, (GLeglImageOES)image);
+ if (!useReadPixels) {
+ // turn our EGLImage into a texture
+ glGenTextures(1, &tname);
+ glBindTexture(GL_TEXTURE_2D, tname);
+ glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, (GLeglImageOES)image);
- // create a Framebuffer Object to render into
- glGenFramebuffers(1, &name);
- glBindFramebuffer(GL_FRAMEBUFFER, name);
- glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tname, 0);
+ // create a Framebuffer Object to render into
+ glGenFramebuffers(1, &name);
+ glBindFramebuffer(GL_FRAMEBUFFER, name);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tname, 0);
+ } else {
+ // since we're going to use glReadPixels() anyways,
+ // use an intermediate renderbuffer instead
+ glGenRenderbuffers(1, &tname);
+ glBindRenderbuffer(GL_RENDERBUFFER, tname);
+ glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8_OES, reqWidth, reqHeight);
+ // create a FBO to render into
+ glGenFramebuffers(1, &name);
+ glBindFramebuffer(GL_FRAMEBUFFER, name);
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, tname);
+ }
*status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
*texName = tname;
*fbName = name;
}
-void GLES20RenderEngine::unbindFramebuffer(uint32_t texName, uint32_t fbName) {
+void GLES20RenderEngine::unbindFramebuffer(uint32_t texName, uint32_t fbName,
+ bool useReadPixels) {
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glDeleteFramebuffers(1, &fbName);
- glDeleteTextures(1, &texName);
+ if (!useReadPixels)
+ glDeleteTextures(1, &texName);
+ else
+ glDeleteRenderbuffers(1, &texName);
}
void GLES20RenderEngine::setupFillWithColor(float r, float g, float b, float a) {
diff --git a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h
index 819356a62..6074a3d0b 100644
--- a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h
+++ b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h
@@ -55,8 +55,9 @@ class GLES20RenderEngine : public RenderEngine {
Vector mGroupStack;
virtual void bindImageAsFramebuffer(EGLImageKHR image,
- uint32_t* texName, uint32_t* fbName, uint32_t* status);
- virtual void unbindFramebuffer(uint32_t texName, uint32_t fbName);
+ uint32_t* texName, uint32_t* fbName, uint32_t* status,
+ bool useReadPixels, int reqWidth, int reqHeight);
+ virtual void unbindFramebuffer(uint32_t texName, uint32_t fbName, bool useReadPixels);
public:
GLES20RenderEngine();
diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.cpp b/services/surfaceflinger/RenderEngine/RenderEngine.cpp
index 7cd42e405..faae6fc1c 100644
--- a/services/surfaceflinger/RenderEngine/RenderEngine.cpp
+++ b/services/surfaceflinger/RenderEngine/RenderEngine.cpp
@@ -262,9 +262,11 @@ void RenderEngine::dump(String8& result) {
// ---------------------------------------------------------------------------
RenderEngine::BindImageAsFramebuffer::BindImageAsFramebuffer(
- RenderEngine& engine, EGLImageKHR image) : mEngine(engine)
+ RenderEngine& engine, EGLImageKHR image, bool useReadPixels,
+ int reqWidth, int reqHeight) : mEngine(engine), mUseReadPixels(useReadPixels)
{
- mEngine.bindImageAsFramebuffer(image, &mTexName, &mFbName, &mStatus);
+ mEngine.bindImageAsFramebuffer(image, &mTexName, &mFbName, &mStatus,
+ useReadPixels, reqWidth, reqHeight);
ALOGE_IF(mStatus != GL_FRAMEBUFFER_COMPLETE_OES,
"glCheckFramebufferStatusOES error %d", mStatus);
@@ -272,7 +274,7 @@ RenderEngine::BindImageAsFramebuffer::BindImageAsFramebuffer(
RenderEngine::BindImageAsFramebuffer::~BindImageAsFramebuffer() {
// back to main framebuffer
- mEngine.unbindFramebuffer(mTexName, mFbName);
+ mEngine.unbindFramebuffer(mTexName, mFbName, mUseReadPixels);
}
status_t RenderEngine::BindImageAsFramebuffer::getStatus() const {
diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.h b/services/surfaceflinger/RenderEngine/RenderEngine.h
index 31a961efe..c9a043a62 100644
--- a/services/surfaceflinger/RenderEngine/RenderEngine.h
+++ b/services/surfaceflinger/RenderEngine/RenderEngine.h
@@ -51,8 +51,11 @@ class RenderEngine {
EGLContext mEGLContext;
void setEGLHandles(EGLConfig config, EGLContext ctxt);
- virtual void bindImageAsFramebuffer(EGLImageKHR image, uint32_t* texName, uint32_t* fbName, uint32_t* status) = 0;
- virtual void unbindFramebuffer(uint32_t texName, uint32_t fbName) = 0;
+ virtual void bindImageAsFramebuffer(EGLImageKHR image, uint32_t* texName,
+ uint32_t* fbName, uint32_t* status, bool useReadPixels, int reqWidth,
+ int reqHeight) = 0;
+ virtual void unbindFramebuffer(uint32_t texName, uint32_t fbName,
+ bool useReadPixels) = 0;
protected:
RenderEngine();
@@ -83,8 +86,10 @@ public:
RenderEngine& mEngine;
uint32_t mTexName, mFbName;
uint32_t mStatus;
+ bool mUseReadPixels;
public:
- BindImageAsFramebuffer(RenderEngine& engine, EGLImageKHR image);
+ BindImageAsFramebuffer(RenderEngine& engine, EGLImageKHR image,
+ bool useReadPixels, int reqWidth, int reqHeight);
~BindImageAsFramebuffer();
int getStatus() const;
};
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index c5e50e88c..8e928120e 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -3160,7 +3160,8 @@ status_t SurfaceFlinger::captureScreen(const sp& display,
const sp& producer,
Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
uint32_t minLayerZ, uint32_t maxLayerZ,
- bool useIdentityTransform, ISurfaceComposer::Rotation rotation) {
+ bool useIdentityTransform, ISurfaceComposer::Rotation rotation,
+ bool useReadPixels) {
if (CC_UNLIKELY(display == 0))
return BAD_VALUE;
@@ -3210,6 +3211,7 @@ status_t SurfaceFlinger::captureScreen(const sp& display,
uint32_t minLayerZ,maxLayerZ;
bool useIdentityTransform;
Transform::orientation_flags rotation;
+ bool useReadPixels;
status_t result;
public:
MessageCaptureScreen(SurfaceFlinger* flinger,
@@ -3217,12 +3219,14 @@ status_t SurfaceFlinger::captureScreen(const sp& display,
const sp& producer,
Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
uint32_t minLayerZ, uint32_t maxLayerZ,
- bool useIdentityTransform, Transform::orientation_flags rotation)
+ bool useIdentityTransform, Transform::orientation_flags rotation,
+ bool useReadPixels)
: flinger(flinger), display(display), producer(producer),
sourceCrop(sourceCrop), reqWidth(reqWidth), reqHeight(reqHeight),
minLayerZ(minLayerZ), maxLayerZ(maxLayerZ),
useIdentityTransform(useIdentityTransform),
rotation(rotation),
+ useReadPixels(useReadPixels),
result(PERMISSION_DENIED)
{
}
@@ -3232,9 +3236,10 @@ status_t SurfaceFlinger::captureScreen(const sp& display,
virtual bool handler() {
Mutex::Autolock _l(flinger->mStateLock);
sp hw(flinger->getDisplayDevice(display));
+ bool useReadPixels = this->useReadPixels && !flinger->mGpuToCpuSupported;
result = flinger->captureScreenImplLocked(hw, producer,
sourceCrop, reqWidth, reqHeight, minLayerZ, maxLayerZ,
- useIdentityTransform, rotation);
+ useIdentityTransform, rotation, useReadPixels);
static_cast(IInterface::asBinder(producer).get())->exit(result);
return true;
}
@@ -3257,7 +3262,7 @@ status_t SurfaceFlinger::captureScreen(const sp& display,
sp msg = new MessageCaptureScreen(this,
display, IGraphicBufferProducer::asInterface( wrapper ),
sourceCrop, reqWidth, reqHeight, minLayerZ, maxLayerZ,
- useIdentityTransform, rotationFlags);
+ useIdentityTransform, rotationFlags, useReadPixels);
status_t res = postMessageAsync(msg);
if (res == NO_ERROR) {
@@ -3347,7 +3352,8 @@ status_t SurfaceFlinger::captureScreenImplLocked(
const sp& producer,
Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
uint32_t minLayerZ, uint32_t maxLayerZ,
- bool useIdentityTransform, Transform::orientation_flags rotation)
+ bool useIdentityTransform, Transform::orientation_flags rotation,
+ bool useReadPixels)
{
ATRACE_CALL();
@@ -3399,7 +3405,8 @@ status_t SurfaceFlinger::captureScreenImplLocked(
if (image != EGL_NO_IMAGE_KHR) {
// this binds the given EGLImage as a framebuffer for the
// duration of this scope.
- RenderEngine::BindImageAsFramebuffer imageBond(getRenderEngine(), image);
+ RenderEngine::BindImageAsFramebuffer imageBond(getRenderEngine(), image,
+ useReadPixels, reqWidth, reqHeight);
if (imageBond.getStatus() == NO_ERROR) {
// this will in fact render into our dequeued buffer
// via an FBO, which means we didn't have to create
@@ -3446,6 +3453,15 @@ status_t SurfaceFlinger::captureScreenImplLocked(
ALOGW("captureScreen: error creating EGL fence: %#x", eglGetError());
}
}
+ if (useReadPixels) {
+ sp buf = static_cast(buffer);
+ void* vaddr;
+ if (buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, &vaddr) == NO_ERROR) {
+ getRenderEngine().readPixels(0, 0, buffer->stride, reqHeight,
+ (uint32_t *)vaddr);
+ buf->unlock();
+ }
+ }
if (DEBUG_SCREENSHOTS) {
uint32_t* pixels = new uint32_t[reqWidth*reqHeight];
getRenderEngine().readPixels(0, 0, reqWidth, reqHeight, pixels);
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 6e5df04e3..b559f0e55 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -212,7 +212,8 @@ private:
const sp& producer,
Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
uint32_t minLayerZ, uint32_t maxLayerZ,
- bool useIdentityTransform, ISurfaceComposer::Rotation rotation);
+ bool useIdentityTransform, ISurfaceComposer::Rotation rotation,
+ bool isCpuConsumer);
virtual status_t getDisplayStats(const sp& display,
DisplayStatInfo* stats);
virtual status_t getDisplayConfigs(const sp& display,
@@ -366,7 +367,8 @@ private:
const sp& producer,
Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
uint32_t minLayerZ, uint32_t maxLayerZ,
- bool useIdentityTransform, Transform::orientation_flags rotation);
+ bool useIdentityTransform, Transform::orientation_flags rotation,
+ bool useReadPixels);
/* ------------------------------------------------------------------------
* EGL