TextureObjectManager.cpp revision bb0628d9debc5ddd5b1ca3311d6397bbe668c4ee
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#include <private/ui/android_natives_priv.h>
23
24namespace android {
25// ----------------------------------------------------------------------------
26
27EGLTextureObject::EGLTextureObject()
28    : mSize(0)
29{
30    init();
31}
32
33EGLTextureObject::~EGLTextureObject()
34{
35    if (!direct) {
36        if (mSize && surface.data)
37            free(surface.data);
38        if (mMipmaps)
39            freeMipmaps();
40    }
41}
42
43void EGLTextureObject::init()
44{
45    memset(&surface, 0, sizeof(surface));
46    surface.version = sizeof(surface);
47    mMipmaps = 0;
48    mNumExtraLod = 0;
49    mIsComplete = false;
50    wraps = GL_REPEAT;
51    wrapt = GL_REPEAT;
52    min_filter = GL_LINEAR;
53    mag_filter = GL_LINEAR;
54    internalformat = 0;
55    memset(crop_rect, 0, sizeof(crop_rect));
56    generate_mipmap = GL_FALSE;
57    direct = GL_FALSE;
58    buffer = 0;
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    buffer = 0;
130
131    // we should keep the crop_rect, but it's delicate because
132    // the new size of the surface could make it invalid.
133    // so for now, we just loose it.
134    memset(crop_rect, 0, sizeof(crop_rect));
135
136    // it would be nice if we could keep the generate_mipmap flag,
137    // we would have to generate them right now though.
138    generate_mipmap = GL_FALSE;
139
140    direct = GL_TRUE;
141    mSize = 0;  // we don't own this surface
142    if (mMipmaps)
143        freeMipmaps();
144    mIsComplete = true;
145    return NO_ERROR;
146}
147
148status_t EGLTextureObject::setImage(android_native_buffer_t* native_buffer)
149{
150    GGLSurface sur;
151    sur.version = sizeof(GGLSurface);
152    sur.width = native_buffer->width;
153    sur.height= native_buffer->height;
154    sur.stride= native_buffer->stride;
155    sur.format= native_buffer->format;
156    sur.data  = 0;
157    setSurface(&sur);
158    buffer = native_buffer;
159    return NO_ERROR;
160}
161
162status_t EGLTextureObject::reallocate(
163        GLint level, int w, int h, int s,
164        int format, int compressedFormat, int bpr)
165{
166    const size_t size = h * bpr;
167    if (level == 0)
168    {
169        if (size!=mSize || !surface.data) {
170            if (mSize && surface.data) {
171                free(surface.data);
172            }
173            surface.data = (GGLubyte*)malloc(size);
174            if (!surface.data) {
175                mSize = 0;
176                mIsComplete = false;
177                return NO_MEMORY;
178            }
179            mSize = size;
180        }
181        surface.version = sizeof(GGLSurface);
182        surface.width  = w;
183        surface.height = h;
184        surface.stride = s;
185        surface.format = format;
186        surface.compressedFormat = compressedFormat;
187        if (mMipmaps)
188            freeMipmaps();
189        mIsComplete = true;
190    }
191    else
192    {
193        if (!mMipmaps) {
194            if (allocateMipmaps() != NO_ERROR)
195                return NO_MEMORY;
196        }
197
198        LOGW_IF(level-1 >= mNumExtraLod,
199                "specifying mipmap level %d, but # of level is %d",
200                level, mNumExtraLod+1);
201
202        GGLSurface& mipmap = editMip(level);
203        if (mipmap.data)
204            free(mipmap.data);
205
206        mipmap.data = (GGLubyte*)malloc(size);
207        if (!mipmap.data) {
208            memset(&mipmap, 0, sizeof(GGLSurface));
209            mIsComplete = false;
210            return NO_MEMORY;
211        }
212
213        mipmap.version = sizeof(GGLSurface);
214        mipmap.width  = w;
215        mipmap.height = h;
216        mipmap.stride = s;
217        mipmap.format = format;
218        mipmap.compressedFormat = compressedFormat;
219
220        // check if the texture is complete
221        mIsComplete = true;
222        const GGLSurface* prev = &surface;
223        for (int i=0 ; i<mNumExtraLod ; i++) {
224            const GGLSurface* curr = mMipmaps + i;
225            if (curr->format != surface.format) {
226                mIsComplete = false;
227                break;
228            }
229
230            uint32_t w = (prev->width  >> 1) ? : 1;
231            uint32_t h = (prev->height >> 1) ? : 1;
232            if (w != curr->width || h != curr->height) {
233                mIsComplete = false;
234                break;
235            }
236            prev = curr;
237        }
238    }
239    return NO_ERROR;
240}
241
242// ----------------------------------------------------------------------------
243
244EGLSurfaceManager::EGLSurfaceManager()
245    : TokenManager()
246{
247}
248
249EGLSurfaceManager::~EGLSurfaceManager()
250{
251    // everything gets freed automatically here...
252}
253
254sp<EGLTextureObject> EGLSurfaceManager::createTexture(GLuint name)
255{
256    sp<EGLTextureObject> result;
257
258    Mutex::Autolock _l(mLock);
259    if (mTextures.indexOfKey(name) >= 0)
260        return result; // already exists!
261
262    result = new EGLTextureObject();
263
264    status_t err = mTextures.add(name, result);
265    if (err < 0)
266        result.clear();
267
268    return result;
269}
270
271sp<EGLTextureObject> EGLSurfaceManager::removeTexture(GLuint name)
272{
273    Mutex::Autolock _l(mLock);
274    const ssize_t index = mTextures.indexOfKey(name);
275    if (index >= 0) {
276        sp<EGLTextureObject> result(mTextures.valueAt(index));
277        mTextures.removeItemsAt(index);
278        return result;
279    }
280    return 0;
281}
282
283sp<EGLTextureObject> EGLSurfaceManager::replaceTexture(GLuint name)
284{
285    sp<EGLTextureObject> tex;
286    Mutex::Autolock _l(mLock);
287    const ssize_t index = mTextures.indexOfKey(name);
288    if (index >= 0) {
289        const sp<EGLTextureObject>& old = mTextures.valueAt(index);
290        const uint32_t refs = old->getStrongCount();
291        if (ggl_likely(refs == 1)) {
292            // we're the only owner
293            tex = old;
294        } else {
295            // keep the texture's parameters
296            tex = new EGLTextureObject();
297            tex->copyParameters(old);
298            mTextures.removeItemsAt(index);
299            mTextures.add(name, tex);
300        }
301    }
302    return tex;
303}
304
305void EGLSurfaceManager::deleteTextures(GLsizei n, const GLuint *tokens)
306{
307    // free all textures
308    Mutex::Autolock _l(mLock);
309    for (GLsizei i=0 ; i<n ; i++) {
310        const GLuint t(*tokens++);
311        if (t) {
312            mTextures.removeItem(t);
313        }
314    }
315}
316
317sp<EGLTextureObject> EGLSurfaceManager::texture(GLuint name)
318{
319    Mutex::Autolock _l(mLock);
320    const ssize_t index = mTextures.indexOfKey(name);
321    if (index >= 0)
322        return mTextures.valueAt(index);
323    return 0;
324}
325
326// ----------------------------------------------------------------------------
327}; // namespace android
328