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