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