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