TextureObjectManager.cpp revision 076b1cc3a9b90aa5b381a1ed268ca0b548444c9b
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#ifdef LIBAGL_USE_GRALLOC_COPYBITS
57    copybits_fd = -1;
58#endif // LIBAGL_USE_GRALLOC_COPYBITS
59}
60
61void 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
72status_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
94void 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
108const 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
116GGLSurface& EGLTextureObject::editMip(int lod)
117{
118    return const_cast<GGLSurface&>(mip(lod));
119}
120
121status_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
130    // we should keep the crop_rect, but it's delicate because
131    // the new size of the surface could make it invalid.
132    // so for now, we just loose it.
133    memset(crop_rect, 0, sizeof(crop_rect));
134
135    // it would be nice if we could keep the generate_mipmap flag,
136    // we would have to generate them right now though.
137    generate_mipmap = GL_FALSE;
138
139    direct = GL_TRUE;
140    mSize = 0;  // we don't own this surface
141    if (mMipmaps)
142        freeMipmaps();
143    mIsComplete = true;
144    return NO_ERROR;
145}
146
147status_t EGLTextureObject::reallocate(
148        GLint level, int w, int h, int s,
149        int format, int compressedFormat, int bpr)
150{
151    const size_t size = h * bpr;
152    if (level == 0)
153    {
154        if (size!=mSize || !surface.data) {
155            if (mSize && surface.data) {
156                free(surface.data);
157            }
158            surface.data = (GGLubyte*)malloc(size);
159            if (!surface.data) {
160                mSize = 0;
161                mIsComplete = false;
162                return NO_MEMORY;
163            }
164            mSize = size;
165        }
166        surface.version = sizeof(GGLSurface);
167        surface.width  = w;
168        surface.height = h;
169        surface.stride = s;
170        surface.format = format;
171        surface.compressedFormat = compressedFormat;
172        if (mMipmaps)
173            freeMipmaps();
174        mIsComplete = true;
175    }
176    else
177    {
178        if (!mMipmaps) {
179            if (allocateMipmaps() != NO_ERROR)
180                return NO_MEMORY;
181        }
182
183        LOGW_IF(level-1 >= mNumExtraLod,
184                "specifying mipmap level %d, but # of level is %d",
185                level, mNumExtraLod+1);
186
187        GGLSurface& mipmap = editMip(level);
188        if (mipmap.data)
189            free(mipmap.data);
190
191        mipmap.data = (GGLubyte*)malloc(size);
192        if (!mipmap.data) {
193            memset(&mipmap, 0, sizeof(GGLSurface));
194            mIsComplete = false;
195            return NO_MEMORY;
196        }
197
198        mipmap.version = sizeof(GGLSurface);
199        mipmap.width  = w;
200        mipmap.height = h;
201        mipmap.stride = s;
202        mipmap.format = format;
203        mipmap.compressedFormat = compressedFormat;
204
205        // check if the texture is complete
206        mIsComplete = true;
207        const GGLSurface* prev = &surface;
208        for (int i=0 ; i<mNumExtraLod ; i++) {
209            const GGLSurface* curr = mMipmaps + i;
210            if (curr->format != surface.format) {
211                mIsComplete = false;
212                break;
213            }
214
215            uint32_t w = (prev->width  >> 1) ? : 1;
216            uint32_t h = (prev->height >> 1) ? : 1;
217            if (w != curr->width || h != curr->height) {
218                mIsComplete = false;
219                break;
220            }
221            prev = curr;
222        }
223    }
224    return NO_ERROR;
225}
226
227// ----------------------------------------------------------------------------
228
229EGLSurfaceManager::EGLSurfaceManager()
230    : TokenManager(), mCount(0)
231{
232}
233
234EGLSurfaceManager::~EGLSurfaceManager()
235{
236    // everything gets freed automatically here...
237}
238
239sp<EGLTextureObject> EGLSurfaceManager::createTexture(GLuint name)
240{
241    sp<EGLTextureObject> result;
242
243    Mutex::Autolock _l(mLock);
244    if (mTextures.indexOfKey(name) >= 0)
245        return result; // already exists!
246
247    result = new EGLTextureObject();
248
249    status_t err = mTextures.add(name, result);
250    if (err < 0)
251        result.clear();
252
253    return result;
254}
255
256sp<EGLTextureObject> EGLSurfaceManager::removeTexture(GLuint name)
257{
258    Mutex::Autolock _l(mLock);
259    const ssize_t index = mTextures.indexOfKey(name);
260    if (index >= 0) {
261        sp<EGLTextureObject> result(mTextures.valueAt(index));
262        mTextures.removeItemsAt(index);
263        return result;
264    }
265    return 0;
266}
267
268sp<EGLTextureObject> EGLSurfaceManager::replaceTexture(GLuint name)
269{
270    sp<EGLTextureObject> tex;
271    Mutex::Autolock _l(mLock);
272    const ssize_t index = mTextures.indexOfKey(name);
273    if (index >= 0) {
274        const sp<EGLTextureObject>& old = mTextures.valueAt(index);
275        const uint32_t refs = old->getStrongCount();
276        if (ggl_likely(refs == 1)) {
277            // we're the only owner
278            tex = old;
279        } else {
280            // keep the texture's parameters
281            tex = new EGLTextureObject();
282            tex->copyParameters(old);
283            mTextures.removeItemsAt(index);
284            mTextures.add(name, tex);
285        }
286    }
287    return tex;
288}
289
290void EGLSurfaceManager::deleteTextures(GLsizei n, const GLuint *tokens)
291{
292    // free all textures
293    Mutex::Autolock _l(mLock);
294    for (GLsizei i=0 ; i<n ; i++) {
295        const GLuint t(*tokens++);
296        if (t) {
297            mTextures.removeItem(t);
298        }
299    }
300}
301
302sp<EGLTextureObject> EGLSurfaceManager::texture(GLuint name)
303{
304    Mutex::Autolock _l(mLock);
305    const ssize_t index = mTextures.indexOfKey(name);
306    if (index >= 0)
307        return mTextures.valueAt(index);
308    return 0;
309}
310
311// ----------------------------------------------------------------------------
312}; // namespace android
313