am 6a70cb8a: Merge "Refactor some code in surfaceflinger in preparation of upcoming changes" into kraken

This commit is contained in:
Mathias Agopian
2010-05-12 17:36:27 -07:00
committed by Android Git Automerger
10 changed files with 555 additions and 366 deletions

View File

@ -13,6 +13,7 @@ LOCAL_SRC_FILES:= \
LayerDim.cpp \
MessageQueue.cpp \
SurfaceFlinger.cpp \
TextureManager.cpp \
Tokenizer.cpp \
Transform.cpp

View File

@ -48,40 +48,48 @@ template <typename T> inline T min(T a, T b) {
// ---------------------------------------------------------------------------
Layer::Layer(SurfaceFlinger* flinger, DisplayID display,
const sp<Client>& c, int32_t i)
: LayerBaseClient(flinger, display, c, i),
const sp<Client>& client, int32_t i)
: LayerBaseClient(flinger, display, client, i),
lcblk(NULL),
mSecure(false),
mNeedsBlending(true),
mNeedsDithering(false)
mNeedsDithering(false),
mTextureManager(mFlags),
mBufferManager(mTextureManager)
{
// no OpenGL operation is possible here, since we might not be
// in the OpenGL thread.
mFrontBufferIndex = lcblk->getFrontBuffer();
lcblk = new SharedBufferServer(
client->ctrlblk, i, mBufferManager.getBufferCount(),
getIdentity());
mBufferManager.setActiveBufferIndex( lcblk->getFrontBuffer() );
}
Layer::~Layer()
{
destroy();
// the actual buffers will be destroyed here
delete lcblk;
}
// called with SurfaceFlinger::mStateLock as soon as the layer is entered
// in the purgatory list
void Layer::onRemoved()
{
// wake up the condition
lcblk->setStatus(NO_INIT);
}
void Layer::destroy()
{
for (size_t i=0 ; i<NUM_BUFFERS ; i++) {
if (mTextures[i].name != -1U) {
glDeleteTextures(1, &mTextures[i].name);
mTextures[i].name = -1U;
}
if (mTextures[i].image != EGL_NO_IMAGE_KHR) {
EGLDisplay dpy(mFlinger->graphicPlane(0).getEGLDisplay());
eglDestroyImageKHR(dpy, mTextures[i].image);
mTextures[i].image = EGL_NO_IMAGE_KHR;
}
Mutex::Autolock _l(mLock);
mBuffers[i].clear();
mWidth = mHeight = 0;
}
EGLDisplay dpy(mFlinger->graphicPlane(0).getEGLDisplay());
mBufferManager.destroy(dpy);
mSurface.clear();
Mutex::Autolock _l(mLock);
mWidth = mHeight = 0;
}
sp<LayerBaseClient::Surface> Layer::createSurface() const
@ -131,17 +139,13 @@ status_t Layer::setBuffers( uint32_t w, uint32_t h,
int layerRedsize = info.getSize(PixelFormatInfo::INDEX_RED);
mNeedsDithering = layerRedsize > displayRedSize;
for (size_t i=0 ; i<NUM_BUFFERS ; i++) {
mBuffers[i] = new GraphicBuffer();
}
mSurface = new SurfaceLayer(mFlinger, clientIndex(), this);
return NO_ERROR;
}
void Layer::reloadTexture(const Region& dirty)
{
Mutex::Autolock _l(mLock);
sp<GraphicBuffer> buffer(getFrontBufferLocked());
sp<GraphicBuffer> buffer(mBufferManager.getActiveBuffer());
if (buffer == NULL) {
// this situation can happen if we ran out of memory for instance.
// not much we can do. continue to use whatever texture was bound
@ -149,37 +153,24 @@ void Layer::reloadTexture(const Region& dirty)
return;
}
const int index = mFrontBufferIndex;
// create the new texture name if needed
if (UNLIKELY(mTextures[index].name == -1U)) {
mTextures[index].name = createTexture();
mTextures[index].width = 0;
mTextures[index].height = 0;
}
#ifdef EGL_ANDROID_image_native_buffer
if (mFlags & DisplayHardware::DIRECT_TEXTURE) {
if (mTextures[index].dirty) {
if (initializeEglImage(buffer, &mTextures[index]) != NO_ERROR) {
// not sure what we can do here...
mFlags &= ~DisplayHardware::DIRECT_TEXTURE;
goto slowpath;
}
EGLDisplay dpy(mFlinger->graphicPlane(0).getEGLDisplay());
if (mBufferManager.initEglImage(dpy, buffer) != NO_ERROR) {
// not sure what we can do here...
mFlags &= ~DisplayHardware::DIRECT_TEXTURE;
goto slowpath;
}
} else
#endif
{
slowpath:
for (size_t i=0 ; i<NUM_BUFFERS ; i++) {
mTextures[i].image = EGL_NO_IMAGE_KHR;
}
GGLSurface t;
status_t res = buffer->lock(&t, GRALLOC_USAGE_SW_READ_OFTEN);
LOGE_IF(res, "error %d (%s) locking buffer %p",
res, strerror(res), buffer.get());
if (res == NO_ERROR) {
loadTexture(&mTextures[0], dirty, t);
mBufferManager.loadTexture(dirty, t);
buffer->unlock();
}
}
@ -187,11 +178,8 @@ slowpath:
void Layer::onDraw(const Region& clip) const
{
int index = mFrontBufferIndex;
if (mTextures[index].image == EGL_NO_IMAGE_KHR)
index = 0;
GLuint textureName = mTextures[index].name;
if (UNLIKELY(textureName == -1LU)) {
Texture tex(mBufferManager.getActiveTexture());
if (tex.name == -1LU) {
// the texture has not been created yet, this Layer has
// in fact never been drawn into. This happens frequently with
// SurfaceView because the WindowManager can't know when the client
@ -217,7 +205,7 @@ void Layer::onDraw(const Region& clip) const
}
return;
}
drawWithOpenGL(clip, mTextures[index]);
drawWithOpenGL(clip, tex);
}
sp<GraphicBuffer> Layer::requestBuffer(int index, int usage)
@ -254,15 +242,7 @@ sp<GraphicBuffer> Layer::requestBuffer(int index, int usage)
Mutex::Autolock _l(mLock);
w = mWidth;
h = mHeight;
buffer = mBuffers[index];
// destroy() could have been called before we get here, we log it
// because it's uncommon, and the code below should handle it
LOGW_IF(buffer==0,
"mBuffers[%d] is null (mWidth=%d, mHeight=%d)",
index, w, h);
mBuffers[index].clear();
buffer = mBufferManager.detachBuffer(index);
}
const uint32_t effectiveUsage = getEffectiveUsage(usage);
@ -290,10 +270,7 @@ sp<GraphicBuffer> Layer::requestBuffer(int index, int usage)
if (err == NO_ERROR && buffer->handle != 0) {
Mutex::Autolock _l(mLock);
if (mWidth && mHeight) {
// and we have new buffer
mBuffers[index] = buffer;
// texture is now dirty...
mTextures[index].dirty = true;
mBufferManager.attachBuffer(index, buffer);
} else {
// oops we got killed while we were allocating the buffer
buffer.clear();
@ -338,13 +315,10 @@ uint32_t Layer::doTransaction(uint32_t flags)
(front.requested_h != temp.requested_h)) {
// the size changed, we need to ask our client to request a new buffer
LOGD_IF(DEBUG_RESIZE,
"resize (layer=%p), requested (%dx%d), "
"drawing (%d,%d), (%dx%d), (%dx%d)",
"resize (layer=%p), requested (%dx%d), drawing (%d,%d)",
this,
int(temp.requested_w), int(temp.requested_h),
int(front.requested_w), int(front.requested_h),
int(mBuffers[0]->getWidth()), int(mBuffers[0]->getHeight()),
int(mBuffers[1]->getWidth()), int(mBuffers[1]->getHeight()));
int(front.requested_w), int(front.requested_h));
// we're being resized and there is a freeze display request,
// acquire a freeze lock, so that the screen stays put
@ -396,22 +370,25 @@ void Layer::setDrawingSize(uint32_t w, uint32_t h) {
void Layer::lockPageFlip(bool& recomputeVisibleRegions)
{
ssize_t buf = lcblk->retireAndLock();
if (buf < NO_ERROR) {
//LOGW("nothing to retire (%s)", strerror(-buf));
// NOTE: here the buffer is locked because we will used
if (buf == NOT_ENOUGH_DATA) {
// NOTE: This is not an error, it simply means there is nothing to
// retire. The buffer is locked because we will use it
// for composition later in the loop
return;
}
// ouch, this really should never happen
if (uint32_t(buf)>=NUM_BUFFERS) {
if (buf < NO_ERROR) {
LOGE("retireAndLock() buffer index (%d) out of range", buf);
mPostedDirtyRegion.clear();
return;
}
// we retired a buffer, which becomes the new front buffer
mFrontBufferIndex = buf;
if (mBufferManager.setActiveBufferIndex(buf) < NO_ERROR) {
LOGE("retireAndLock() buffer index (%d) out of range", buf);
mPostedDirtyRegion.clear();
return;
}
// get the dirty region
sp<GraphicBuffer> newFrontBuffer(getBuffer(buf));
@ -503,10 +480,9 @@ void Layer::unlockPageFlip(
void Layer::finishPageFlip()
{
status_t err = lcblk->unlock( mFrontBufferIndex );
LOGE_IF(err!=NO_ERROR,
"layer %p, buffer=%d wasn't locked!",
this, mFrontBufferIndex);
int buf = mBufferManager.getActiveBufferIndex();
status_t err = lcblk->unlock( buf );
LOGE_IF(err!=NO_ERROR, "layer %p, buffer=%d wasn't locked!", this, buf);
}
@ -543,6 +519,109 @@ void Layer::dump(String8& result, char* buffer, size_t SIZE) const
// ---------------------------------------------------------------------------
Layer::BufferManager::BufferManager(TextureManager& tm)
: mTextureManager(tm), mActiveBuffer(0), mFailover(false)
{
}
size_t Layer::BufferManager::getBufferCount() const {
return NUM_BUFFERS;
}
// only for debugging
sp<GraphicBuffer> Layer::BufferManager::getBuffer(size_t index) const {
return mBufferData[index].buffer;
}
status_t Layer::BufferManager::setActiveBufferIndex(size_t index) {
// TODO: need to validate 'index'
mActiveBuffer = index;
return NO_ERROR;
}
size_t Layer::BufferManager::getActiveBufferIndex() const {
return mActiveBuffer;
}
Texture Layer::BufferManager::getActiveTexture() const {
return mFailover ? mFailoverTexture : mBufferData[mActiveBuffer].texture;
}
sp<GraphicBuffer> Layer::BufferManager::getActiveBuffer() const {
Mutex::Autolock _l(mLock);
return mBufferData[mActiveBuffer].buffer;
}
sp<GraphicBuffer> Layer::BufferManager::detachBuffer(size_t index)
{
sp<GraphicBuffer> buffer;
Mutex::Autolock _l(mLock);
buffer = mBufferData[index].buffer;
mBufferData[index].buffer = 0;
return buffer;
}
status_t Layer::BufferManager::attachBuffer(size_t index,
const sp<GraphicBuffer>& buffer)
{
Mutex::Autolock _l(mLock);
mBufferData[index].buffer = buffer;
mBufferData[index].texture.dirty = true;
return NO_ERROR;
}
status_t Layer::BufferManager::destroyTexture(Texture* tex, EGLDisplay dpy)
{
if (tex->name != -1U) {
glDeleteTextures(1, &tex->name);
tex->name = -1U;
}
if (tex->image != EGL_NO_IMAGE_KHR) {
eglDestroyImageKHR(dpy, tex->image);
tex->image = EGL_NO_IMAGE_KHR;
}
return NO_ERROR;
}
status_t Layer::BufferManager::destroy(EGLDisplay dpy)
{
Mutex::Autolock _l(mLock);
for (size_t i=0 ; i<NUM_BUFFERS ; i++) {
destroyTexture(&mBufferData[i].texture, dpy);
mBufferData[i].buffer = 0;
}
destroyTexture(&mFailoverTexture, dpy);
return NO_ERROR;
}
status_t Layer::BufferManager::initEglImage(EGLDisplay dpy,
const sp<GraphicBuffer>& buffer)
{
size_t index = mActiveBuffer;
Texture& texture(mBufferData[index].texture);
status_t err = mTextureManager.initEglImage(&texture, dpy, buffer);
// if EGLImage fails, we switch to regular texture mode, and we
// free all resources associated with using EGLImages.
if (err == NO_ERROR) {
mFailover = false;
destroyTexture(&mFailoverTexture, dpy);
} else {
mFailover = true;
for (size_t i=0 ; i<NUM_BUFFERS ; i++) {
destroyTexture(&mBufferData[i].texture, dpy);
}
}
return err;
}
status_t Layer::BufferManager::loadTexture(
const Region& dirty, const GGLSurface& t)
{
return mTextureManager.loadTexture(&mFailoverTexture, dirty, t);
}
// ---------------------------------------------------------------------------
Layer::SurfaceLayer::SurfaceLayer(const sp<SurfaceFlinger>& flinger,
SurfaceID id, const sp<Layer>& owner)
: Surface(flinger, id, owner->getIdentity(), owner)
@ -558,11 +637,7 @@ sp<GraphicBuffer> Layer::SurfaceLayer::requestBuffer(int index, int usage)
sp<GraphicBuffer> buffer;
sp<Layer> owner(getOwner());
if (owner != 0) {
LOGE_IF(uint32_t(index)>=NUM_BUFFERS,
"getBuffer() index (%d) out of range", index);
if (uint32_t(index) < NUM_BUFFERS) {
buffer = owner->requestBuffer(index, usage);
}
buffer = owner->requestBuffer(index, usage);
}
return buffer;
}

View File

@ -31,6 +31,7 @@
#include "LayerBase.h"
#include "Transform.h"
#include "TextureManager.h"
namespace android {
@ -41,11 +42,13 @@ class FreezeLock;
// ---------------------------------------------------------------------------
const size_t NUM_BUFFERS = 2;
class Layer : public LayerBaseClient
{
public:
public:
// lcblk is (almost) only accessed from the main SF thread, in the places
// where it's not, a reference to Client must be held
SharedBufferServer* lcblk;
Layer(SurfaceFlinger* flinger, DisplayID display,
const sp<Client>& client, int32_t i);
@ -66,15 +69,14 @@ public:
virtual bool isSecure() const { return mSecure; }
virtual sp<Surface> createSurface() const;
virtual status_t ditch();
virtual void onRemoved();
// only for debugging
inline sp<GraphicBuffer> getBuffer(int i) const { return mBuffers[i]; }
inline sp<GraphicBuffer> getBuffer(int i) const { return mBufferManager.getBuffer(i); }
// only for debugging
inline const sp<FreezeLock>& getFreezeLock() const { return mFreezeLock; }
// only for debugging
inline PixelFormat pixelFormat() const { return mFormat; }
// only for debugging
inline int getFrontBufferIndex() const { return mFrontBufferIndex; }
virtual const char* getTypeId() const { return "Layer"; }
@ -82,10 +84,6 @@ protected:
virtual void dump(String8& result, char* scratch, size_t size) const;
private:
inline sp<GraphicBuffer> getFrontBufferLocked() {
return mBuffers[mFrontBufferIndex];
}
void reloadTexture(const Region& dirty);
uint32_t getEffectiveUsage(uint32_t usage) const;
@ -115,14 +113,64 @@ private:
Region mPostedDirtyRegion;
sp<FreezeLock> mFreezeLock;
PixelFormat mFormat;
// protected by mLock
sp<GraphicBuffer> mBuffers[NUM_BUFFERS];
Texture mTextures[NUM_BUFFERS];
uint32_t mWidth;
uint32_t mHeight;
mutable Mutex mLock;
class BufferManager {
static const size_t NUM_BUFFERS = 2;
struct BufferData {
sp<GraphicBuffer> buffer;
Texture texture;
};
mutable Mutex mLock;
BufferData mBufferData[NUM_BUFFERS];
Texture mFailoverTexture;
TextureManager& mTextureManager;
ssize_t mActiveBuffer;
bool mFailover;
static status_t destroyTexture(Texture* tex, EGLDisplay dpy);
public:
BufferManager(TextureManager& tm);
size_t getBufferCount() const;
// detach/attach buffer from/to given index
sp<GraphicBuffer> detachBuffer(size_t index);
status_t attachBuffer(size_t index, const sp<GraphicBuffer>& buffer);
// ----------------------------------------------
// must be called from GL thread
// set/get active buffer index
status_t setActiveBufferIndex(size_t index);
size_t getActiveBufferIndex() const;
// return the active buffer
sp<GraphicBuffer> getActiveBuffer() const;
// return the active texture (or fail-over)
Texture getActiveTexture() const;
// frees resources associated with all buffers
status_t destroy(EGLDisplay dpy);
// load bitmap data into the active buffer
status_t loadTexture(const Region& dirty, const GGLSurface& t);
// make active buffer an EGLImage if needed
status_t initEglImage(EGLDisplay dpy,
const sp<GraphicBuffer>& buffer);
// ----------------------------------------------
// only for debugging
sp<GraphicBuffer> getBuffer(size_t index) const;
};
TextureManager mTextureManager;
BufferManager mBufferManager;
mutable Mutex mLock;
uint32_t mWidth;
uint32_t mHeight;
};
// ---------------------------------------------------------------------------

View File

@ -32,6 +32,7 @@
#include "LayerBase.h"
#include "SurfaceFlinger.h"
#include "DisplayHardware/DisplayHardware.h"
#include "TextureManager.h"
namespace android {
@ -340,18 +341,6 @@ void LayerBase::draw(const Region& inClip) const
*/
}
GLuint LayerBase::createTexture() const
{
GLuint textureName = -1;
glGenTextures(1, &textureName);
glBindTexture(GL_TEXTURE_2D, textureName);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
return textureName;
}
void LayerBase::clearWithOpenGL(const Region& clip, GLclampx red,
GLclampx green, GLclampx blue,
GLclampx alpha) const
@ -492,187 +481,6 @@ void LayerBase::validateTexture(GLint textureName) const
}
}
bool LayerBase::isSupportedYuvFormat(int format) const
{
switch (format) {
case HAL_PIXEL_FORMAT_YCbCr_422_SP:
case HAL_PIXEL_FORMAT_YCbCr_420_SP:
case HAL_PIXEL_FORMAT_YCbCr_422_P:
case HAL_PIXEL_FORMAT_YCbCr_420_P:
case HAL_PIXEL_FORMAT_YCbCr_422_I:
case HAL_PIXEL_FORMAT_YCbCr_420_I:
case HAL_PIXEL_FORMAT_YCrCb_420_SP:
return true;
}
return false;
}
void LayerBase::loadTexture(Texture* texture,
const Region& dirty, const GGLSurface& t) const
{
if (texture->name == -1U) {
// uh?
return;
}
glBindTexture(GL_TEXTURE_2D, texture->name);
/*
* In OpenGL ES we can't specify a stride with glTexImage2D (however,
* GL_UNPACK_ALIGNMENT is a limited form of stride).
* So if the stride here isn't representable with GL_UNPACK_ALIGNMENT, we
* need to do something reasonable (here creating a bigger texture).
*
* extra pixels = (((stride - width) * pixelsize) / GL_UNPACK_ALIGNMENT);
*
* This situation doesn't happen often, but some h/w have a limitation
* for their framebuffer (eg: must be multiple of 8 pixels), and
* we need to take that into account when using these buffers as
* textures.
*
* This should never be a problem with POT textures
*/
int unpack = __builtin_ctz(t.stride * bytesPerPixel(t.format));
unpack = 1 << ((unpack > 3) ? 3 : unpack);
glPixelStorei(GL_UNPACK_ALIGNMENT, unpack);
/*
* round to POT if needed
*/
if (!(mFlags & DisplayHardware::NPOT_EXTENSION)) {
texture->NPOTAdjust = true;
}
if (texture->NPOTAdjust) {
// find the smallest power-of-two that will accommodate our surface
texture->potWidth = 1 << (31 - clz(t.width));
texture->potHeight = 1 << (31 - clz(t.height));
if (texture->potWidth < t.width) texture->potWidth <<= 1;
if (texture->potHeight < t.height) texture->potHeight <<= 1;
texture->wScale = float(t.width) / texture->potWidth;
texture->hScale = float(t.height) / texture->potHeight;
} else {
texture->potWidth = t.width;
texture->potHeight = t.height;
}
Rect bounds(dirty.bounds());
GLvoid* data = 0;
if (texture->width != t.width || texture->height != t.height) {
texture->width = t.width;
texture->height = t.height;
// texture size changed, we need to create a new one
bounds.set(Rect(t.width, t.height));
if (t.width == texture->potWidth &&
t.height == texture->potHeight) {
// we can do it one pass
data = t.data;
}
if (t.format == HAL_PIXEL_FORMAT_RGB_565) {
glTexImage2D(GL_TEXTURE_2D, 0,
GL_RGB, texture->potWidth, texture->potHeight, 0,
GL_RGB, GL_UNSIGNED_SHORT_5_6_5, data);
} else if (t.format == HAL_PIXEL_FORMAT_RGBA_4444) {
glTexImage2D(GL_TEXTURE_2D, 0,
GL_RGBA, texture->potWidth, texture->potHeight, 0,
GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, data);
} else if (t.format == HAL_PIXEL_FORMAT_RGBA_8888 ||
t.format == HAL_PIXEL_FORMAT_RGBX_8888) {
glTexImage2D(GL_TEXTURE_2D, 0,
GL_RGBA, texture->potWidth, texture->potHeight, 0,
GL_RGBA, GL_UNSIGNED_BYTE, data);
} else if (isSupportedYuvFormat(t.format)) {
// just show the Y plane of YUV buffers
glTexImage2D(GL_TEXTURE_2D, 0,
GL_LUMINANCE, texture->potWidth, texture->potHeight, 0,
GL_LUMINANCE, GL_UNSIGNED_BYTE, data);
} else {
// oops, we don't handle this format!
LOGE("layer %p, texture=%d, using format %d, which is not "
"supported by the GL", this, texture->name, t.format);
}
}
if (!data) {
if (t.format == HAL_PIXEL_FORMAT_RGB_565) {
glTexSubImage2D(GL_TEXTURE_2D, 0,
0, bounds.top, t.width, bounds.height(),
GL_RGB, GL_UNSIGNED_SHORT_5_6_5,
t.data + bounds.top*t.stride*2);
} else if (t.format == HAL_PIXEL_FORMAT_RGBA_4444) {
glTexSubImage2D(GL_TEXTURE_2D, 0,
0, bounds.top, t.width, bounds.height(),
GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4,
t.data + bounds.top*t.stride*2);
} else if (t.format == HAL_PIXEL_FORMAT_RGBA_8888 ||
t.format == HAL_PIXEL_FORMAT_RGBX_8888) {
glTexSubImage2D(GL_TEXTURE_2D, 0,
0, bounds.top, t.width, bounds.height(),
GL_RGBA, GL_UNSIGNED_BYTE,
t.data + bounds.top*t.stride*4);
} else if (isSupportedYuvFormat(t.format)) {
// just show the Y plane of YUV buffers
glTexSubImage2D(GL_TEXTURE_2D, 0,
0, bounds.top, t.width, bounds.height(),
GL_LUMINANCE, GL_UNSIGNED_BYTE,
t.data + bounds.top*t.stride);
}
}
}
status_t LayerBase::initializeEglImage(
const sp<GraphicBuffer>& buffer, Texture* texture)
{
status_t err = NO_ERROR;
// we need to recreate the texture
EGLDisplay dpy(mFlinger->graphicPlane(0).getEGLDisplay());
// free the previous image
if (texture->image != EGL_NO_IMAGE_KHR) {
eglDestroyImageKHR(dpy, texture->image);
texture->image = EGL_NO_IMAGE_KHR;
}
// construct an EGL_NATIVE_BUFFER_ANDROID
android_native_buffer_t* clientBuf = buffer->getNativeBuffer();
// create the new EGLImageKHR
const EGLint attrs[] = {
EGL_IMAGE_PRESERVED_KHR, EGL_TRUE,
EGL_NONE, EGL_NONE
};
texture->image = eglCreateImageKHR(
dpy, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID,
(EGLClientBuffer)clientBuf, attrs);
if (texture->image != EGL_NO_IMAGE_KHR) {
glBindTexture(GL_TEXTURE_2D, texture->name);
glEGLImageTargetTexture2DOES(GL_TEXTURE_2D,
(GLeglImageOES)texture->image);
GLint error = glGetError();
if (UNLIKELY(error != GL_NO_ERROR)) {
LOGE("layer=%p, glEGLImageTargetTexture2DOES(%p) "
"failed err=0x%04x",
this, texture->image, error);
err = INVALID_OPERATION;
} else {
// Everything went okay!
texture->NPOTAdjust = false;
texture->dirty = false;
texture->width = clientBuf->width;
texture->height = clientBuf->height;
}
} else {
LOGE("layer=%p, eglCreateImageKHR() failed. err=0x%4x",
this, eglGetError());
err = INVALID_OPERATION;
}
return err;
}
void LayerBase::dump(String8& result, char* buffer, size_t SIZE) const
{
const Layer::State& s(drawingState());
@ -696,12 +504,9 @@ int32_t LayerBaseClient::sIdentity = 0;
LayerBaseClient::LayerBaseClient(SurfaceFlinger* flinger, DisplayID display,
const sp<Client>& client, int32_t i)
: LayerBase(flinger, display), lcblk(NULL), client(client), mIndex(i),
: LayerBase(flinger, display), client(client), mIndex(i),
mIdentity(uint32_t(android_atomic_inc(&sIdentity)))
{
lcblk = new SharedBufferServer(
client->ctrlblk, i, NUM_BUFFERS,
mIdentity);
}
void LayerBaseClient::onFirstRef()
@ -718,7 +523,6 @@ LayerBaseClient::~LayerBaseClient()
if (client != 0) {
client->free(mIndex);
}
delete lcblk;
}
ssize_t LayerBaseClient::serverIndex() const
@ -748,14 +552,6 @@ sp<LayerBaseClient::Surface> LayerBaseClient::createSurface() const
const_cast<LayerBaseClient *>(this));
}
// called with SurfaceFlinger::mStateLock as soon as the layer is entered
// in the purgatory list
void LayerBaseClient::onRemoved()
{
// wake up the condition
lcblk->setStatus(NO_INIT);
}
void LayerBaseClient::dump(String8& result, char* buffer, size_t SIZE) const
{
LayerBase::dump(result, buffer, SIZE);

View File

@ -46,6 +46,7 @@ class Client;
class GraphicBuffer;
class GraphicPlane;
class SurfaceFlinger;
class Texture;
// ---------------------------------------------------------------------------
@ -221,35 +222,10 @@ protected:
const GraphicPlane& graphicPlane(int dpy) const;
GraphicPlane& graphicPlane(int dpy);
GLuint createTexture() const;
struct Texture {
Texture() : name(-1U), width(0), height(0),
image(EGL_NO_IMAGE_KHR), transform(0),
NPOTAdjust(false), dirty(true) { }
GLuint name;
GLuint width;
GLuint height;
GLuint potWidth;
GLuint potHeight;
GLfloat wScale;
GLfloat hScale;
EGLImageKHR image;
uint32_t transform;
bool NPOTAdjust;
bool dirty;
};
void clearWithOpenGL(const Region& clip, GLclampx r, GLclampx g,
GLclampx b, GLclampx alpha) const;
void clearWithOpenGL(const Region& clip) const;
void drawWithOpenGL(const Region& clip, const Texture& texture) const;
void loadTexture(Texture* texture,
const Region& dirty, const GGLSurface& t) const;
status_t initializeEglImage(
const sp<GraphicBuffer>& buffer, Texture* texture);
bool isSupportedYuvFormat(int format) const;
sp<SurfaceFlinger> mFlinger;
uint32_t mFlags;
@ -294,10 +270,6 @@ class LayerBaseClient : public LayerBase
public:
class Surface;
// lcblk is (almost) only accessed from the main SF thread, in the places
// where it's not, a reference to Client must be held
SharedBufferServer* lcblk;
LayerBaseClient(SurfaceFlinger* flinger, DisplayID display,
const sp<Client>& client, int32_t i);
virtual ~LayerBaseClient();
@ -311,7 +283,6 @@ public:
sp<Surface> getSurface();
virtual sp<Surface> createSurface() const;
virtual ssize_t serverIndex() const;
virtual void onRemoved();
virtual const char* getTypeId() const { return "LayerBaseClient"; }
class Surface : public BnSurface

View File

@ -328,7 +328,7 @@ bool LayerBuffer::Source::transformed() const {
LayerBuffer::BufferSource::BufferSource(LayerBuffer& layer,
const ISurface::BufferHeap& buffers)
: Source(layer), mStatus(NO_ERROR), mBufferSize(0),
mUseEGLImageDirectly(true)
mTextureManager(layer.mFlags)
{
if (buffers.heap == NULL) {
// this is allowed, but in this case, it is illegal to receive
@ -460,35 +460,10 @@ void LayerBuffer::BufferSource::onDraw(const Region& clip) const
NativeBuffer src(ourBuffer->getBuffer());
const Rect transformedBounds(mLayer.getTransformedBounds());
if (UNLIKELY(mTexture.name == -1LU)) {
mTexture.name = mLayer.createTexture();
}
#if defined(EGL_ANDROID_image_native_buffer)
if (mLayer.mFlags & DisplayHardware::DIRECT_TEXTURE) {
err = INVALID_OPERATION;
if (ourBuffer->supportsCopybit()) {
// there are constraints on buffers used by the GPU and these may not
// be honored here. We need to change the API so the buffers
// are allocated with gralloc. For now disable this code-path
#if 0
// First, try to use the buffer as an EGLImage directly
if (mUseEGLImageDirectly) {
// NOTE: Assume the buffer is allocated with the proper USAGE flags
sp<GraphicBuffer> buffer = new GraphicBuffer(
src.img.w, src.img.h, src.img.format,
GraphicBuffer::USAGE_HW_TEXTURE,
src.img.w, src.img.handle, false);
err = mLayer.initializeEglImage(buffer, &mTexture);
if (err != NO_ERROR) {
mUseEGLImageDirectly = false;
}
}
#endif
copybit_device_t* copybit = mLayer.mBlitEngine;
if (copybit && err != NO_ERROR) {
// create our EGLImageKHR the first time
@ -525,7 +500,7 @@ void LayerBuffer::BufferSource::onDraw(const Region& clip) const
t.format = src.img.format;
t.data = (GGLubyte*)src.img.base;
const Region dirty(Rect(t.width, t.height));
mLayer.loadTexture(&mTexture, dirty, t);
mTextureManager.loadTexture(&mTexture, dirty, t);
}
mTexture.transform = mBufferHeap.transform;
@ -591,7 +566,8 @@ status_t LayerBuffer::BufferSource::initTempBuffer() const
dst.crop.r = w;
dst.crop.b = h;
err = mLayer.initializeEglImage(buffer, &mTexture);
EGLDisplay dpy(mLayer.mFlinger->graphicPlane(0).getEGLDisplay());
err = mTextureManager.initEglImage(&mTexture, dpy, buffer);
}
return err;
@ -607,7 +583,6 @@ void LayerBuffer::BufferSource::clearTempBufferImage() const
glDeleteTextures(1, &mTexture.name);
Texture defaultTexture;
mTexture = defaultTexture;
mTexture.name = mLayer.createTexture();
}
// ---------------------------------------------------------------------------

View File

@ -21,6 +21,7 @@
#include <sys/types.h>
#include "LayerBase.h"
#include "TextureManager.h"
struct copybit_device_t;
@ -139,9 +140,9 @@ private:
status_t mStatus;
ISurface::BufferHeap mBufferHeap;
size_t mBufferSize;
mutable LayerBase::Texture mTexture;
mutable Texture mTexture;
mutable NativeBuffer mTempBuffer;
mutable bool mUseEGLImageDirectly;
mutable TextureManager mTextureManager;
};
class OverlaySource : public Source {

View File

@ -0,0 +1,242 @@
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdlib.h>
#include <stdint.h>
#include <sys/types.h>
#include <utils/Errors.h>
#include <utils/Log.h>
#include <ui/GraphicBuffer.h>
#include <GLES/gl.h>
#include <GLES/glext.h>
#include <hardware/hardware.h>
#include "clz.h"
#include "DisplayHardware/DisplayHardware.h"
#include "TextureManager.h"
namespace android {
// ---------------------------------------------------------------------------
TextureManager::TextureManager(uint32_t flags)
: mFlags(flags)
{
}
GLuint TextureManager::createTexture()
{
GLuint textureName = -1;
glGenTextures(1, &textureName);
glBindTexture(GL_TEXTURE_2D, textureName);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
return textureName;
}
bool TextureManager::isSupportedYuvFormat(int format)
{
switch (format) {
case HAL_PIXEL_FORMAT_YCbCr_422_SP:
case HAL_PIXEL_FORMAT_YCbCr_420_SP:
case HAL_PIXEL_FORMAT_YCbCr_422_P:
case HAL_PIXEL_FORMAT_YCbCr_420_P:
case HAL_PIXEL_FORMAT_YCbCr_422_I:
case HAL_PIXEL_FORMAT_YCbCr_420_I:
case HAL_PIXEL_FORMAT_YCrCb_420_SP:
return true;
}
return false;
}
status_t TextureManager::initEglImage(Texture* texture,
EGLDisplay dpy, const sp<GraphicBuffer>& buffer)
{
status_t err = NO_ERROR;
if (!texture->dirty) return err;
// free the previous image
if (texture->image != EGL_NO_IMAGE_KHR) {
eglDestroyImageKHR(dpy, texture->image);
texture->image = EGL_NO_IMAGE_KHR;
}
// construct an EGL_NATIVE_BUFFER_ANDROID
android_native_buffer_t* clientBuf = buffer->getNativeBuffer();
// create the new EGLImageKHR
const EGLint attrs[] = {
EGL_IMAGE_PRESERVED_KHR, EGL_TRUE,
EGL_NONE, EGL_NONE
};
texture->image = eglCreateImageKHR(
dpy, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID,
(EGLClientBuffer)clientBuf, attrs);
if (texture->image != EGL_NO_IMAGE_KHR) {
if (texture->name == -1UL) {
texture->name = createTexture();
texture->width = 0;
texture->height = 0;
}
glBindTexture(GL_TEXTURE_2D, texture->name);
glEGLImageTargetTexture2DOES(GL_TEXTURE_2D,
(GLeglImageOES)texture->image);
GLint error = glGetError();
if (error != GL_NO_ERROR) {
LOGE("glEGLImageTargetTexture2DOES(%p) failed err=0x%04x",
texture->image, error);
err = INVALID_OPERATION;
} else {
// Everything went okay!
texture->NPOTAdjust = false;
texture->dirty = false;
texture->width = clientBuf->width;
texture->height = clientBuf->height;
}
} else {
LOGE("eglCreateImageKHR() failed. err=0x%4x", eglGetError());
err = INVALID_OPERATION;
}
return err;
}
status_t TextureManager::loadTexture(Texture* texture,
const Region& dirty, const GGLSurface& t)
{
if (texture->name == -1UL) {
texture->name = createTexture();
texture->width = 0;
texture->height = 0;
}
glBindTexture(GL_TEXTURE_2D, texture->name);
/*
* In OpenGL ES we can't specify a stride with glTexImage2D (however,
* GL_UNPACK_ALIGNMENT is a limited form of stride).
* So if the stride here isn't representable with GL_UNPACK_ALIGNMENT, we
* need to do something reasonable (here creating a bigger texture).
*
* extra pixels = (((stride - width) * pixelsize) / GL_UNPACK_ALIGNMENT);
*
* This situation doesn't happen often, but some h/w have a limitation
* for their framebuffer (eg: must be multiple of 8 pixels), and
* we need to take that into account when using these buffers as
* textures.
*
* This should never be a problem with POT textures
*/
int unpack = __builtin_ctz(t.stride * bytesPerPixel(t.format));
unpack = 1 << ((unpack > 3) ? 3 : unpack);
glPixelStorei(GL_UNPACK_ALIGNMENT, unpack);
/*
* round to POT if needed
*/
if (!(mFlags & DisplayHardware::NPOT_EXTENSION)) {
texture->NPOTAdjust = true;
}
if (texture->NPOTAdjust) {
// find the smallest power-of-two that will accommodate our surface
texture->potWidth = 1 << (31 - clz(t.width));
texture->potHeight = 1 << (31 - clz(t.height));
if (texture->potWidth < t.width) texture->potWidth <<= 1;
if (texture->potHeight < t.height) texture->potHeight <<= 1;
texture->wScale = float(t.width) / texture->potWidth;
texture->hScale = float(t.height) / texture->potHeight;
} else {
texture->potWidth = t.width;
texture->potHeight = t.height;
}
Rect bounds(dirty.bounds());
GLvoid* data = 0;
if (texture->width != t.width || texture->height != t.height) {
texture->width = t.width;
texture->height = t.height;
// texture size changed, we need to create a new one
bounds.set(Rect(t.width, t.height));
if (t.width == texture->potWidth &&
t.height == texture->potHeight) {
// we can do it one pass
data = t.data;
}
if (t.format == HAL_PIXEL_FORMAT_RGB_565) {
glTexImage2D(GL_TEXTURE_2D, 0,
GL_RGB, texture->potWidth, texture->potHeight, 0,
GL_RGB, GL_UNSIGNED_SHORT_5_6_5, data);
} else if (t.format == HAL_PIXEL_FORMAT_RGBA_4444) {
glTexImage2D(GL_TEXTURE_2D, 0,
GL_RGBA, texture->potWidth, texture->potHeight, 0,
GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, data);
} else if (t.format == HAL_PIXEL_FORMAT_RGBA_8888 ||
t.format == HAL_PIXEL_FORMAT_RGBX_8888) {
glTexImage2D(GL_TEXTURE_2D, 0,
GL_RGBA, texture->potWidth, texture->potHeight, 0,
GL_RGBA, GL_UNSIGNED_BYTE, data);
} else if (isSupportedYuvFormat(t.format)) {
// just show the Y plane of YUV buffers
glTexImage2D(GL_TEXTURE_2D, 0,
GL_LUMINANCE, texture->potWidth, texture->potHeight, 0,
GL_LUMINANCE, GL_UNSIGNED_BYTE, data);
} else {
// oops, we don't handle this format!
LOGE("texture=%d, using format %d, which is not "
"supported by the GL", texture->name, t.format);
}
}
if (!data) {
if (t.format == HAL_PIXEL_FORMAT_RGB_565) {
glTexSubImage2D(GL_TEXTURE_2D, 0,
0, bounds.top, t.width, bounds.height(),
GL_RGB, GL_UNSIGNED_SHORT_5_6_5,
t.data + bounds.top*t.stride*2);
} else if (t.format == HAL_PIXEL_FORMAT_RGBA_4444) {
glTexSubImage2D(GL_TEXTURE_2D, 0,
0, bounds.top, t.width, bounds.height(),
GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4,
t.data + bounds.top*t.stride*2);
} else if (t.format == HAL_PIXEL_FORMAT_RGBA_8888 ||
t.format == HAL_PIXEL_FORMAT_RGBX_8888) {
glTexSubImage2D(GL_TEXTURE_2D, 0,
0, bounds.top, t.width, bounds.height(),
GL_RGBA, GL_UNSIGNED_BYTE,
t.data + bounds.top*t.stride*4);
} else if (isSupportedYuvFormat(t.format)) {
// just show the Y plane of YUV buffers
glTexSubImage2D(GL_TEXTURE_2D, 0,
0, bounds.top, t.width, bounds.height(),
GL_LUMINANCE, GL_UNSIGNED_BYTE,
t.data + bounds.top*t.stride);
}
}
return NO_ERROR;
}
// ---------------------------------------------------------------------------
}; // namespace android

View File

@ -0,0 +1,79 @@
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef ANDROID_TEXTURE_MANAGER_H
#define ANDROID_TEXTURE_MANAGER_H
#include <stdint.h>
#include <sys/types.h>
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <GLES/gl.h>
#include <ui/Region.h>
#include <pixelflinger/pixelflinger.h>
namespace android {
// ---------------------------------------------------------------------------
class GraphicBuffer;
// ---------------------------------------------------------------------------
struct Texture {
Texture() : name(-1U), width(0), height(0),
image(EGL_NO_IMAGE_KHR), transform(0),
NPOTAdjust(false), dirty(true) { }
GLuint name;
GLuint width;
GLuint height;
GLuint potWidth;
GLuint potHeight;
GLfloat wScale;
GLfloat hScale;
EGLImageKHR image;
uint32_t transform;
bool NPOTAdjust;
bool dirty;
};
// ---------------------------------------------------------------------------
class TextureManager {
uint32_t mFlags;
GLuint createTexture();
static bool isSupportedYuvFormat(int format);
public:
TextureManager(uint32_t flags);
// load bitmap data into the active buffer
status_t loadTexture(Texture* texture,
const Region& dirty, const GGLSurface& t);
// make active buffer an EGLImage if needed
status_t initEglImage(Texture* texture,
EGLDisplay dpy, const sp<GraphicBuffer>& buffer);
};
// ---------------------------------------------------------------------------
}; // namespace android
#endif // ANDROID_TEXTURE_MANAGER_H

View File

@ -513,6 +513,7 @@ int32_t SharedBufferServer::getQueuedCount() const
status_t SharedBufferServer::assertReallocate(int buf)
{
// TODO: need to validate "buf"
ReallocateCondition condition(this, buf);
status_t err = waitForCondition(condition);
return err;