blob: e5d5302b7d23440571e52511b91872bf1ab78236 [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
71status_t TextureManager::initEglImage(Texture* texture,
72 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!
111 texture->NPOTAdjust = false;
112 texture->dirty = false;
113 texture->width = clientBuf->width;
114 texture->height = clientBuf->height;
115 }
116 } else {
117 LOGE("eglCreateImageKHR() failed. err=0x%4x", eglGetError());
118 err = INVALID_OPERATION;
119 }
120 return err;
121}
122
123status_t TextureManager::loadTexture(Texture* texture,
124 const Region& dirty, const GGLSurface& t)
125{
126 if (texture->name == -1UL) {
127 texture->name = createTexture();
128 texture->width = 0;
129 texture->height = 0;
130 }
131
132 glBindTexture(GL_TEXTURE_2D, texture->name);
133
134 /*
135 * In OpenGL ES we can't specify a stride with glTexImage2D (however,
136 * GL_UNPACK_ALIGNMENT is a limited form of stride).
137 * So if the stride here isn't representable with GL_UNPACK_ALIGNMENT, we
138 * need to do something reasonable (here creating a bigger texture).
139 *
140 * extra pixels = (((stride - width) * pixelsize) / GL_UNPACK_ALIGNMENT);
141 *
142 * This situation doesn't happen often, but some h/w have a limitation
143 * for their framebuffer (eg: must be multiple of 8 pixels), and
144 * we need to take that into account when using these buffers as
145 * textures.
146 *
147 * This should never be a problem with POT textures
148 */
149
150 int unpack = __builtin_ctz(t.stride * bytesPerPixel(t.format));
151 unpack = 1 << ((unpack > 3) ? 3 : unpack);
152 glPixelStorei(GL_UNPACK_ALIGNMENT, unpack);
153
154 /*
155 * round to POT if needed
156 */
157 if (!(mFlags & DisplayHardware::NPOT_EXTENSION)) {
158 texture->NPOTAdjust = true;
159 }
160
161 if (texture->NPOTAdjust) {
162 // find the smallest power-of-two that will accommodate our surface
163 texture->potWidth = 1 << (31 - clz(t.width));
164 texture->potHeight = 1 << (31 - clz(t.height));
165 if (texture->potWidth < t.width) texture->potWidth <<= 1;
166 if (texture->potHeight < t.height) texture->potHeight <<= 1;
167 texture->wScale = float(t.width) / texture->potWidth;
168 texture->hScale = float(t.height) / texture->potHeight;
169 } else {
170 texture->potWidth = t.width;
171 texture->potHeight = t.height;
172 }
173
174 Rect bounds(dirty.bounds());
175 GLvoid* data = 0;
176 if (texture->width != t.width || texture->height != t.height) {
177 texture->width = t.width;
178 texture->height = t.height;
179
180 // texture size changed, we need to create a new one
181 bounds.set(Rect(t.width, t.height));
182 if (t.width == texture->potWidth &&
183 t.height == texture->potHeight) {
184 // we can do it one pass
185 data = t.data;
186 }
187
188 if (t.format == HAL_PIXEL_FORMAT_RGB_565) {
189 glTexImage2D(GL_TEXTURE_2D, 0,
190 GL_RGB, texture->potWidth, texture->potHeight, 0,
191 GL_RGB, GL_UNSIGNED_SHORT_5_6_5, data);
192 } else if (t.format == HAL_PIXEL_FORMAT_RGBA_4444) {
193 glTexImage2D(GL_TEXTURE_2D, 0,
194 GL_RGBA, texture->potWidth, texture->potHeight, 0,
195 GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, data);
196 } else if (t.format == HAL_PIXEL_FORMAT_RGBA_8888 ||
197 t.format == HAL_PIXEL_FORMAT_RGBX_8888) {
198 glTexImage2D(GL_TEXTURE_2D, 0,
199 GL_RGBA, texture->potWidth, texture->potHeight, 0,
200 GL_RGBA, GL_UNSIGNED_BYTE, data);
201 } else if (isSupportedYuvFormat(t.format)) {
202 // just show the Y plane of YUV buffers
203 glTexImage2D(GL_TEXTURE_2D, 0,
204 GL_LUMINANCE, texture->potWidth, texture->potHeight, 0,
205 GL_LUMINANCE, GL_UNSIGNED_BYTE, data);
206 } else {
207 // oops, we don't handle this format!
208 LOGE("texture=%d, using format %d, which is not "
209 "supported by the GL", texture->name, t.format);
210 }
211 }
212 if (!data) {
213 if (t.format == HAL_PIXEL_FORMAT_RGB_565) {
214 glTexSubImage2D(GL_TEXTURE_2D, 0,
215 0, bounds.top, t.width, bounds.height(),
216 GL_RGB, GL_UNSIGNED_SHORT_5_6_5,
217 t.data + bounds.top*t.stride*2);
218 } else if (t.format == HAL_PIXEL_FORMAT_RGBA_4444) {
219 glTexSubImage2D(GL_TEXTURE_2D, 0,
220 0, bounds.top, t.width, bounds.height(),
221 GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4,
222 t.data + bounds.top*t.stride*2);
223 } else if (t.format == HAL_PIXEL_FORMAT_RGBA_8888 ||
224 t.format == HAL_PIXEL_FORMAT_RGBX_8888) {
225 glTexSubImage2D(GL_TEXTURE_2D, 0,
226 0, bounds.top, t.width, bounds.height(),
227 GL_RGBA, GL_UNSIGNED_BYTE,
228 t.data + bounds.top*t.stride*4);
229 } else if (isSupportedYuvFormat(t.format)) {
230 // just show the Y plane of YUV buffers
231 glTexSubImage2D(GL_TEXTURE_2D, 0,
232 0, bounds.top, t.width, bounds.height(),
233 GL_LUMINANCE, GL_UNSIGNED_BYTE,
234 t.data + bounds.top*t.stride);
235 }
236 }
237 return NO_ERROR;
238}
239
240// ---------------------------------------------------------------------------
241
242}; // namespace android