Home | History | Annotate | Download | only in libagl
      1 /*
      2  ** Copyright 2006, The Android Open Source Project
      3  **
      4  ** Licensed under the Apache License, Version 2.0 (the "License");
      5  ** you may not use this file except in compliance with the License.
      6  ** You may obtain a copy of the License at
      7  **
      8  **     http://www.apache.org/licenses/LICENSE-2.0
      9  **
     10  ** Unless required by applicable law or agreed to in writing, software
     11  ** distributed under the License is distributed on an "AS IS" BASIS,
     12  ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  ** See the License for the specific language governing permissions and
     14  ** limitations under the License.
     15  */
     16 
     17 #include <stdio.h>
     18 #include <stdlib.h>
     19 #include "context.h"
     20 #include "TextureObjectManager.h"
     21 
     22 #include <private/ui/android_natives_priv.h>
     23 
     24 namespace android {
     25 // ----------------------------------------------------------------------------
     26 
     27 EGLTextureObject::EGLTextureObject()
     28     : mSize(0)
     29 {
     30     init();
     31 }
     32 
     33 EGLTextureObject::~EGLTextureObject()
     34 {
     35     if (!direct) {
     36         if (mSize && surface.data)
     37             free(surface.data);
     38         if (mMipmaps)
     39             freeMipmaps();
     40     }
     41 }
     42 
     43 void EGLTextureObject::init()
     44 {
     45     memset(&surface, 0, sizeof(surface));
     46     surface.version = sizeof(surface);
     47     mMipmaps = 0;
     48     mNumExtraLod = 0;
     49     mIsComplete = false;
     50     wraps = GL_REPEAT;
     51     wrapt = GL_REPEAT;
     52     min_filter = GL_LINEAR;
     53     mag_filter = GL_LINEAR;
     54     internalformat = 0;
     55     memset(crop_rect, 0, sizeof(crop_rect));
     56     generate_mipmap = GL_FALSE;
     57     direct = GL_FALSE;
     58     buffer = 0;
     59 }
     60 
     61 void EGLTextureObject::copyParameters(const sp<EGLTextureObject>& old)
     62 {
     63     wraps = old->wraps;
     64     wrapt = old->wrapt;
     65     min_filter = old->min_filter;
     66     mag_filter = old->mag_filter;
     67     memcpy(crop_rect, old->crop_rect, sizeof(crop_rect));
     68     generate_mipmap = old->generate_mipmap;
     69     direct = old->direct;
     70 }
     71 
     72 status_t EGLTextureObject::allocateMipmaps()
     73 {
     74     // here, by construction, mMipmaps=0 && mNumExtraLod=0
     75 
     76     if (!surface.data)
     77         return NO_INIT;
     78 
     79     int w = surface.width;
     80     int h = surface.height;
     81     const int numLods = 31 - gglClz(max(w,h));
     82     if (numLods <= 0)
     83         return NO_ERROR;
     84 
     85     mMipmaps = (GGLSurface*)malloc(numLods * sizeof(GGLSurface));
     86     if (!mMipmaps)
     87         return NO_MEMORY;
     88 
     89     memset(mMipmaps, 0, numLods * sizeof(GGLSurface));
     90     mNumExtraLod = numLods;
     91     return NO_ERROR;
     92 }
     93 
     94 void EGLTextureObject::freeMipmaps()
     95 {
     96     if (mMipmaps) {
     97         for (int i=0 ; i<mNumExtraLod ; i++) {
     98             if (mMipmaps[i].data) {
     99                 free(mMipmaps[i].data);
    100             }
    101         }
    102         free(mMipmaps);
    103         mMipmaps = 0;
    104         mNumExtraLod = 0;
    105     }
    106 }
    107 
    108 const GGLSurface& EGLTextureObject::mip(int lod) const
    109 {
    110     if (lod<=0 || !mMipmaps)
    111         return surface;
    112     lod = min(lod-1, mNumExtraLod-1);
    113     return mMipmaps[lod];
    114 }
    115 
    116 GGLSurface& EGLTextureObject::editMip(int lod)
    117 {
    118     return const_cast<GGLSurface&>(mip(lod));
    119 }
    120 
    121 status_t EGLTextureObject::setSurface(GGLSurface const* s)
    122 {
    123     // XXX: glFlush() on 's'
    124     if (mSize && surface.data) {
    125         free(surface.data);
    126     }
    127     surface = *s;
    128     internalformat = 0;
    129     buffer = 0;
    130 
    131     // we should keep the crop_rect, but it's delicate because
    132     // the new size of the surface could make it invalid.
    133     // so for now, we just loose it.
    134     memset(crop_rect, 0, sizeof(crop_rect));
    135 
    136     // it would be nice if we could keep the generate_mipmap flag,
    137     // we would have to generate them right now though.
    138     generate_mipmap = GL_FALSE;
    139 
    140     direct = GL_TRUE;
    141     mSize = 0;  // we don't own this surface
    142     if (mMipmaps)
    143         freeMipmaps();
    144     mIsComplete = true;
    145     return NO_ERROR;
    146 }
    147 
    148 status_t EGLTextureObject::setImage(ANativeWindowBuffer* native_buffer)
    149 {
    150     GGLSurface sur;
    151     sur.version = sizeof(GGLSurface);
    152     sur.width = native_buffer->width;
    153     sur.height= native_buffer->height;
    154     sur.stride= native_buffer->stride;
    155     sur.format= native_buffer->format;
    156     sur.data  = 0;
    157     setSurface(&sur);
    158     buffer = native_buffer;
    159     return NO_ERROR;
    160 }
    161 
    162 status_t EGLTextureObject::reallocate(
    163         GLint level, int w, int h, int s,
    164         int format, int compressedFormat, int bpr)
    165 {
    166     const size_t size = h * bpr;
    167     if (level == 0)
    168     {
    169         if (size!=mSize || !surface.data) {
    170             if (mSize && surface.data) {
    171                 free(surface.data);
    172             }
    173             surface.data = (GGLubyte*)malloc(size);
    174             if (!surface.data) {
    175                 mSize = 0;
    176                 mIsComplete = false;
    177                 return NO_MEMORY;
    178             }
    179             mSize = size;
    180         }
    181         surface.version = sizeof(GGLSurface);
    182         surface.width  = w;
    183         surface.height = h;
    184         surface.stride = s;
    185         surface.format = format;
    186         surface.compressedFormat = compressedFormat;
    187         if (mMipmaps)
    188             freeMipmaps();
    189         mIsComplete = true;
    190     }
    191     else
    192     {
    193         if (!mMipmaps) {
    194             if (allocateMipmaps() != NO_ERROR)
    195                 return NO_MEMORY;
    196         }
    197 
    198         LOGW_IF(level-1 >= mNumExtraLod,
    199                 "specifying mipmap level %d, but # of level is %d",
    200                 level, mNumExtraLod+1);
    201 
    202         GGLSurface& mipmap = editMip(level);
    203         if (mipmap.data)
    204             free(mipmap.data);
    205 
    206         mipmap.data = (GGLubyte*)malloc(size);
    207         if (!mipmap.data) {
    208             memset(&mipmap, 0, sizeof(GGLSurface));
    209             mIsComplete = false;
    210             return NO_MEMORY;
    211         }
    212 
    213         mipmap.version = sizeof(GGLSurface);
    214         mipmap.width  = w;
    215         mipmap.height = h;
    216         mipmap.stride = s;
    217         mipmap.format = format;
    218         mipmap.compressedFormat = compressedFormat;
    219 
    220         // check if the texture is complete
    221         mIsComplete = true;
    222         const GGLSurface* prev = &surface;
    223         for (int i=0 ; i<mNumExtraLod ; i++) {
    224             const GGLSurface* curr = mMipmaps + i;
    225             if (curr->format != surface.format) {
    226                 mIsComplete = false;
    227                 break;
    228             }
    229 
    230             uint32_t w = (prev->width  >> 1) ? : 1;
    231             uint32_t h = (prev->height >> 1) ? : 1;
    232             if (w != curr->width || h != curr->height) {
    233                 mIsComplete = false;
    234                 break;
    235             }
    236             prev = curr;
    237         }
    238     }
    239     return NO_ERROR;
    240 }
    241 
    242 // ----------------------------------------------------------------------------
    243 
    244 EGLSurfaceManager::EGLSurfaceManager()
    245     : TokenManager()
    246 {
    247 }
    248 
    249 EGLSurfaceManager::~EGLSurfaceManager()
    250 {
    251     // everything gets freed automatically here...
    252 }
    253 
    254 sp<EGLTextureObject> EGLSurfaceManager::createTexture(GLuint name)
    255 {
    256     sp<EGLTextureObject> result;
    257 
    258     Mutex::Autolock _l(mLock);
    259     if (mTextures.indexOfKey(name) >= 0)
    260         return result; // already exists!
    261 
    262     result = new EGLTextureObject();
    263 
    264     status_t err = mTextures.add(name, result);
    265     if (err < 0)
    266         result.clear();
    267 
    268     return result;
    269 }
    270 
    271 sp<EGLTextureObject> EGLSurfaceManager::removeTexture(GLuint name)
    272 {
    273     Mutex::Autolock _l(mLock);
    274     const ssize_t index = mTextures.indexOfKey(name);
    275     if (index >= 0) {
    276         sp<EGLTextureObject> result(mTextures.valueAt(index));
    277         mTextures.removeItemsAt(index);
    278         return result;
    279     }
    280     return 0;
    281 }
    282 
    283 sp<EGLTextureObject> EGLSurfaceManager::replaceTexture(GLuint name)
    284 {
    285     sp<EGLTextureObject> tex;
    286     Mutex::Autolock _l(mLock);
    287     const ssize_t index = mTextures.indexOfKey(name);
    288     if (index >= 0) {
    289         const sp<EGLTextureObject>& old = mTextures.valueAt(index);
    290         const uint32_t refs = old->getStrongCount();
    291         if (ggl_likely(refs == 1)) {
    292             // we're the only owner
    293             tex = old;
    294         } else {
    295             // keep the texture's parameters
    296             tex = new EGLTextureObject();
    297             tex->copyParameters(old);
    298             mTextures.removeItemsAt(index);
    299             mTextures.add(name, tex);
    300         }
    301     }
    302     return tex;
    303 }
    304 
    305 void EGLSurfaceManager::deleteTextures(GLsizei n, const GLuint *tokens)
    306 {
    307     // free all textures
    308     Mutex::Autolock _l(mLock);
    309     for (GLsizei i=0 ; i<n ; i++) {
    310         const GLuint t(*tokens++);
    311         if (t) {
    312             mTextures.removeItem(t);
    313         }
    314     }
    315 }
    316 
    317 sp<EGLTextureObject> EGLSurfaceManager::texture(GLuint name)
    318 {
    319     Mutex::Autolock _l(mLock);
    320     const ssize_t index = mTextures.indexOfKey(name);
    321     if (index >= 0)
    322         return mTextures.valueAt(index);
    323     return 0;
    324 }
    325 
    326 // ----------------------------------------------------------------------------
    327 }; // namespace android
    328