diff options
author | Mathias Agopian <mathias@google.com> | 2010-07-14 17:59:35 -0700 |
---|---|---|
committer | Mathias Agopian <mathias@google.com> | 2010-07-14 17:59:35 -0700 |
commit | 08e83bb3b7cc41f603867acbeb1168019cf535fe (patch) | |
tree | 79594e01ef6c3306b890cb944d6f15d3098075c4 /services/surfaceflinger/TextureManager.cpp | |
parent | c9a11088e503b9e3ae52a3f671b2d21f5cd54f06 (diff) | |
download | frameworks_base-08e83bb3b7cc41f603867acbeb1168019cf535fe.zip frameworks_base-08e83bb3b7cc41f603867acbeb1168019cf535fe.tar.gz frameworks_base-08e83bb3b7cc41f603867acbeb1168019cf535fe.tar.bz2 |
move native services under services/
moved surfaceflinger, audioflinger, cameraservice
all native services should now reside in this location.
Change-Id: Iee42b83dd2a94c3bf5107ab0895fe2dfcd5337a8
Diffstat (limited to 'services/surfaceflinger/TextureManager.cpp')
-rw-r--r-- | services/surfaceflinger/TextureManager.cpp | 342 |
1 files changed, 342 insertions, 0 deletions
diff --git a/services/surfaceflinger/TextureManager.cpp b/services/surfaceflinger/TextureManager.cpp new file mode 100644 index 0000000..3b326df --- /dev/null +++ b/services/surfaceflinger/TextureManager.cpp @@ -0,0 +1,342 @@ +/* + * 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 "GLExtensions.h" +#include "TextureManager.h" + +namespace android { + +// --------------------------------------------------------------------------- + +TextureManager::TextureManager() + : mGLExtensions(GLExtensions::getInstance()) +{ +} + +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); + 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 (GLExtensions::getInstance().haveTextureExternal()) { + if (format && isYuvFormat(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) +{ + switch (format) { + case HAL_PIXEL_FORMAT_YV12: + return true; + } + return false; +} + +bool TextureManager::isYuvFormat(int format) +{ + switch (format) { + // supported YUV formats + case HAL_PIXEL_FORMAT_YV12: + // Legacy/deprecated YUV formats + case HAL_PIXEL_FORMAT_YCbCr_422_SP: + case HAL_PIXEL_FORMAT_YCrCb_420_SP: + case HAL_PIXEL_FORMAT_YCbCr_422_I: + case HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED: + return true; + } + + // Any OEM format needs to be considered + if (format>=0x100 && format<=0x1FF) + return true; + + return false; +} + +status_t TextureManager::initEglImage(Image* pImage, + EGLDisplay dpy, const sp<GraphicBuffer>& buffer) +{ + status_t err = NO_ERROR; + if (!pImage->dirty) return err; + + // free the previous image + if (pImage->image != EGL_NO_IMAGE_KHR) { + eglDestroyImageKHR(dpy, pImage->image); + pImage->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 + }; + pImage->image = eglCreateImageKHR( + dpy, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, + (EGLClientBuffer)clientBuf, attrs); + + if (pImage->image != EGL_NO_IMAGE_KHR) { + if (pImage->name == -1UL) { + initTexture(pImage, buffer->format); + } + 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", + pImage->image, error); + err = INVALID_OPERATION; + } else { + // Everything went okay! + pImage->dirty = false; + pImage->width = clientBuf->width; + pImage->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) { + 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); + + /* + * 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 (!mGLExtensions.haveNpot()) { + 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; +} + +void TextureManager::activateTexture(const Texture& texture, bool filter) +{ + const GLenum target = getTextureTarget(&texture); + if (target == GL_TEXTURE_2D) { + glBindTexture(GL_TEXTURE_2D, texture.name); + glEnable(GL_TEXTURE_2D); +#if defined(GL_OES_texture_external) + if (GLExtensions::getInstance().haveTextureExternal()) { + glDisable(GL_TEXTURE_EXTERNAL_OES); + } + } else { + glBindTexture(GL_TEXTURE_EXTERNAL_OES, texture.name); + glEnable(GL_TEXTURE_EXTERNAL_OES); + 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) + if (GLExtensions::getInstance().haveTextureExternal()) { + glDisable(GL_TEXTURE_EXTERNAL_OES); + } +#endif +} + +// --------------------------------------------------------------------------- + +}; // namespace android |