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