blob: bbb82fc48a9cc10579f42a76e8b38daa1645390e [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 ** Copyright 2006, The Android Open Source Project
3 **
Mathias Agopian1473f462009-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 Project9066cfe2009-03-03 19:31:44 -08007 **
Mathias Agopian1473f462009-04-10 14:24:30 -07008 ** http://www.apache.org/licenses/LICENSE-2.0
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009 **
Mathias Agopian1473f462009-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 Project9066cfe2009-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
Mathias Agopianb51e18d2009-05-05 18:21:32 -070022#include <private/ui/android_natives_priv.h>
Mathias Agopianac2523b2009-05-05 18:11:11 -070023
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080024namespace android {
25// ----------------------------------------------------------------------------
26
27EGLTextureObject::EGLTextureObject()
Mathias Agopiandff8e582009-05-04 14:17:04 -070028 : mSize(0)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080029{
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;
Mathias Agopiandff8e582009-05-04 14:17:04 -070058 buffer = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080059}
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;
Mathias Agopiandff8e582009-05-04 14:17:04 -0700129 buffer = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800130
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
Mathias Agopiandff8e582009-05-04 14:17:04 -0700148status_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
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800162status_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;
Mathias Agopian1473f462009-04-10 14:24:30 -0700167 if (level == 0)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800168 {
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
Mathias Agopian1473f462009-04-10 14:24:30 -0700198 LOGW_IF(level-1 >= mNumExtraLod,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800199 "specifying mipmap level %d, but # of level is %d",
Mathias Agopian1473f462009-04-10 14:24:30 -0700200 level, mNumExtraLod+1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800201
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()
Mathias Agopiandff8e582009-05-04 14:17:04 -0700245 : TokenManager()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800246{
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