am 6a70cb8a
: Merge "Refactor some code in surfaceflinger in preparation of upcoming changes" into kraken
This commit is contained in:
@ -13,6 +13,7 @@ LOCAL_SRC_FILES:= \
|
||||
LayerDim.cpp \
|
||||
MessageQueue.cpp \
|
||||
SurfaceFlinger.cpp \
|
||||
TextureManager.cpp \
|
||||
Tokenizer.cpp \
|
||||
Transform.cpp
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
@ -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 {
|
||||
|
242
libs/surfaceflinger/TextureManager.cpp
Normal file
242
libs/surfaceflinger/TextureManager.cpp
Normal 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
|
79
libs/surfaceflinger/TextureManager.h
Normal file
79
libs/surfaceflinger/TextureManager.h
Normal 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
|
@ -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;
|
||||
|
Reference in New Issue
Block a user