blob: a539a2bdd5d7b46467ac76cc45a31c86a99fe90f [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"
Mathias Agopian076b1cc2009-04-10 14:24:30 -070030#include "TextureObjectManager.h"
Mathias Agopian0a3139a2009-06-10 16:01:54 -070031
Mathias Agopian076b1cc2009-04-10 14:24:30 -070032#include <hardware/gralloc.h>
33#include <hardware/copybit.h>
Mathias Agopian0a3139a2009-06-10 16:01:54 -070034#include <private/ui/android_natives_priv.h>
Mathias Agopian076b1cc2009-04-10 14:24:30 -070035#include "gralloc_priv.h"
36
37// ----------------------------------------------------------------------------
38
39namespace android {
40
Mathias Agopian0a3139a2009-06-10 16:01:54 -070041static void textureToCopyBitImage(
42 const GGLSurface* surface, buffer_handle_t buffer, copybit_image_t* img)
43{
44 // we know private_handle_t is good here
45 private_handle_t* hnd = (private_handle_t*)buffer;
Mathias Agopian076b1cc2009-04-10 14:24:30 -070046 img->w = surface->stride;
47 img->h = surface->height;
48 img->format = surface->format;
Mathias Agopian0a3139a2009-06-10 16:01:54 -070049 img->offset = hnd->offset;
Mathias Agopian076b1cc2009-04-10 14:24:30 -070050 img->base = surface->data;
Mathias Agopian0a3139a2009-06-10 16:01:54 -070051 img->fd = hnd->fd;
Mathias Agopian076b1cc2009-04-10 14:24:30 -070052}
53
54struct clipRectRegion : public copybit_region_t {
55 clipRectRegion(ogles_context_t* c) {
56 next = iterate;
57 int x = c->viewport.scissor.x;
58 int y = c->viewport.scissor.y;
59 r.l = x;
60 r.t = y;
61 r.r = x + c->viewport.scissor.w;
62 r.b = y + c->viewport.scissor.h;
63 firstTime = true;
64 }
65private:
66 static int iterate(copybit_region_t const * self, copybit_rect_t* rect) {
67 clipRectRegion* myself = (clipRectRegion*) self;
68 if (myself->firstTime) {
69 myself->firstTime = false;
70 *rect = myself->r;
71 return 1;
72 }
73 return 0;
74 }
75 mutable copybit_rect_t r;
76 mutable bool firstTime;
77};
78
79static bool supportedCopybitsFormat(int format) {
80 switch (format) {
81 case COPYBIT_FORMAT_RGBA_8888:
82 case COPYBIT_FORMAT_RGB_565:
83 case COPYBIT_FORMAT_BGRA_8888:
84 case COPYBIT_FORMAT_RGBA_5551:
85 case COPYBIT_FORMAT_RGBA_4444:
86 case COPYBIT_FORMAT_YCbCr_422_SP:
87 case COPYBIT_FORMAT_YCbCr_420_SP:
88 return true;
89 default:
90 return false;
91 }
92}
93
94static bool hasAlpha(int format) {
95 switch (format) {
96 case COPYBIT_FORMAT_RGBA_8888:
97 case COPYBIT_FORMAT_BGRA_8888:
98 case COPYBIT_FORMAT_RGBA_5551:
99 case COPYBIT_FORMAT_RGBA_4444:
100 return true;
101 default:
102 return false;
103 }
104}
105
106static inline int fixedToByte(GGLfixed val) {
107 return (val - (val >> 8)) >> 8;
108}
109
110/**
111 * Performs a quick check of the rendering state. If this function returns
112 * false we cannot use the copybit driver.
113 */
114
115static bool checkContext(ogles_context_t* c) {
116
Mathias Agopian0a3139a2009-06-10 16:01:54 -0700117 // By convention copybitQuickCheckContext() has already returned true.
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700118 // avoid checking the same information again.
119
120 if (c->copybits.blitEngine == NULL
121 || (c->rasterizer.state.enables
122 & (GGL_ENABLE_DEPTH_TEST|GGL_ENABLE_FOG)) != 0) {
123 return false;
124 }
125
Mathias Agopian0a3139a2009-06-10 16:01:54 -0700126 // Note: The drawSurfaceBuffer is only set for destination
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700127 // surfaces types that are supported by the hardware and
128 // do not have an alpha channel. So we don't have to re-check that here.
129
130 static const int tmu = 0;
131 texture_unit_t& u(c->textures.tmu[tmu]);
132 EGLTextureObject* textureObject = u.texture;
133
134 if (!supportedCopybitsFormat(textureObject->surface.format)) {
135 return false;
136 }
137 return true;
138}
139
140
141static bool copybit(GLint x, GLint y,
142 GLint w, GLint h,
143 EGLTextureObject* textureObject,
144 const GLint* crop_rect,
145 int transform,
146 ogles_context_t* c)
147{
148 // We assume checkContext has already been called and has already
149 // returned true.
150
151 const GGLSurface& cbSurface = c->rasterizer.state.buffers.color.s;
152
153 y = cbSurface.height - (y + h);
154
155 const GLint Ucr = crop_rect[0];
156 const GLint Vcr = crop_rect[1];
157 const GLint Wcr = crop_rect[2];
158 const GLint Hcr = crop_rect[3];
159
160 int32_t dsdx = (Wcr << 16) / w; // dsdx = ((Wcr/w)/Wt)*Wt
161 int32_t dtdy = ((-Hcr) << 16) / h; // dtdy = -((Hcr/h)/Ht)*Ht
162
163 if (dsdx < c->copybits.minScale || dsdx > c->copybits.maxScale
164 || dtdy < c->copybits.minScale || dtdy > c->copybits.maxScale) {
165 // The requested scale is out of the range the hardware
166 // can support.
167 return false;
168 }
169
170 int32_t texelArea = gglMulx(dtdy, dsdx);
171 if (texelArea < FIXED_ONE && textureObject->mag_filter != GL_LINEAR) {
172 // Non-linear filtering on a texture enlargement.
173 return false;
174 }
175
176 if (texelArea > FIXED_ONE && textureObject->min_filter != GL_LINEAR) {
177 // Non-linear filtering on an texture shrink.
178 return false;
179 }
180
181 const uint32_t enables = c->rasterizer.state.enables;
182 int planeAlpha = 255;
183 static const int tmu = 0;
184 texture_t& tev(c->rasterizer.state.texture[tmu]);
185 bool srcTextureHasAlpha = hasAlpha(textureObject->surface.format);
186 switch (tev.env) {
187
188 case GGL_REPLACE:
189 if (!srcTextureHasAlpha) {
190 planeAlpha = fixedToByte(c->currentColorClamped.a);
191 }
192 break;
193
194 case GGL_MODULATE:
195 if (! (c->currentColorClamped.r == FIXED_ONE
196 && c->currentColorClamped.g == FIXED_ONE
197 && c->currentColorClamped.b == FIXED_ONE)) {
198 return false;
199 }
200 planeAlpha = fixedToByte(c->currentColorClamped.a);
201 break;
202
203 default:
204 // Incompatible texture environment.
205 return false;
206 }
207
208 bool blending = false;
209
210 if ((enables & GGL_ENABLE_BLENDING)
211 && !(c->rasterizer.state.blend.src == GL_ONE
212 && c->rasterizer.state.blend.dst == GL_ZERO)) {
213 // Blending is OK if it is
214 // the exact kind of blending that the copybits hardware supports.
215 // Note: The hardware only supports
216 // GL_SRC_ALPHA / GL_ONE_MINUS_SRC_ALPHA,
217 // But the surface flinger uses GL_ONE / GL_ONE_MINUS_SRC_ALPHA.
218 // We substitute GL_SRC_ALPHA / GL_ONE_MINUS_SRC_ALPHA in that case,
219 // because the performance is worth it, even if the results are
220 // not correct.
221 if (!((c->rasterizer.state.blend.src == GL_SRC_ALPHA
222 || c->rasterizer.state.blend.src == GL_ONE)
223 && c->rasterizer.state.blend.dst == GL_ONE_MINUS_SRC_ALPHA
224 && c->rasterizer.state.blend.alpha_separate == 0)) {
225 // Incompatible blend mode.
226 return false;
227 }
228 blending = true;
229 } else {
230 // No blending is OK if we are not using alpha.
231 if (srcTextureHasAlpha || planeAlpha != 255) {
232 // Incompatible alpha
233 return false;
234 }
235 }
236
237 if (srcTextureHasAlpha && planeAlpha != 255) {
238 // Can't do two types of alpha at once.
239 return false;
240 }
241
242 // LOGW("calling copybits");
243
244 copybit_device_t* copybit = c->copybits.blitEngine;
Mathias Agopian0a3139a2009-06-10 16:01:54 -0700245
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700246 copybit_image_t dst;
Mathias Agopian0a3139a2009-06-10 16:01:54 -0700247 buffer_handle_t target_hnd = c->copybits.drawSurfaceBuffer;
248 textureToCopyBitImage(&cbSurface, target_hnd, &dst);
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700249 copybit_rect_t drect = {x, y, x+w, y+h};
250
Mathias Agopian0a3139a2009-06-10 16:01:54 -0700251 // we know private_handle_t is good here
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700252 copybit_image_t src;
Mathias Agopian0a3139a2009-06-10 16:01:54 -0700253 buffer_handle_t source_hnd = textureObject->buffer->handle;
254 textureToCopyBitImage(&textureObject->surface, source_hnd, &src);
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700255 copybit_rect_t srect = { Ucr, Vcr + Hcr, Ucr + Wcr, Vcr };
256
257 copybit->set_parameter(copybit, COPYBIT_TRANSFORM, transform);
258 copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, planeAlpha);
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700259 copybit->set_parameter(copybit, COPYBIT_DITHER,
260 (enables & GGL_ENABLE_DITHER) ? COPYBIT_ENABLE : COPYBIT_DISABLE);
261
262 clipRectRegion it(c);
263 copybit->stretch(copybit, &dst, &src, &drect, &srect, &it);
264 return true;
265}
266
267/*
268 * Try to draw a triangle fan with copybit, return false if we fail.
269 */
270bool drawTrangleFanWithCopybit_impl(ogles_context_t* c, GLint first, GLsizei count) {
271 if (! checkContext(c)) {
272 return false;
273 }
274
275 c->arrays.compileElements(c, c->vc.vBuffer, 0, 4);
276 // Is the result a screen aligned rectangle?
277 int sx[4];
278 int sy[4];
279 for (int i = 0; i < 4; i++) {
280 GLfixed x = c->vc.vBuffer[i].window.x;
281 GLfixed y = c->vc.vBuffer[i].window.y;
282 if (x < 0 || y < 0 || (x & 0xf) != 0 || (y & 0xf) != 0) {
283 return false;
284 }
285 sx[i] = x >> 4;
286 sy[i] = y >> 4;
287 }
288
289 /*
290 * This is the pattern we're looking for:
291 * (2)--(3)
292 * |\ |
293 * | \ |
294 * | \ |
295 * | \|
296 * (1)--(0)
297 *
298 */
299 int dx[4];
300 int dy[4];
301 for (int i = 0; i < 4; i++) {
302 int i1 = (i + 1) & 3;
303 dx[i] = sx[i] - sx[i1];
304 dy[i] = sy[i] - sy[i1];
305 }
306 if (dx[1] | dx[3] | dy[0] | dy[2]) {
307 return false;
308 }
309 if (dx[0] != -dx[2] || dy[1] != -dy[3]) {
310 return false;
311 }
312
313 int x = sx[1];
314 int y = sy[1];
315 int w = dx[0];
316 int h = dy[3];
317
318 // We expect the texture coordinates to always be the unit square:
319
320 static const GLfixed kExpectedUV[8] = {
321 0, 0,
322 0, FIXED_ONE,
323 FIXED_ONE, FIXED_ONE,
324 FIXED_ONE, 0
325 };
326 {
327 const GLfixed* pExpected = &kExpectedUV[0];
328 for (int i = 0; i < 4; i++) {
329 GLfixed u = c->vc.vBuffer[i].texture[0].x;
330 GLfixed v = c->vc.vBuffer[i].texture[0].y;
331 if (u != *pExpected++ || v != *pExpected++) {
332 return false;
333 }
334 }
335 }
336
337 static const int tmu = 0;
338 texture_unit_t& u(c->textures.tmu[tmu]);
339 EGLTextureObject* textureObject = u.texture;
340
341 GLint tWidth = textureObject->surface.width;
342 GLint tHeight = textureObject->surface.height;
343 GLint crop_rect[4] = {0, tHeight, tWidth, -tHeight};
344
345 const GGLSurface& cbSurface = c->rasterizer.state.buffers.color.s;
346 y = cbSurface.height - (y + h);
347
348 return copybit(x, y, w, h, textureObject, crop_rect,
349 COPYBIT_TRANSFORM_ROT_90, c);
350}
351
352/*
353 * Try to drawTexiOESWithCopybit, return false if we fail.
354 */
355
356bool drawTexiOESWithCopybit_impl(GLint x, GLint y, GLint z,
357 GLint w, GLint h, ogles_context_t* c)
358{
359 // quickly process empty rects
360 if ((w|h) <= 0) {
361 return true;
362 }
363
364 if (! checkContext(c)) {
365 return false;
366 }
367
368 static const int tmu = 0;
369 texture_unit_t& u(c->textures.tmu[tmu]);
370 EGLTextureObject* textureObject = u.texture;
371
372 return copybit(x, y, w, h, textureObject, textureObject->crop_rect,
373 0, c);
374}
375
376} // namespace android
377