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 : 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 buffer = 0; 57} 58 59void 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 70status_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 92void 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 106const 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 114GGLSurface& EGLTextureObject::editMip(int lod) 115{ 116 return const_cast<GGLSurface&>(mip(lod)); 117} 118 119status_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 146status_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 160status_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 242EGLSurfaceManager::EGLSurfaceManager() 243 : TokenManager() 244{ 245} 246 247EGLSurfaceManager::~EGLSurfaceManager() 248{ 249 // everything gets freed automatically here... 250} 251 252sp<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 269sp<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 281sp<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 303void 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 315sp<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