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