blob: ee2159b3ffed7057cc3f90965c56f4c8a136be63 [file] [log] [blame]
Mathias Agopiand606de62010-05-10 20:06:11 -07001/*
2 * Copyright (C) 2010 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 <stdlib.h>
18#include <stdint.h>
19#include <sys/types.h>
20
21#include <utils/Errors.h>
22#include <utils/Log.h>
23
24#include <ui/GraphicBuffer.h>
25
26#include <GLES/gl.h>
27#include <GLES/glext.h>
28
29#include <hardware/hardware.h>
30
31#include "clz.h"
32#include "DisplayHardware/DisplayHardware.h"
33#include "TextureManager.h"
34
35namespace android {
36
37// ---------------------------------------------------------------------------
38
39TextureManager::TextureManager(uint32_t flags)
40 : mFlags(flags)
41{
42}
43
44GLuint TextureManager::createTexture()
45{
46 GLuint textureName = -1;
47 glGenTextures(1, &textureName);
48 glBindTexture(GL_TEXTURE_2D, textureName);
49 glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
50 glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
51 glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
52 glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
53 return textureName;
54}
55
56bool TextureManager::isSupportedYuvFormat(int format)
57{
58 switch (format) {
59 case HAL_PIXEL_FORMAT_YCbCr_422_SP:
60 case HAL_PIXEL_FORMAT_YCbCr_420_SP:
61 case HAL_PIXEL_FORMAT_YCbCr_422_P:
62 case HAL_PIXEL_FORMAT_YCbCr_420_P:
63 case HAL_PIXEL_FORMAT_YCbCr_422_I:
64 case HAL_PIXEL_FORMAT_YCbCr_420_I:
65 case HAL_PIXEL_FORMAT_YCrCb_420_SP:
66 return true;
67 }
68 return false;
69}
70
Mathias Agopianbb641242010-05-18 17:06:55 -070071status_t TextureManager::initEglImage(Image* texture,
Mathias Agopiand606de62010-05-10 20:06:11 -070072 EGLDisplay dpy, const sp<GraphicBuffer>& buffer)
73{
74 status_t err = NO_ERROR;
75 if (!texture->dirty) return err;
76
77 // free the previous image
78 if (texture->image != EGL_NO_IMAGE_KHR) {
79 eglDestroyImageKHR(dpy, texture->image);
80 texture->image = EGL_NO_IMAGE_KHR;
81 }
82
83 // construct an EGL_NATIVE_BUFFER_ANDROID
84 android_native_buffer_t* clientBuf = buffer->getNativeBuffer();
85
86 // create the new EGLImageKHR
87 const EGLint attrs[] = {
88 EGL_IMAGE_PRESERVED_KHR, EGL_TRUE,
89 EGL_NONE, EGL_NONE
90 };
91 texture->image = eglCreateImageKHR(
92 dpy, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID,
93 (EGLClientBuffer)clientBuf, attrs);
94
95 if (texture->image != EGL_NO_IMAGE_KHR) {
96 if (texture->name == -1UL) {
97 texture->name = createTexture();
98 texture->width = 0;
99 texture->height = 0;
100 }
101 glBindTexture(GL_TEXTURE_2D, texture->name);
102 glEGLImageTargetTexture2DOES(GL_TEXTURE_2D,
103 (GLeglImageOES)texture->image);
104 GLint error = glGetError();
105 if (error != GL_NO_ERROR) {
106 LOGE("glEGLImageTargetTexture2DOES(%p) failed err=0x%04x",
107 texture->image, error);
108 err = INVALID_OPERATION;
109 } else {
110 // Everything went okay!
Mathias Agopiand606de62010-05-10 20:06:11 -0700111 texture->dirty = false;
112 texture->width = clientBuf->width;
113 texture->height = clientBuf->height;
114 }
115 } else {
116 LOGE("eglCreateImageKHR() failed. err=0x%4x", eglGetError());
117 err = INVALID_OPERATION;
118 }
119 return err;
120}
121
122status_t TextureManager::loadTexture(Texture* texture,
123 const Region& dirty, const GGLSurface& t)
124{
125 if (texture->name == -1UL) {
126 texture->name = createTexture();
127 texture->width = 0;
128 texture->height = 0;
129 }
130
131 glBindTexture(GL_TEXTURE_2D, texture->name);
132
133 /*
134 * In OpenGL ES we can't specify a stride with glTexImage2D (however,
135 * GL_UNPACK_ALIGNMENT is a limited form of stride).
136 * So if the stride here isn't representable with GL_UNPACK_ALIGNMENT, we
137 * need to do something reasonable (here creating a bigger texture).
138 *
139 * extra pixels = (((stride - width) * pixelsize) / GL_UNPACK_ALIGNMENT);
140 *
141 * This situation doesn't happen often, but some h/w have a limitation
142 * for their framebuffer (eg: must be multiple of 8 pixels), and
143 * we need to take that into account when using these buffers as
144 * textures.
145 *
146 * This should never be a problem with POT textures
147 */
148
149 int unpack = __builtin_ctz(t.stride * bytesPerPixel(t.format));
150 unpack = 1 << ((unpack > 3) ? 3 : unpack);
151 glPixelStorei(GL_UNPACK_ALIGNMENT, unpack);
152
153 /*
154 * round to POT if needed
155 */
156 if (!(mFlags & DisplayHardware::NPOT_EXTENSION)) {
157 texture->NPOTAdjust = true;
158 }
159
160 if (texture->NPOTAdjust) {
161 // find the smallest power-of-two that will accommodate our surface
162 texture->potWidth = 1 << (31 - clz(t.width));
163 texture->potHeight = 1 << (31 - clz(t.height));
164 if (texture->potWidth < t.width) texture->potWidth <<= 1;
165 if (texture->potHeight < t.height) texture->potHeight <<= 1;
166 texture->wScale = float(t.width) / texture->potWidth;
167 texture->hScale = float(t.height) / texture->potHeight;
168 } else {
169 texture->potWidth = t.width;
170 texture->potHeight = t.height;
171 }
172
173 Rect bounds(dirty.bounds());
174 GLvoid* data = 0;
175 if (texture->width != t.width || texture->height != t.height) {
176 texture->width = t.width;
177 texture->height = t.height;
178
179 // texture size changed, we need to create a new one
180 bounds.set(Rect(t.width, t.height));
181 if (t.width == texture->potWidth &&
182 t.height == texture->potHeight) {
183 // we can do it one pass
184 data = t.data;
185 }
186
187 if (t.format == HAL_PIXEL_FORMAT_RGB_565) {
188 glTexImage2D(GL_TEXTURE_2D, 0,
189 GL_RGB, texture->potWidth, texture->potHeight, 0,
190 GL_RGB, GL_UNSIGNED_SHORT_5_6_5, data);
191 } else if (t.format == HAL_PIXEL_FORMAT_RGBA_4444) {
192 glTexImage2D(GL_TEXTURE_2D, 0,
193 GL_RGBA, texture->potWidth, texture->potHeight, 0,
194 GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, data);
195 } else if (t.format == HAL_PIXEL_FORMAT_RGBA_8888 ||
196 t.format == HAL_PIXEL_FORMAT_RGBX_8888) {
197 glTexImage2D(GL_TEXTURE_2D, 0,
198 GL_RGBA, texture->potWidth, texture->potHeight, 0,
199 GL_RGBA, GL_UNSIGNED_BYTE, data);
200 } else if (isSupportedYuvFormat(t.format)) {
201 // just show the Y plane of YUV buffers
202 glTexImage2D(GL_TEXTURE_2D, 0,
203 GL_LUMINANCE, texture->potWidth, texture->potHeight, 0,
204 GL_LUMINANCE, GL_UNSIGNED_BYTE, data);
205 } else {
206 // oops, we don't handle this format!
207 LOGE("texture=%d, using format %d, which is not "
208 "supported by the GL", texture->name, t.format);
209 }
210 }
211 if (!data) {
212 if (t.format == HAL_PIXEL_FORMAT_RGB_565) {
213 glTexSubImage2D(GL_TEXTURE_2D, 0,
214 0, bounds.top, t.width, bounds.height(),
215 GL_RGB, GL_UNSIGNED_SHORT_5_6_5,
216 t.data + bounds.top*t.stride*2);
217 } else if (t.format == HAL_PIXEL_FORMAT_RGBA_4444) {
218 glTexSubImage2D(GL_TEXTURE_2D, 0,
219 0, bounds.top, t.width, bounds.height(),
220 GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4,
221 t.data + bounds.top*t.stride*2);
222 } else if (t.format == HAL_PIXEL_FORMAT_RGBA_8888 ||
223 t.format == HAL_PIXEL_FORMAT_RGBX_8888) {
224 glTexSubImage2D(GL_TEXTURE_2D, 0,
225 0, bounds.top, t.width, bounds.height(),
226 GL_RGBA, GL_UNSIGNED_BYTE,
227 t.data + bounds.top*t.stride*4);
228 } else if (isSupportedYuvFormat(t.format)) {
229 // just show the Y plane of YUV buffers
230 glTexSubImage2D(GL_TEXTURE_2D, 0,
231 0, bounds.top, t.width, bounds.height(),
232 GL_LUMINANCE, GL_UNSIGNED_BYTE,
233 t.data + bounds.top*t.stride);
234 }
235 }
236 return NO_ERROR;
237}
238
239// ---------------------------------------------------------------------------
240
241}; // namespace android