blob: 0736b6b7b374028742432075609283a231d75814 [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
Mathias Agopian6d2cad22009-06-17 21:18:56 -070037
38#define DEBUG_COPYBIT true
39
Mathias Agopian076b1cc2009-04-10 14:24:30 -070040// ----------------------------------------------------------------------------
41
42namespace android {
43
Mathias Agopian0a3139a2009-06-10 16:01:54 -070044static void textureToCopyBitImage(
45 const GGLSurface* surface, buffer_handle_t buffer, copybit_image_t* img)
46{
47 // we know private_handle_t is good here
48 private_handle_t* hnd = (private_handle_t*)buffer;
Mathias Agopian076b1cc2009-04-10 14:24:30 -070049 img->w = surface->stride;
50 img->h = surface->height;
51 img->format = surface->format;
Mathias Agopian0a3139a2009-06-10 16:01:54 -070052 img->offset = hnd->offset;
Mathias Agopian076b1cc2009-04-10 14:24:30 -070053 img->base = surface->data;
Mathias Agopian0a3139a2009-06-10 16:01:54 -070054 img->fd = hnd->fd;
Mathias Agopian076b1cc2009-04-10 14:24:30 -070055}
56
57struct clipRectRegion : public copybit_region_t {
Mathias Agopiancf251b92009-06-16 18:08:29 -070058 clipRectRegion(ogles_context_t* c)
59 {
60 scissor_t const* scissor = &c->rasterizer.state.scissor;
61 r.l = scissor->left;
62 r.t = scissor->top;
63 r.r = scissor->right;
64 r.b = scissor->bottom;
65 next = iterate;
Mathias Agopian076b1cc2009-04-10 14:24:30 -070066 }
67private:
68 static int iterate(copybit_region_t const * self, copybit_rect_t* rect) {
Mathias Agopiancf251b92009-06-16 18:08:29 -070069 *rect = static_cast<clipRectRegion const*>(self)->r;
70 const_cast<copybit_region_t *>(self)->next = iterate_done;
71 return 1;
72 }
73 static int iterate_done(copybit_region_t const *, copybit_rect_t*) {
Mathias Agopian076b1cc2009-04-10 14:24:30 -070074 return 0;
75 }
Mathias Agopiancf251b92009-06-16 18:08:29 -070076 copybit_rect_t r;
Mathias Agopian076b1cc2009-04-10 14:24:30 -070077};
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
Mathias Agopian6d2cad22009-06-17 21:18:56 -0700120 if (c->copybits.blitEngine == NULL) {
121 LOGD_IF(DEBUG_COPYBIT, "no copybit hal");
122 return false;
123 }
124
125 if (c->rasterizer.state.enables
126 & (GGL_ENABLE_DEPTH_TEST|GGL_ENABLE_FOG)) {
127 LOGD_IF(DEBUG_COPYBIT, "depth test and/or fog");
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700128 return false;
129 }
130
Mathias Agopian0a3139a2009-06-10 16:01:54 -0700131 // Note: The drawSurfaceBuffer is only set for destination
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700132 // surfaces types that are supported by the hardware and
133 // do not have an alpha channel. So we don't have to re-check that here.
134
135 static const int tmu = 0;
136 texture_unit_t& u(c->textures.tmu[tmu]);
137 EGLTextureObject* textureObject = u.texture;
138
139 if (!supportedCopybitsFormat(textureObject->surface.format)) {
Mathias Agopian6d2cad22009-06-17 21:18:56 -0700140 LOGD_IF(DEBUG_COPYBIT, "texture format not supported");
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700141 return false;
142 }
143 return true;
144}
145
146
147static bool copybit(GLint x, GLint y,
148 GLint w, GLint h,
149 EGLTextureObject* textureObject,
150 const GLint* crop_rect,
151 int transform,
152 ogles_context_t* c)
153{
154 // We assume checkContext has already been called and has already
155 // returned true.
156
157 const GGLSurface& cbSurface = c->rasterizer.state.buffers.color.s;
158
159 y = cbSurface.height - (y + h);
160
161 const GLint Ucr = crop_rect[0];
162 const GLint Vcr = crop_rect[1];
163 const GLint Wcr = crop_rect[2];
164 const GLint Hcr = crop_rect[3];
165
166 int32_t dsdx = (Wcr << 16) / w; // dsdx = ((Wcr/w)/Wt)*Wt
167 int32_t dtdy = ((-Hcr) << 16) / h; // dtdy = -((Hcr/h)/Ht)*Ht
168
169 if (dsdx < c->copybits.minScale || dsdx > c->copybits.maxScale
170 || dtdy < c->copybits.minScale || dtdy > c->copybits.maxScale) {
171 // The requested scale is out of the range the hardware
172 // can support.
Mathias Agopian6d2cad22009-06-17 21:18:56 -0700173 LOGD_IF(DEBUG_COPYBIT,
174 "scale out of range dsdx=%08x, dtdy=%08x", dsdx, dtdy);
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700175 return false;
176 }
177
Mathias Agopian6d2cad22009-06-17 21:18:56 -0700178 /*
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700179 int32_t texelArea = gglMulx(dtdy, dsdx);
180 if (texelArea < FIXED_ONE && textureObject->mag_filter != GL_LINEAR) {
181 // Non-linear filtering on a texture enlargement.
Mathias Agopian6d2cad22009-06-17 21:18:56 -0700182 LOGD_IF(DEBUG_COPYBIT, "mag filter is not GL_LINEAR");
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700183 return false;
184 }
185
186 if (texelArea > FIXED_ONE && textureObject->min_filter != GL_LINEAR) {
187 // Non-linear filtering on an texture shrink.
Mathias Agopian6d2cad22009-06-17 21:18:56 -0700188 LOGD_IF(DEBUG_COPYBIT, "min filter is not GL_LINEAR");
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700189 return false;
190 }
Mathias Agopian6d2cad22009-06-17 21:18:56 -0700191 */
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700192
193 const uint32_t enables = c->rasterizer.state.enables;
194 int planeAlpha = 255;
195 static const int tmu = 0;
196 texture_t& tev(c->rasterizer.state.texture[tmu]);
197 bool srcTextureHasAlpha = hasAlpha(textureObject->surface.format);
198 switch (tev.env) {
199
200 case GGL_REPLACE:
201 if (!srcTextureHasAlpha) {
202 planeAlpha = fixedToByte(c->currentColorClamped.a);
203 }
204 break;
205
206 case GGL_MODULATE:
207 if (! (c->currentColorClamped.r == FIXED_ONE
208 && c->currentColorClamped.g == FIXED_ONE
209 && c->currentColorClamped.b == FIXED_ONE)) {
Mathias Agopian6d2cad22009-06-17 21:18:56 -0700210 LOGD_IF(DEBUG_COPYBIT, "MODULATE and non white color");
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700211 return false;
212 }
213 planeAlpha = fixedToByte(c->currentColorClamped.a);
214 break;
215
216 default:
217 // Incompatible texture environment.
Mathias Agopian6d2cad22009-06-17 21:18:56 -0700218 LOGD_IF(DEBUG_COPYBIT, "incompatible texture environment");
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700219 return false;
220 }
221
222 bool blending = false;
223
224 if ((enables & GGL_ENABLE_BLENDING)
225 && !(c->rasterizer.state.blend.src == GL_ONE
226 && c->rasterizer.state.blend.dst == GL_ZERO)) {
227 // Blending is OK if it is
228 // the exact kind of blending that the copybits hardware supports.
229 // Note: The hardware only supports
230 // GL_SRC_ALPHA / GL_ONE_MINUS_SRC_ALPHA,
231 // But the surface flinger uses GL_ONE / GL_ONE_MINUS_SRC_ALPHA.
232 // We substitute GL_SRC_ALPHA / GL_ONE_MINUS_SRC_ALPHA in that case,
233 // because the performance is worth it, even if the results are
234 // not correct.
235 if (!((c->rasterizer.state.blend.src == GL_SRC_ALPHA
236 || c->rasterizer.state.blend.src == GL_ONE)
237 && c->rasterizer.state.blend.dst == GL_ONE_MINUS_SRC_ALPHA
238 && c->rasterizer.state.blend.alpha_separate == 0)) {
239 // Incompatible blend mode.
Mathias Agopian6d2cad22009-06-17 21:18:56 -0700240 LOGD_IF(DEBUG_COPYBIT, "incompatible blend mode");
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700241 return false;
242 }
243 blending = true;
244 } else {
245 // No blending is OK if we are not using alpha.
246 if (srcTextureHasAlpha || planeAlpha != 255) {
247 // Incompatible alpha
Mathias Agopian6d2cad22009-06-17 21:18:56 -0700248 LOGD_IF(DEBUG_COPYBIT, "incompatible alpha");
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700249 return false;
250 }
251 }
252
253 if (srcTextureHasAlpha && planeAlpha != 255) {
254 // Can't do two types of alpha at once.
Mathias Agopian6d2cad22009-06-17 21:18:56 -0700255 LOGD_IF(DEBUG_COPYBIT, "src alpha and plane alpha");
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700256 return false;
257 }
258
259 // LOGW("calling copybits");
260
261 copybit_device_t* copybit = c->copybits.blitEngine;
Mathias Agopian0a3139a2009-06-10 16:01:54 -0700262
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700263 copybit_image_t dst;
Mathias Agopian0a3139a2009-06-10 16:01:54 -0700264 buffer_handle_t target_hnd = c->copybits.drawSurfaceBuffer;
265 textureToCopyBitImage(&cbSurface, target_hnd, &dst);
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700266 copybit_rect_t drect = {x, y, x+w, y+h};
267
Mathias Agopian0a3139a2009-06-10 16:01:54 -0700268 // we know private_handle_t is good here
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700269 copybit_image_t src;
Mathias Agopian0a3139a2009-06-10 16:01:54 -0700270 buffer_handle_t source_hnd = textureObject->buffer->handle;
271 textureToCopyBitImage(&textureObject->surface, source_hnd, &src);
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700272 copybit_rect_t srect = { Ucr, Vcr + Hcr, Ucr + Wcr, Vcr };
273
274 copybit->set_parameter(copybit, COPYBIT_TRANSFORM, transform);
275 copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, planeAlpha);
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700276 copybit->set_parameter(copybit, COPYBIT_DITHER,
277 (enables & GGL_ENABLE_DITHER) ? COPYBIT_ENABLE : COPYBIT_DISABLE);
278
279 clipRectRegion it(c);
280 copybit->stretch(copybit, &dst, &src, &drect, &srect, &it);
281 return true;
282}
283
284/*
285 * Try to draw a triangle fan with copybit, return false if we fail.
286 */
Mathias Agopian6d2cad22009-06-17 21:18:56 -0700287bool drawTriangleFanWithCopybit_impl(ogles_context_t* c, GLint first, GLsizei count)
288{
289 if (!checkContext(c)) {
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700290 return false;
291 }
292
293 c->arrays.compileElements(c, c->vc.vBuffer, 0, 4);
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700294
Mathias Agopian6d2cad22009-06-17 21:18:56 -0700295 // we detect if we're dealing with a rectangle, by comparing the
296 // rectangles {v0,v2} and {v1,v3} which should be identical.
297
298 const vec4_t& v0 = c->vc.vBuffer[0].window;
299 const vec4_t& v1 = c->vc.vBuffer[1].window;
300 const vec4_t& v2 = c->vc.vBuffer[2].window;
301 const vec4_t& v3 = c->vc.vBuffer[3].window;
302 int l = min(v0.x, v2.x);
303 int b = min(v0.y, v2.y);
304 int r = max(v0.x, v2.x);
305 int t = max(v0.y, v2.y);
306 if ((l != min(v1.x, v3.x)) || (b != min(v1.y, v3.y)) ||
307 (r != max(v1.x, v3.x)) || (t != max(v1.y, v3.y))) {
308 LOGD_IF(DEBUG_COPYBIT, "geometry not a rectangle");
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700309 return false;
310 }
Mathias Agopian6d2cad22009-06-17 21:18:56 -0700311
312 const vec4_t& t0 = c->vc.vBuffer[0].texture[0];
313 const vec4_t& t1 = c->vc.vBuffer[1].texture[0];
314 const vec4_t& t2 = c->vc.vBuffer[2].texture[0];
315 const vec4_t& t3 = c->vc.vBuffer[3].texture[0];
316 int txl = min(t0.x, t2.x);
317 int txb = min(t0.y, t2.y);
318 int txr = max(t0.x, t2.x);
319 int txt = max(t0.y, t2.y);
320 if ((txl != min(t1.x, t3.x)) || (txb != min(t1.y, t3.y)) ||
321 (txr != max(t1.x, t3.x)) || (txt != max(t1.y, t3.y))) {
322 LOGD_IF(DEBUG_COPYBIT, "texcoord not a rectangle");
323 return false;
324 }
325 if ((txl != 0) || (txb != 0) ||
326 (txr != FIXED_ONE) || (txt != FIXED_ONE)) {
327 // we could probably handle this case, if we wanted to
328 LOGD_IF(DEBUG_COPYBIT, "texture is cropped");
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700329 return false;
330 }
331
Mathias Agopian6d2cad22009-06-17 21:18:56 -0700332 // at this point, we know we are dealing with a rectangle, so we
333 // only need to consider 3 vertices for computing the jacobians
334
335 const int dx01 = v1.x - v0.x;
336 const int dy01 = v1.y - v0.y;
337 const int dx02 = v2.x - v0.x;
338 const int dy02 = v2.y - v0.y;
339 const int ds01 = t1.S - t0.S;
340 const int dt01 = t1.T - t0.T;
341 const int ds02 = t2.S - t0.S;
342 const int dt02 = t2.T - t0.T;
343 const int area = dx01*dy02 - dy01*dx02;
344 int dsdx, dsdy, dtdx, dtdy;
345 if (area >= 0) {
346 dsdx = ds01*dy02 - ds02*dy01;
347 dsdy = ds02*dx01 - ds01*dx02;
348 dtdx = dt01*dy02 - dt02*dy01;
349 dtdy = dt02*dx01 - dt01*dx02;
350 } else {
351 dsdx = ds02*dy01 - ds01*dy02;
352 dsdy = ds01*dx02 - ds02*dx01;
353 dtdx = dt02*dy01 - dt01*dy02;
354 dtdy = dt01*dx02 - dt02*dx01;
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700355 }
356
Mathias Agopian6d2cad22009-06-17 21:18:56 -0700357 // here we rely on the fact that we know the transform is
358 // a rigid-body transform AND that it can only rotate in 90 degrees
359 // increments
360
361 int transform = 0;
362 if (dsdx == 0) {
363 // 90 deg rotation case
364 // [ 0 dtdx ]
365 // [ dsdx 0 ]
366 transform |= COPYBIT_TRANSFORM_ROT_90;
367 // FIXME: not sure if FLIP_H and FLIP_V shouldn't be inverted
368 if (dtdx > 0)
369 transform |= COPYBIT_TRANSFORM_FLIP_H;
370 if (dsdy < 0)
371 transform |= COPYBIT_TRANSFORM_FLIP_V;
372 } else {
373 // [ dsdx 0 ]
374 // [ 0 dtdy ]
375 if (dsdx < 0)
376 transform |= COPYBIT_TRANSFORM_FLIP_H;
377 if (dtdy < 0)
378 transform |= COPYBIT_TRANSFORM_FLIP_V;
379 }
380
381 //LOGD("l=%d, b=%d, w=%d, h=%d, tr=%d", x, y, w, h, transform);
382 //LOGD("A=%f\tB=%f\nC=%f\tD=%f",
383 // dsdx/65536.0, dtdx/65536.0, dsdy/65536.0, dtdy/65536.0);
384
385 int x = l >> 4;
386 int y = b >> 4;
387 int w = (r-l) >> 4;
388 int h = (t-b) >> 4;
389 texture_unit_t& u(c->textures.tmu[0]);
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700390 EGLTextureObject* textureObject = u.texture;
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700391 GLint tWidth = textureObject->surface.width;
392 GLint tHeight = textureObject->surface.height;
393 GLint crop_rect[4] = {0, tHeight, tWidth, -tHeight};
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700394 const GGLSurface& cbSurface = c->rasterizer.state.buffers.color.s;
395 y = cbSurface.height - (y + h);
Mathias Agopian6d2cad22009-06-17 21:18:56 -0700396 return copybit(x, y, w, h, textureObject, crop_rect, transform, c);
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700397}
398
399/*
400 * Try to drawTexiOESWithCopybit, return false if we fail.
401 */
402
403bool drawTexiOESWithCopybit_impl(GLint x, GLint y, GLint z,
404 GLint w, GLint h, ogles_context_t* c)
405{
406 // quickly process empty rects
407 if ((w|h) <= 0) {
408 return true;
409 }
Mathias Agopian6d2cad22009-06-17 21:18:56 -0700410 if (!checkContext(c)) {
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700411 return false;
412 }
Mathias Agopian6d2cad22009-06-17 21:18:56 -0700413 texture_unit_t& u(c->textures.tmu[0]);
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700414 EGLTextureObject* textureObject = u.texture;
Mathias Agopian6d2cad22009-06-17 21:18:56 -0700415 return copybit(x, y, w, h, textureObject, textureObject->crop_rect, 0, c);
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700416}
417
418} // namespace android
419