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