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 
EGLTextureObject()25 EGLTextureObject::EGLTextureObject()
26     : mSize(0)
27 {
28     init();
29 }
30 
~EGLTextureObject()31 EGLTextureObject::~EGLTextureObject()
32 {
33     if (!direct) {
34         if (mSize && surface.data)
35             free(surface.data);
36         if (mMipmaps)
37             freeMipmaps();
38     }
39 }
40 
init()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 
copyParameters(const sp<EGLTextureObject> & old)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 
allocateMipmaps()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 
freeMipmaps()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 
mip(int lod) const106 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 
editMip(int lod)114 GGLSurface& EGLTextureObject::editMip(int lod)
115 {
116     return const_cast<GGLSurface&>(mip(lod));
117 }
118 
setSurface(GGLSurface const * s)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 
setImage(ANativeWindowBuffer * native_buffer)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 
reallocate(GLint level,int w,int h,int s,int format,int compressedFormat,int bpr)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 
EGLSurfaceManager()242 EGLSurfaceManager::EGLSurfaceManager()
243     : TokenManager()
244 {
245 }
246 
~EGLSurfaceManager()247 EGLSurfaceManager::~EGLSurfaceManager()
248 {
249     // everything gets freed automatically here...
250 }
251 
createTexture(GLuint name)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 
removeTexture(GLuint name)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 
replaceTexture(GLuint name)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 
deleteTextures(GLsizei n,const GLuint * tokens)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 
texture(GLuint name)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