blob: 9eb99f0bc2319f66d183bdd47a2cfc557932b37d [file] [log] [blame]
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001/*
2 ** Copyright 2006, The Android Open Source Project
3 **
Mathias Agopian076b1cc2009-04-10 14:24:30 -07004 ** 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
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08007 **
Mathias Agopian076b1cc2009-04-10 14:24:30 -07008 ** http://www.apache.org/licenses/LICENSE-2.0
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08009 **
Mathias Agopian076b1cc2009-04-10 14:24:30 -070010 ** 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
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080014 ** 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()
Mathias Agopian0926f502009-05-04 14:17:04 -070026 : mSize(0)
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080027{
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;
Mathias Agopian076b1cc2009-04-10 14:24:30 -070056#ifdef LIBAGL_USE_GRALLOC_COPYBITS
57 copybits_fd = -1;
58#endif // LIBAGL_USE_GRALLOC_COPYBITS
Mathias Agopian0926f502009-05-04 14:17:04 -070059 buffer = 0;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080060}
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;
Mathias Agopian0926f502009-05-04 14:17:04 -0700130 buffer = 0;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800131
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
Mathias Agopian0926f502009-05-04 14:17:04 -0700149status_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
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800163status_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;
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700168 if (level == 0)
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800169 {
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
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700199 LOGW_IF(level-1 >= mNumExtraLod,
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800200 "specifying mipmap level %d, but # of level is %d",
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700201 level, mNumExtraLod+1);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800202
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()
Mathias Agopian0926f502009-05-04 14:17:04 -0700246 : TokenManager()
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800247{
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