blob: 255ccac3565baa7b0124169fc19db3aede58f404 [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 Agopian1473f462009-04-10 14:24:30 -070058#ifdef LIBAGL_USE_GRALLOC_COPYBITS
Mathias Agopian350d6512009-06-10 16:01:54 -070059 try_copybit = false;
Mathias Agopian1473f462009-04-10 14:24:30 -070060#endif // LIBAGL_USE_GRALLOC_COPYBITS
Mathias Agopiandff8e582009-05-04 14:17:04 -070061 buffer = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080062}
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;
Mathias Agopiandff8e582009-05-04 14:17:04 -0700132 buffer = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800133
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
Mathias Agopiandff8e582009-05-04 14:17:04 -0700151status_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
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800165status_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;
Mathias Agopian1473f462009-04-10 14:24:30 -0700170 if (level == 0)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800171 {
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
Mathias Agopian1473f462009-04-10 14:24:30 -0700201 LOGW_IF(level-1 >= mNumExtraLod,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800202 "specifying mipmap level %d, but # of level is %d",
Mathias Agopian1473f462009-04-10 14:24:30 -0700203 level, mNumExtraLod+1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800204
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()
Mathias Agopiandff8e582009-05-04 14:17:04 -0700248 : TokenManager()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800249{
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