blob: ce31854172d34b123fbddf56f0b2b1c17431dba8 [file] [log] [blame]
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001/*
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
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800132 // it would be nice if we could keep the generate_mipmap flag,
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700133 // 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{
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800289 // free all textures
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700290 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