blob: 427e42aaf292c6af4da5cee55256d11741021677 [file] [log] [blame]
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001/*
2**
3** Copyright 2009, The Android Open Source Project
4**
5** Licensed under the Apache License, Version 2.0 (the "License");
6** you may not use this file except in compliance with the License.
7** You may obtain a copy of the License at
8**
9** http://www.apache.org/licenses/LICENSE-2.0
10**
11** Unless required by applicable law or agreed to in writing, software
12** distributed under the License is distributed on an "AS IS" BASIS,
13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14** See the License for the specific language governing permissions and
15** limitations under the License.
16*/
17
18#include <stdlib.h>
19#include <stdio.h>
20
21#include "context.h"
22#include "fp.h"
23#include "state.h"
24#include "matrix.h"
25#include "vertex.h"
26#include "light.h"
27#include "primitives.h"
28#include "texture.h"
29#include "BufferObjectManager.h"
30
31#include "TextureObjectManager.h"
32#include <hardware/gralloc.h>
33#include <hardware/copybit.h>
34#include "gralloc_priv.h"
35
36// ----------------------------------------------------------------------------
37
38namespace android {
39
40static void textureToCopyBitImage(const GGLSurface* surface, int fd, copybit_image_t* img) {
41 img->w = surface->stride;
42 img->h = surface->height;
43 img->format = surface->format;
44 img->offset = 0;
45 img->base = surface->data;
46 img->fd = fd;
47}
48
49struct clipRectRegion : public copybit_region_t {
50 clipRectRegion(ogles_context_t* c) {
51 next = iterate;
52 int x = c->viewport.scissor.x;
53 int y = c->viewport.scissor.y;
54 r.l = x;
55 r.t = y;
56 r.r = x + c->viewport.scissor.w;
57 r.b = y + c->viewport.scissor.h;
58 firstTime = true;
59 }
60private:
61 static int iterate(copybit_region_t const * self, copybit_rect_t* rect) {
62 clipRectRegion* myself = (clipRectRegion*) self;
63 if (myself->firstTime) {
64 myself->firstTime = false;
65 *rect = myself->r;
66 return 1;
67 }
68 return 0;
69 }
70 mutable copybit_rect_t r;
71 mutable bool firstTime;
72};
73
74static bool supportedCopybitsFormat(int format) {
75 switch (format) {
76 case COPYBIT_FORMAT_RGBA_8888:
77 case COPYBIT_FORMAT_RGB_565:
78 case COPYBIT_FORMAT_BGRA_8888:
79 case COPYBIT_FORMAT_RGBA_5551:
80 case COPYBIT_FORMAT_RGBA_4444:
81 case COPYBIT_FORMAT_YCbCr_422_SP:
82 case COPYBIT_FORMAT_YCbCr_420_SP:
83 return true;
84 default:
85 return false;
86 }
87}
88
89static bool hasAlpha(int format) {
90 switch (format) {
91 case COPYBIT_FORMAT_RGBA_8888:
92 case COPYBIT_FORMAT_BGRA_8888:
93 case COPYBIT_FORMAT_RGBA_5551:
94 case COPYBIT_FORMAT_RGBA_4444:
95 return true;
96 default:
97 return false;
98 }
99}
100
101static inline int fixedToByte(GGLfixed val) {
102 return (val - (val >> 8)) >> 8;
103}
104
105/**
106 * Performs a quick check of the rendering state. If this function returns
107 * false we cannot use the copybit driver.
108 */
109
110static bool checkContext(ogles_context_t* c) {
111
112 // By convenction copybitQuickCheckContext() has already returned true.
113 // avoid checking the same information again.
114
115 if (c->copybits.blitEngine == NULL
116 || (c->rasterizer.state.enables
117 & (GGL_ENABLE_DEPTH_TEST|GGL_ENABLE_FOG)) != 0) {
118 return false;
119 }
120
121 // Note: The drawSurfaceFd is only set for destination
122 // surfaces types that are supported by the hardware and
123 // do not have an alpha channel. So we don't have to re-check that here.
124
125 static const int tmu = 0;
126 texture_unit_t& u(c->textures.tmu[tmu]);
127 EGLTextureObject* textureObject = u.texture;
128
129 if (!supportedCopybitsFormat(textureObject->surface.format)) {
130 return false;
131 }
132 return true;
133}
134
135
136static bool copybit(GLint x, GLint y,
137 GLint w, GLint h,
138 EGLTextureObject* textureObject,
139 const GLint* crop_rect,
140 int transform,
141 ogles_context_t* c)
142{
143 // We assume checkContext has already been called and has already
144 // returned true.
145
146 const GGLSurface& cbSurface = c->rasterizer.state.buffers.color.s;
147
148 y = cbSurface.height - (y + h);
149
150 const GLint Ucr = crop_rect[0];
151 const GLint Vcr = crop_rect[1];
152 const GLint Wcr = crop_rect[2];
153 const GLint Hcr = crop_rect[3];
154
155 int32_t dsdx = (Wcr << 16) / w; // dsdx = ((Wcr/w)/Wt)*Wt
156 int32_t dtdy = ((-Hcr) << 16) / h; // dtdy = -((Hcr/h)/Ht)*Ht
157
158 if (dsdx < c->copybits.minScale || dsdx > c->copybits.maxScale
159 || dtdy < c->copybits.minScale || dtdy > c->copybits.maxScale) {
160 // The requested scale is out of the range the hardware
161 // can support.
162 return false;
163 }
164
165 int32_t texelArea = gglMulx(dtdy, dsdx);
166 if (texelArea < FIXED_ONE && textureObject->mag_filter != GL_LINEAR) {
167 // Non-linear filtering on a texture enlargement.
168 return false;
169 }
170
171 if (texelArea > FIXED_ONE && textureObject->min_filter != GL_LINEAR) {
172 // Non-linear filtering on an texture shrink.
173 return false;
174 }
175
176 const uint32_t enables = c->rasterizer.state.enables;
177 int planeAlpha = 255;
178 static const int tmu = 0;
179 texture_t& tev(c->rasterizer.state.texture[tmu]);
180 bool srcTextureHasAlpha = hasAlpha(textureObject->surface.format);
181 switch (tev.env) {
182
183 case GGL_REPLACE:
184 if (!srcTextureHasAlpha) {
185 planeAlpha = fixedToByte(c->currentColorClamped.a);
186 }
187 break;
188
189 case GGL_MODULATE:
190 if (! (c->currentColorClamped.r == FIXED_ONE
191 && c->currentColorClamped.g == FIXED_ONE
192 && c->currentColorClamped.b == FIXED_ONE)) {
193 return false;
194 }
195 planeAlpha = fixedToByte(c->currentColorClamped.a);
196 break;
197
198 default:
199 // Incompatible texture environment.
200 return false;
201 }
202
203 bool blending = false;
204
205 if ((enables & GGL_ENABLE_BLENDING)
206 && !(c->rasterizer.state.blend.src == GL_ONE
207 && c->rasterizer.state.blend.dst == GL_ZERO)) {
208 // Blending is OK if it is
209 // the exact kind of blending that the copybits hardware supports.
210 // Note: The hardware only supports
211 // GL_SRC_ALPHA / GL_ONE_MINUS_SRC_ALPHA,
212 // But the surface flinger uses GL_ONE / GL_ONE_MINUS_SRC_ALPHA.
213 // We substitute GL_SRC_ALPHA / GL_ONE_MINUS_SRC_ALPHA in that case,
214 // because the performance is worth it, even if the results are
215 // not correct.
216 if (!((c->rasterizer.state.blend.src == GL_SRC_ALPHA
217 || c->rasterizer.state.blend.src == GL_ONE)
218 && c->rasterizer.state.blend.dst == GL_ONE_MINUS_SRC_ALPHA
219 && c->rasterizer.state.blend.alpha_separate == 0)) {
220 // Incompatible blend mode.
221 return false;
222 }
223 blending = true;
224 } else {
225 // No blending is OK if we are not using alpha.
226 if (srcTextureHasAlpha || planeAlpha != 255) {
227 // Incompatible alpha
228 return false;
229 }
230 }
231
232 if (srcTextureHasAlpha && planeAlpha != 255) {
233 // Can't do two types of alpha at once.
234 return false;
235 }
236
237 // LOGW("calling copybits");
238
239 copybit_device_t* copybit = c->copybits.blitEngine;
240 copybit_image_t dst;
241 textureToCopyBitImage(&cbSurface, c->copybits.drawSurfaceFd, &dst);
242 copybit_rect_t drect = {x, y, x+w, y+h};
243
244 copybit_image_t src;
245 textureToCopyBitImage(&textureObject->surface, textureObject->copybits_fd,
246 &src);
247 copybit_rect_t srect = { Ucr, Vcr + Hcr, Ucr + Wcr, Vcr };
248
249 copybit->set_parameter(copybit, COPYBIT_TRANSFORM, transform);
250 copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, planeAlpha);
251
252 copybit->set_parameter(copybit, COPYBIT_DITHER,
253 (enables & GGL_ENABLE_DITHER) ? COPYBIT_ENABLE : COPYBIT_DISABLE);
254
255 clipRectRegion it(c);
256 copybit->stretch(copybit, &dst, &src, &drect, &srect, &it);
257 return true;
258}
259
260/*
261 * Try to draw a triangle fan with copybit, return false if we fail.
262 */
263bool drawTrangleFanWithCopybit_impl(ogles_context_t* c, GLint first, GLsizei count) {
264 if (! checkContext(c)) {
265 return false;
266 }
267
268 c->arrays.compileElements(c, c->vc.vBuffer, 0, 4);
269 // Is the result a screen aligned rectangle?
270 int sx[4];
271 int sy[4];
272 for (int i = 0; i < 4; i++) {
273 GLfixed x = c->vc.vBuffer[i].window.x;
274 GLfixed y = c->vc.vBuffer[i].window.y;
275 if (x < 0 || y < 0 || (x & 0xf) != 0 || (y & 0xf) != 0) {
276 return false;
277 }
278 sx[i] = x >> 4;
279 sy[i] = y >> 4;
280 }
281
282 /*
283 * This is the pattern we're looking for:
284 * (2)--(3)
285 * |\ |
286 * | \ |
287 * | \ |
288 * | \|
289 * (1)--(0)
290 *
291 */
292 int dx[4];
293 int dy[4];
294 for (int i = 0; i < 4; i++) {
295 int i1 = (i + 1) & 3;
296 dx[i] = sx[i] - sx[i1];
297 dy[i] = sy[i] - sy[i1];
298 }
299 if (dx[1] | dx[3] | dy[0] | dy[2]) {
300 return false;
301 }
302 if (dx[0] != -dx[2] || dy[1] != -dy[3]) {
303 return false;
304 }
305
306 int x = sx[1];
307 int y = sy[1];
308 int w = dx[0];
309 int h = dy[3];
310
311 // We expect the texture coordinates to always be the unit square:
312
313 static const GLfixed kExpectedUV[8] = {
314 0, 0,
315 0, FIXED_ONE,
316 FIXED_ONE, FIXED_ONE,
317 FIXED_ONE, 0
318 };
319 {
320 const GLfixed* pExpected = &kExpectedUV[0];
321 for (int i = 0; i < 4; i++) {
322 GLfixed u = c->vc.vBuffer[i].texture[0].x;
323 GLfixed v = c->vc.vBuffer[i].texture[0].y;
324 if (u != *pExpected++ || v != *pExpected++) {
325 return false;
326 }
327 }
328 }
329
330 static const int tmu = 0;
331 texture_unit_t& u(c->textures.tmu[tmu]);
332 EGLTextureObject* textureObject = u.texture;
333
334 GLint tWidth = textureObject->surface.width;
335 GLint tHeight = textureObject->surface.height;
336 GLint crop_rect[4] = {0, tHeight, tWidth, -tHeight};
337
338 const GGLSurface& cbSurface = c->rasterizer.state.buffers.color.s;
339 y = cbSurface.height - (y + h);
340
341 return copybit(x, y, w, h, textureObject, crop_rect,
342 COPYBIT_TRANSFORM_ROT_90, c);
343}
344
345/*
346 * Try to drawTexiOESWithCopybit, return false if we fail.
347 */
348
349bool drawTexiOESWithCopybit_impl(GLint x, GLint y, GLint z,
350 GLint w, GLint h, ogles_context_t* c)
351{
352 // quickly process empty rects
353 if ((w|h) <= 0) {
354 return true;
355 }
356
357 if (! checkContext(c)) {
358 return false;
359 }
360
361 static const int tmu = 0;
362 texture_unit_t& u(c->textures.tmu[tmu]);
363 EGLTextureObject* textureObject = u.texture;
364
365 return copybit(x, y, w, h, textureObject, textureObject->crop_rect,
366 0, c);
367}
368
369} // namespace android
370