Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save steven676/7276913 to your computer and use it in GitHub Desktop.
Save steven676/7276913 to your computer and use it in GitHub Desktop.
[PATCH 2/6] Restore support for glReadPixels screenshot path (against android-4.4_r1.2 frameworks/native)
From 1e81c876af6e11790632c9fdfd32768f970ccebe Mon Sep 17 00:00:00 2001
From: Steven Luo <steven+android@steven676.net>
Date: Fri, 1 Nov 2013 23:26:39 -0700
Subject: [PATCH 2/2] Restore support for glReadPixels screenshot path
This is needed for SGX530/540 GPUs.
This reverts commit 3ca76f416bc8665a97636ca8a2d0128b9da9d92c.
Conflicts:
services/surfaceflinger/SurfaceFlinger.cpp
Change-Id: I52b29dac9bfe23d1f27bd2fe94db6b9adbcfd900
---
include/gui/ISurfaceComposer.h | 3 +-
libs/gui/ISurfaceComposer.cpp | 8 +++-
libs/gui/SurfaceComposerClient.cpp | 5 ++-
.../RenderEngine/GLES11RenderEngine.cpp | 43 ++++++++++++++------
.../RenderEngine/GLES11RenderEngine.h | 4 +-
.../RenderEngine/GLES20RenderEngine.cpp | 41 +++++++++++++------
.../RenderEngine/GLES20RenderEngine.h | 5 ++-
.../surfaceflinger/RenderEngine/RenderEngine.cpp | 8 ++--
.../surfaceflinger/RenderEngine/RenderEngine.h | 7 ++--
services/surfaceflinger/SurfaceFlinger.cpp | 34 ++++++++++++----
services/surfaceflinger/SurfaceFlinger.h | 5 ++-
11 files changed, 113 insertions(+), 50 deletions(-)
diff --git a/include/gui/ISurfaceComposer.h b/include/gui/ISurfaceComposer.h
index 5c3c99c..319aeaa 100644
--- a/include/gui/ISurfaceComposer.h
+++ b/include/gui/ISurfaceComposer.h
@@ -120,7 +120,8 @@ public:
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;
+ uint32_t minLayerZ, uint32_t maxLayerZ,
+ bool isCpuConsumer) = 0;
};
// ----------------------------------------------------------------------------
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index aab0604..6d22066 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -105,7 +105,8 @@ public:
virtual status_t captureScreen(const sp<IBinder>& display,
const sp<IGraphicBufferProducer>& producer,
uint32_t reqWidth, uint32_t reqHeight,
- uint32_t minLayerZ, uint32_t maxLayerZ)
+ uint32_t minLayerZ, uint32_t maxLayerZ,
+ bool isCpuConsumer)
{
Parcel data, reply;
data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
@@ -115,6 +116,7 @@ public:
data.writeInt32(reqHeight);
data.writeInt32(minLayerZ);
data.writeInt32(maxLayerZ);
+ data.writeInt32(isCpuConsumer);
remote()->transact(BnSurfaceComposer::CAPTURE_SCREEN, data, &reply);
return reply.readInt32();
}
@@ -285,8 +287,10 @@ status_t BnSurfaceComposer::onTransact(
uint32_t reqHeight = data.readInt32();
uint32_t minLayerZ = data.readInt32();
uint32_t maxLayerZ = data.readInt32();
+ bool isCpuConsumer = data.readInt32();
status_t res = captureScreen(display, producer,
- reqWidth, reqHeight, minLayerZ, maxLayerZ);
+ reqWidth, reqHeight, minLayerZ, maxLayerZ,
+ isCpuConsumer);
reply->writeInt32(res);
return NO_ERROR;
}
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index aafc4d2..7962715 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -627,7 +627,8 @@ status_t ScreenshotClient::capture(
sp<ISurfaceComposer> s(ComposerService::getComposerService());
if (s == NULL) return NO_INIT;
return s->captureScreen(display, producer,
- reqWidth, reqHeight, minLayerZ, maxLayerZ);
+ reqWidth, reqHeight, minLayerZ, maxLayerZ,
+ false);
}
ScreenshotClient::ScreenshotClient()
@@ -662,7 +663,7 @@ status_t ScreenshotClient::update(const sp<IBinder>& display,
}
status_t err = s->captureScreen(display, mBufferQueue,
- reqWidth, reqHeight, minLayerZ, maxLayerZ);
+ reqWidth, reqHeight, minLayerZ, maxLayerZ, true);
if (err == NO_ERROR) {
err = mCpuConsumer->lockNextBuffer(&mBuffer);
diff --git a/services/surfaceflinger/RenderEngine/GLES11RenderEngine.cpp b/services/surfaceflinger/RenderEngine/GLES11RenderEngine.cpp
index 521a5d2..da69965 100644
--- a/services/surfaceflinger/RenderEngine/GLES11RenderEngine.cpp
+++ b/services/surfaceflinger/RenderEngine/GLES11RenderEngine.cpp
@@ -185,28 +185,45 @@ 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);
-
- // 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);
+ 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);
+ } 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 cd53aab..6e4c46e 100644
--- a/services/surfaceflinger/RenderEngine/GLES11RenderEngine.h
+++ b/services/surfaceflinger/RenderEngine/GLES11RenderEngine.h
@@ -39,8 +39,8 @@ 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 a2a6270..ada3ab0 100644
--- a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp
+++ b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp
@@ -151,27 +151,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);
-
- // 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);
+ 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);
+ } 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 8b67fcc..d5c5b5d 100644
--- a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h
+++ b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h
@@ -54,8 +54,9 @@ class GLES20RenderEngine : public RenderEngine {
Vector<Group> 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 ba82cad..8a8ee56 100644
--- a/services/surfaceflinger/RenderEngine/RenderEngine.cpp
+++ b/services/surfaceflinger/RenderEngine/RenderEngine.cpp
@@ -217,9 +217,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);
@@ -227,7 +229,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 3c7f9ab..e69b914 100644
--- a/services/surfaceflinger/RenderEngine/RenderEngine.h
+++ b/services/surfaceflinger/RenderEngine/RenderEngine.h
@@ -47,8 +47,8 @@ class RenderEngine {
EGLContext mEGLContext;
void setEGLContext(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();
@@ -76,8 +76,9 @@ 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 5434369..9f2ae46 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -2861,7 +2861,8 @@ public:
status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
const sp<IGraphicBufferProducer>& producer,
uint32_t reqWidth, uint32_t reqHeight,
- uint32_t minLayerZ, uint32_t maxLayerZ) {
+ uint32_t minLayerZ, uint32_t maxLayerZ,
+ bool useReadPixels) {
if (CC_UNLIKELY(display == 0))
return BAD_VALUE;
@@ -2887,16 +2888,18 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
sp<IGraphicBufferProducer> producer;
uint32_t reqWidth, reqHeight;
uint32_t minLayerZ,maxLayerZ;
+ bool useReadPixels;
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)
+ uint32_t minLayerZ, uint32_t maxLayerZ, bool useReadPixels)
: flinger(flinger), display(display), producer(producer),
reqWidth(reqWidth), reqHeight(reqHeight),
minLayerZ(minLayerZ), maxLayerZ(maxLayerZ),
+ useReadPixels(useReadPixels),
result(PERMISSION_DENIED)
{
}
@@ -2906,8 +2909,10 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
virtual bool handler() {
Mutex::Autolock _l(flinger->mStateLock);
sp<const DisplayDevice> hw(flinger->getDisplayDevice(display));
+ bool useReadPixels = this->useReadPixels && !flinger->mGpuToCpuSupported;
result = flinger->captureScreenImplLocked(hw,
- producer, reqWidth, reqHeight, minLayerZ, maxLayerZ);
+ producer, reqWidth, reqHeight, minLayerZ, maxLayerZ,
+ useReadPixels);
static_cast<GraphicProducerWrapper*>(producer->asBinder().get())->exit(result);
return true;
}
@@ -2929,7 +2934,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);
+ reqWidth, reqHeight, minLayerZ, maxLayerZ,
+ useReadPixels);
status_t res = postMessageAsync(msg);
if (res == NO_ERROR) {
@@ -2989,7 +2995,8 @@ 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)
+ uint32_t minLayerZ, uint32_t maxLayerZ,
+ bool useReadPixels)
{
ATRACE_CALL();
@@ -3013,8 +3020,10 @@ status_t SurfaceFlinger::captureScreenImplLocked(
status_t result = NO_ERROR;
if (native_window_api_connect(window, NATIVE_WINDOW_API_EGL) == NO_ERROR) {
- uint32_t usage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN |
- GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE;
+ uint32_t usage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN;
+ if (!useReadPixels) {
+ usage |= GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE;
+ }
int err = 0;
err = native_window_set_buffers_dimensions(window, reqWidth, reqHeight);
@@ -3036,7 +3045,7 @@ 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
@@ -3066,6 +3075,15 @@ status_t SurfaceFlinger::captureScreenImplLocked(
// not fatal
}
+ if (useReadPixels) {
+ sp<GraphicBuffer> buf = static_cast<GraphicBuffer*>(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 f08e66a..5b98685 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -202,7 +202,7 @@ private:
virtual status_t captureScreen(const sp<IBinder>& display,
const sp<IGraphicBufferProducer>& producer,
uint32_t reqWidth, uint32_t reqHeight,
- uint32_t minLayerZ, uint32_t maxLayerZ);
+ uint32_t minLayerZ, uint32_t maxLayerZ, bool isCpuConsumer);
// called when screen needs to turn off
virtual void blank(const sp<IBinder>& display);
// called when screen is turning back on
@@ -312,7 +312,8 @@ private:
const sp<const DisplayDevice>& hw,
const sp<IGraphicBufferProducer>& producer,
uint32_t reqWidth, uint32_t reqHeight,
- uint32_t minLayerZ, uint32_t maxLayerZ);
+ uint32_t minLayerZ, uint32_t maxLayerZ,
+ bool useReadPixels);
/* ------------------------------------------------------------------------
* EGL
--
1.7.10.4
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment