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