Added support for the GL_TEXTURE_EXTERNAL target

This will allow us to support YUV surfaces.

Change-Id: I2d4da75f1006a5285bdc552695d4caeecccf2183
This commit is contained in:
Mathias Agopian 2010-06-14 21:20:00 -07:00
parent f1be483e8e
commit 0a91775c4d
11 changed files with 216 additions and 107 deletions

View File

@ -232,7 +232,7 @@ void Layer::onDraw(const Region& clip) const
// if not everything below us is covered, we plug the holes!
Region holes(clip.subtract(under));
if (!holes.isEmpty()) {
clearWithOpenGL(holes);
clearWithOpenGL(holes, 0, 0, 0, 1);
}
return;
}

View File

@ -324,16 +324,6 @@ void LayerBase::draw(const Region& inClip) const
glEnable(GL_SCISSOR_TEST);
onDraw(clip);
/*
glDisable(GL_TEXTURE_2D);
glDisable(GL_DITHER);
glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
glColor4x(0, 0x8000, 0, 0x10000);
drawRegion(transparentRegionScreen);
glDisable(GL_BLEND);
*/
}
void LayerBase::clearWithOpenGL(const Region& clip, GLclampf red,
@ -343,7 +333,9 @@ void LayerBase::clearWithOpenGL(const Region& clip, GLclampf red,
const DisplayHardware& hw(graphicPlane(0).displayHardware());
const uint32_t fbHeight = hw.getHeight();
glColor4f(red,green,blue,alpha);
glDisable(GL_TEXTURE_2D);
TextureManager::deactivateTextures();
glDisable(GL_BLEND);
glDisable(GL_DITHER);
@ -371,11 +363,9 @@ void LayerBase::drawWithOpenGL(const Region& clip, const Texture& texture) const
const State& s(drawingState());
// bind our texture
validateTexture(texture.name);
TextureManager::activateTexture(texture, needsFiltering());
uint32_t width = texture.width;
uint32_t height = texture.height;
glEnable(GL_TEXTURE_2D);
GLenum src = mPremultipliedAlpha ? GL_ONE : GL_SRC_ALPHA;
if (UNLIKELY(s.alpha < 0xFF)) {
@ -431,6 +421,12 @@ void LayerBase::drawWithOpenGL(const Region& clip, const Texture& texture) const
glScalef(texture.wScale, texture.hScale, 1.0f);
}
if (needsDithering()) {
glEnable(GL_DITHER);
} else {
glDisable(GL_DITHER);
}
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glVertexPointer(2, GL_FLOAT, 0, mVertices);
glTexCoordPointer(2, GL_FLOAT, 0, texCoords);
@ -444,26 +440,6 @@ void LayerBase::drawWithOpenGL(const Region& clip, const Texture& texture) const
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}
void LayerBase::validateTexture(GLint textureName) const
{
glBindTexture(GL_TEXTURE_2D, textureName);
// TODO: reload the texture if needed
// this is currently done in loadTexture() below
if (needsFiltering()) {
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
} else {
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
}
if (needsDithering()) {
glEnable(GL_DITHER);
} else {
glDisable(GL_DITHER);
}
}
void LayerBase::dump(String8& result, char* buffer, size_t SIZE) const
{
const Layer::State& s(drawingState());

View File

@ -260,7 +260,6 @@ protected:
private:
LayerBase(const LayerBase& rhs);
void validateTexture(GLint textureName) const;
};

View File

@ -146,6 +146,9 @@ void LayerBlur::onDraw(const Region& clip) const
Region::const_iterator it = clip.begin();
Region::const_iterator const end = clip.end();
if (it != end) {
#if defined(GL_OES_texture_external)
glDisable(GL_TEXTURE_EXTERNAL_OES);
#endif
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, mTextureName);

View File

@ -119,6 +119,9 @@ void LayerDim::onDraw(const Region& clip) const
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
glColor4x(0, 0, 0, alpha);
#if defined(GL_OES_texture_external)
glDisable(GL_TEXTURE_EXTERNAL_OES);
#endif
#if defined(DIM_WITH_TEXTURE) && defined(EGL_ANDROID_image_native_buffer)
if (sUseTexture) {
glBindTexture(GL_TEXTURE_2D, sTexId);

View File

@ -332,13 +332,6 @@ status_t SurfaceFlinger::readyToRun()
dcblk->density = hw.getDensity();
// Initialize OpenGL|ES
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, 0);
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);
glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
glPixelStorei(GL_PACK_ALIGNMENT, 4);
glEnableClientState(GL_VERTEX_ARRAY);
@ -918,17 +911,18 @@ void SurfaceFlinger::unlockClients()
void SurfaceFlinger::debugFlashRegions()
{
const DisplayHardware& hw(graphicPlane(0).displayHardware());
const uint32_t flags = hw.getFlags();
const DisplayHardware& hw(graphicPlane(0).displayHardware());
const uint32_t flags = hw.getFlags();
if (!((flags & DisplayHardware::SWAP_RECTANGLE) ||
(flags & DisplayHardware::BUFFER_PRESERVED))) {
const Region repaint((flags & DisplayHardware::PARTIAL_UPDATES) ?
mDirtyRegion.bounds() : hw.bounds());
composeSurfaces(repaint);
}
TextureManager::deactivateTextures();
if (!((flags & DisplayHardware::SWAP_RECTANGLE) ||
(flags & DisplayHardware::BUFFER_PRESERVED))) {
const Region repaint((flags & DisplayHardware::PARTIAL_UPDATES) ?
mDirtyRegion.bounds() : hw.bounds());
composeSurfaces(repaint);
}
glDisable(GL_TEXTURE_2D);
glDisable(GL_BLEND);
glDisable(GL_DITHER);
glDisable(GL_SCISSOR_TEST);
@ -936,9 +930,9 @@ void SurfaceFlinger::debugFlashRegions()
static int toggle = 0;
toggle = 1 - toggle;
if (toggle) {
glColor4x(0x10000, 0, 0x10000, 0x10000);
glColor4f(1, 0, 1, 1);
} else {
glColor4x(0x10000, 0x10000, 0, 0x10000);
glColor4f(1, 1, 0, 1);
}
Region::const_iterator it = mDirtyRegion.begin();
@ -954,7 +948,7 @@ void SurfaceFlinger::debugFlashRegions()
glVertexPointer(2, GL_FLOAT, 0, vertices);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
}
if (mInvalidRegion.isEmpty()) {
mDirtyRegion.dump("mDirtyRegion");
mInvalidRegion.dump("mInvalidRegion");
@ -962,7 +956,7 @@ void SurfaceFlinger::debugFlashRegions()
hw.flip(mInvalidRegion);
if (mDebugRegion > 1)
usleep(mDebugRegion * 1000);
usleep(mDebugRegion * 1000);
glEnable(GL_SCISSOR_TEST);
//mDirtyRegion.dump("mDirtyRegion");
@ -982,7 +976,7 @@ void SurfaceFlinger::drawWormhole() const
glDisable(GL_DITHER);
if (LIKELY(!mDebugBackground)) {
glClearColorx(0,0,0,0);
glClearColor(0,0,0,0);
Region::const_iterator it = region.begin();
Region::const_iterator const end = region.end();
while (it != end) {
@ -998,6 +992,9 @@ void SurfaceFlinger::drawWormhole() const
glVertexPointer(2, GL_SHORT, 0, vertices);
glTexCoordPointer(2, GL_SHORT, 0, tcoords);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
#if defined(GL_OES_texture_external)
glDisable(GL_TEXTURE_EXTERNAL_OES);
#endif
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, mWormholeTexName);
glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);

View File

@ -41,43 +41,112 @@ TextureManager::TextureManager(uint32_t flags)
{
}
GLuint TextureManager::createTexture()
GLenum TextureManager::getTextureTarget(const Image* image) {
#if defined(GL_OES_texture_external)
switch (image->target) {
case Texture::TEXTURE_EXTERNAL:
return GL_TEXTURE_EXTERNAL_OES;
}
#endif
return GL_TEXTURE_2D;
}
status_t TextureManager::initTexture(Texture* texture)
{
if (texture->name != -1UL)
return INVALID_OPERATION;
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;
texture->name = textureName;
texture->width = 0;
texture->height = 0;
const GLenum target = GL_TEXTURE_2D;
glBindTexture(target, textureName);
glTexParameterx(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterx(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameterx(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameterx(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
return NO_ERROR;
}
status_t TextureManager::initTexture(Image* pImage, int32_t format)
{
if (pImage->name != -1UL)
return INVALID_OPERATION;
GLuint textureName = -1;
glGenTextures(1, &textureName);
pImage->name = textureName;
pImage->width = 0;
pImage->height = 0;
GLenum target = GL_TEXTURE_2D;
#if defined(GL_OES_texture_external)
if (format && isSupportedYuvFormat(format)) {
target = GL_TEXTURE_EXTERNAL_OES;
pImage->target = Texture::TEXTURE_EXTERNAL;
}
#endif
glBindTexture(target, textureName);
glTexParameterx(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterx(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameterx(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameterx(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
return NO_ERROR;
}
bool TextureManager::isSupportedYuvFormat(int format)
{
// TODO: how to we know which YUV formats are supported by the GPU?
// Adreno 200 supports these
// YUVY_adreno
// UYVY_adreno
// NV21_adreno
// YV12_adreno
// Adreno 205 adds
// NV12_adreno_tiled
// NV21_adreno_tiled
// for now pretend we support them all, failure will happen when
// we try to use them.
return isYuvFormat(format);
}
bool TextureManager::isYuvFormat(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;
case HAL_PIXEL_FORMAT_NV16:
case HAL_PIXEL_FORMAT_NV21:
case HAL_PIXEL_FORMAT_IYUV:
case HAL_PIXEL_FORMAT_YUV9:
case HAL_PIXEL_FORMAT_YUY2:
case HAL_PIXEL_FORMAT_UYVY:
case HAL_PIXEL_FORMAT_NV12:
case HAL_PIXEL_FORMAT_NV61:
case HAL_PIXEL_FORMAT_YV12:
case HAL_PIXEL_FORMAT_NV12_ADRENO_TILED:
case HAL_PIXEL_FORMAT_NV21_ADRENO_TILED:
return true;
}
return false;
}
status_t TextureManager::initEglImage(Image* texture,
status_t TextureManager::initEglImage(Image* pImage,
EGLDisplay dpy, const sp<GraphicBuffer>& buffer)
{
status_t err = NO_ERROR;
if (!texture->dirty) return err;
if (!pImage->dirty) return err;
// free the previous image
if (texture->image != EGL_NO_IMAGE_KHR) {
eglDestroyImageKHR(dpy, texture->image);
texture->image = EGL_NO_IMAGE_KHR;
if (pImage->image != EGL_NO_IMAGE_KHR) {
eglDestroyImageKHR(dpy, pImage->image);
pImage->image = EGL_NO_IMAGE_KHR;
}
// construct an EGL_NATIVE_BUFFER_ANDROID
@ -88,29 +157,27 @@ status_t TextureManager::initEglImage(Image* texture,
EGL_IMAGE_PRESERVED_KHR, EGL_TRUE,
EGL_NONE, EGL_NONE
};
texture->image = eglCreateImageKHR(
pImage->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;
if (pImage->image != EGL_NO_IMAGE_KHR) {
if (pImage->name == -1UL) {
initTexture(pImage, buffer->format);
}
glBindTexture(GL_TEXTURE_2D, texture->name);
glEGLImageTargetTexture2DOES(GL_TEXTURE_2D,
(GLeglImageOES)texture->image);
const GLenum target = getTextureTarget(pImage);
glBindTexture(target, pImage->name);
glEGLImageTargetTexture2DOES(target, (GLeglImageOES)pImage->image);
GLint error = glGetError();
if (error != GL_NO_ERROR) {
LOGE("glEGLImageTargetTexture2DOES(%p) failed err=0x%04x",
texture->image, error);
pImage->image, error);
err = INVALID_OPERATION;
} else {
// Everything went okay!
texture->dirty = false;
texture->width = clientBuf->width;
texture->height = clientBuf->height;
pImage->dirty = false;
pImage->width = clientBuf->width;
pImage->height = clientBuf->height;
}
} else {
LOGE("eglCreateImageKHR() failed. err=0x%4x", eglGetError());
@ -123,11 +190,14 @@ 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;
status_t err = initTexture(texture);
LOGE_IF(err, "loadTexture failed in initTexture (%s)", strerror(err));
return err;
}
if (texture->target != GL_TEXTURE_2D)
return INVALID_OPERATION;
glBindTexture(GL_TEXTURE_2D, texture->name);
/*
@ -197,7 +267,7 @@ status_t TextureManager::loadTexture(Texture* texture,
glTexImage2D(GL_TEXTURE_2D, 0,
GL_RGBA, texture->potWidth, texture->potHeight, 0,
GL_RGBA, GL_UNSIGNED_BYTE, data);
} else if (isSupportedYuvFormat(t.format)) {
} else if (isYuvFormat(t.format)) {
// just show the Y plane of YUV buffers
glTexImage2D(GL_TEXTURE_2D, 0,
GL_LUMINANCE, texture->potWidth, texture->potHeight, 0,
@ -225,7 +295,7 @@ status_t TextureManager::loadTexture(Texture* texture,
0, bounds.top, t.width, bounds.height(),
GL_RGBA, GL_UNSIGNED_BYTE,
t.data + bounds.top*t.stride*4);
} else if (isSupportedYuvFormat(t.format)) {
} else if (isYuvFormat(t.format)) {
// just show the Y plane of YUV buffers
glTexSubImage2D(GL_TEXTURE_2D, 0,
0, bounds.top, t.width, bounds.height(),
@ -236,6 +306,38 @@ status_t TextureManager::loadTexture(Texture* texture,
return NO_ERROR;
}
void TextureManager::activateTexture(const Texture& texture, bool filter)
{
const GLenum target = getTextureTarget(&texture);
glBindTexture(target, texture.name);
glEnable(target);
#if defined(GL_OES_texture_external)
if (texture.target == Texture::TEXTURE_2D) {
glDisable(GL_TEXTURE_EXTERNAL_OES);
} else {
glDisable(GL_TEXTURE_2D);
}
#endif
if (filter) {
glTexParameterx(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterx(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
} else {
glTexParameterx(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameterx(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
}
}
void TextureManager::deactivateTextures()
{
glDisable(GL_TEXTURE_2D);
#if defined(GL_OES_texture_external)
glDisable(GL_TEXTURE_EXTERNAL_OES);
#endif
}
// ---------------------------------------------------------------------------
}; // namespace android

View File

@ -37,31 +37,36 @@ class GraphicBuffer;
// ---------------------------------------------------------------------------
struct Image {
enum { TEXTURE_2D=0, TEXTURE_EXTERNAL=1 };
Image() : name(-1U), image(EGL_NO_IMAGE_KHR), width(0), height(0),
transform(0), dirty(true) { }
transform(0), dirty(1), target(TEXTURE_2D) { }
GLuint name;
EGLImageKHR image;
GLuint width;
GLuint height;
uint32_t transform;
bool dirty;
unsigned dirty : 1;
unsigned target : 1;
};
struct Texture : public Image {
Texture() : Image(), NPOTAdjust(false) { }
GLuint potWidth;
GLuint potHeight;
GLfloat wScale;
GLfloat hScale;
bool NPOTAdjust;
Texture() : Image(), NPOTAdjust(0) { }
GLuint potWidth;
GLuint potHeight;
GLfloat wScale;
GLfloat hScale;
unsigned NPOTAdjust : 1;
};
// ---------------------------------------------------------------------------
class TextureManager {
uint32_t mFlags;
GLuint createTexture();
static status_t initTexture(Image* texture, int32_t format);
static status_t initTexture(Texture* texture);
static bool isSupportedYuvFormat(int format);
static bool isYuvFormat(int format);
static GLenum getTextureTarget(const Image* pImage);
public:
TextureManager(uint32_t flags);
@ -73,6 +78,12 @@ public:
// make active buffer an EGLImage if needed
status_t initEglImage(Image* texture,
EGLDisplay dpy, const sp<GraphicBuffer>& buffer);
// activate a texture
static void activateTexture(const Texture& texture, bool filter);
// deactivate a texture
static void deactivateTextures();
};
// ---------------------------------------------------------------------------

View File

@ -70,8 +70,6 @@ status_t getPixelFormatInfo(PixelFormat format, PixelFormatInfo* info)
case HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED:
case HAL_PIXEL_FORMAT_YCrCb_420_SP_TILED:
case HAL_PIXEL_FORMAT_YCbCr_420_P:
case HAL_PIXEL_FORMAT_YCbCr_420_I:
case HAL_PIXEL_FORMAT_CbYCrY_420_I:
info->bitsPerPixel = 12;
done:
info->format = format;

View File

@ -211,6 +211,11 @@ typedef void* GLeglImageOES;
#define GL_VERTEX_ARRAY_BINDING_OES 0x85B5
#endif
/* GL_OES_texture_external */
#ifndef GL_TEXTURE_EXTERNAL_OES
#define GL_TEXTURE_EXTERNAL_OES 0x8D65
#endif
/*------------------------------------------------------------------------*
* AMD extension tokens
*------------------------------------------------------------------------*/
@ -777,6 +782,11 @@ typedef void (GL_APIENTRYP PFNGLGENVERTEXARRAYSOESPROC) (GLsizei n, GLuint *arra
typedef GLboolean (GL_APIENTRYP PFNGLISVERTEXARRAYOESPROC) (GLuint array);
#endif
/* GL_OES_texture_external */
#ifndef GL_OES_texture_external
#define GL_OES_texture_external 1
#endif
/*------------------------------------------------------------------------*
* AMD extension functions
*------------------------------------------------------------------------*/

View File

@ -146,6 +146,11 @@ typedef void* GLeglImageOES;
#define GL_INT_10_10_10_2_OES 0x8DF7
#endif
/* GL_OES_texture_external */
#ifndef GL_TEXTURE_EXTERNAL_OES
#define GL_TEXTURE_EXTERNAL_OES 0x8D65
#endif
/*------------------------------------------------------------------------*
* AMD extension tokens
*------------------------------------------------------------------------*/
@ -541,6 +546,11 @@ typedef GLboolean (GL_APIENTRYP PFNGLISVERTEXARRAYOESPROC) (GLuint array);
#define GL_OES_vertex_type_10_10_10_2 1
#endif
/* GL_OES_texture_external */
#ifndef GL_OES_texture_external
#define GL_OES_texture_external 1
#endif
/*------------------------------------------------------------------------*
* AMD extension functions
*------------------------------------------------------------------------*/