blob: 4cacc1125f24ec174ab075517353c2f32ace1763 [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
Mathias Agopian54ba51d2009-10-26 20:12:37 -070036#include <ui/GraphicBuffer.h>
37#include <ui/Region.h>
38#include <ui/Rect.h>
39
Mathias Agopian6d2cad22009-06-17 21:18:56 -070040
Mathias Agopianf7457342009-11-30 12:10:53 -080041#define DEBUG_COPYBIT false
Mathias Agopian6d2cad22009-06-17 21:18:56 -070042
Mathias Agopian076b1cc2009-04-10 14:24:30 -070043// ----------------------------------------------------------------------------
44
45namespace android {
46
Mathias Agopian0a3139a2009-06-10 16:01:54 -070047static void textureToCopyBitImage(
Mathias Agopian6dbedd72009-10-16 16:17:58 -070048 const GGLSurface* surface, int32_t opFormat,
Mathias Agopian6fee0642009-11-02 17:48:33 -080049 android_native_buffer_t* buffer, copybit_image_t* img)
Mathias Agopian0a3139a2009-06-10 16:01:54 -070050{
Mathias Agopian6fee0642009-11-02 17:48:33 -080051 uint32_t vstride = 0;
52 if (opFormat == COPYBIT_FORMAT_YCbCr_422_SP ||
53 opFormat == COPYBIT_FORMAT_YCbCr_420_SP) {
54 // NOTE: this static_cast is really not safe b/c we can't know for
55 // sure the buffer passed is of the right type.
56 // However, since we do this only for YUV formats, we should be safe
57 // since only SurfaceFlinger makes use of them.
58 GraphicBuffer* graphicBuffer = static_cast<GraphicBuffer*>(buffer);
59 vstride = graphicBuffer->getVerticalStride();
60 }
61
Mathias Agopian076b1cc2009-04-10 14:24:30 -070062 img->w = surface->stride;
Mathias Agopian6fee0642009-11-02 17:48:33 -080063 img->h = vstride ? vstride : surface->height;
Mathias Agopian6dbedd72009-10-16 16:17:58 -070064 img->format = opFormat;
Mathias Agopian076b1cc2009-04-10 14:24:30 -070065 img->base = surface->data;
Mathias Agopian6fee0642009-11-02 17:48:33 -080066 img->handle = (native_handle_t *)buffer->handle;
Mathias Agopian076b1cc2009-04-10 14:24:30 -070067}
68
69struct clipRectRegion : public copybit_region_t {
Mathias Agopiancf251b92009-06-16 18:08:29 -070070 clipRectRegion(ogles_context_t* c)
71 {
72 scissor_t const* scissor = &c->rasterizer.state.scissor;
73 r.l = scissor->left;
74 r.t = scissor->top;
75 r.r = scissor->right;
76 r.b = scissor->bottom;
77 next = iterate;
Mathias Agopian076b1cc2009-04-10 14:24:30 -070078 }
79private:
80 static int iterate(copybit_region_t const * self, copybit_rect_t* rect) {
Mathias Agopiancf251b92009-06-16 18:08:29 -070081 *rect = static_cast<clipRectRegion const*>(self)->r;
82 const_cast<copybit_region_t *>(self)->next = iterate_done;
83 return 1;
84 }
85 static int iterate_done(copybit_region_t const *, copybit_rect_t*) {
Mathias Agopian076b1cc2009-04-10 14:24:30 -070086 return 0;
87 }
Mathias Agopiandf2d9292009-10-28 21:00:29 -070088public:
Mathias Agopiancf251b92009-06-16 18:08:29 -070089 copybit_rect_t r;
Mathias Agopian076b1cc2009-04-10 14:24:30 -070090};
91
92static bool supportedCopybitsFormat(int format) {
93 switch (format) {
94 case COPYBIT_FORMAT_RGBA_8888:
Mathias Agopiandfbec0e2009-08-07 20:55:14 -070095 case COPYBIT_FORMAT_RGBX_8888:
96 case COPYBIT_FORMAT_RGB_888:
Mathias Agopian076b1cc2009-04-10 14:24:30 -070097 case COPYBIT_FORMAT_RGB_565:
98 case COPYBIT_FORMAT_BGRA_8888:
99 case COPYBIT_FORMAT_RGBA_5551:
100 case COPYBIT_FORMAT_RGBA_4444:
101 case COPYBIT_FORMAT_YCbCr_422_SP:
102 case COPYBIT_FORMAT_YCbCr_420_SP:
103 return true;
104 default:
105 return false;
106 }
107}
108
109static bool hasAlpha(int format) {
110 switch (format) {
111 case COPYBIT_FORMAT_RGBA_8888:
112 case COPYBIT_FORMAT_BGRA_8888:
113 case COPYBIT_FORMAT_RGBA_5551:
114 case COPYBIT_FORMAT_RGBA_4444:
115 return true;
116 default:
117 return false;
118 }
119}
120
121static inline int fixedToByte(GGLfixed val) {
122 return (val - (val >> 8)) >> 8;
123}
124
125/**
126 * Performs a quick check of the rendering state. If this function returns
127 * false we cannot use the copybit driver.
128 */
129
130static bool checkContext(ogles_context_t* c) {
131
Mathias Agopian0a3139a2009-06-10 16:01:54 -0700132 // By convention copybitQuickCheckContext() has already returned true.
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700133 // avoid checking the same information again.
134
Mathias Agopian6d2cad22009-06-17 21:18:56 -0700135 if (c->copybits.blitEngine == NULL) {
136 LOGD_IF(DEBUG_COPYBIT, "no copybit hal");
137 return false;
138 }
139
140 if (c->rasterizer.state.enables
141 & (GGL_ENABLE_DEPTH_TEST|GGL_ENABLE_FOG)) {
142 LOGD_IF(DEBUG_COPYBIT, "depth test and/or fog");
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700143 return false;
144 }
145
Mathias Agopian0a3139a2009-06-10 16:01:54 -0700146 // Note: The drawSurfaceBuffer is only set for destination
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700147 // surfaces types that are supported by the hardware and
148 // do not have an alpha channel. So we don't have to re-check that here.
149
150 static const int tmu = 0;
151 texture_unit_t& u(c->textures.tmu[tmu]);
152 EGLTextureObject* textureObject = u.texture;
153
154 if (!supportedCopybitsFormat(textureObject->surface.format)) {
Mathias Agopian6d2cad22009-06-17 21:18:56 -0700155 LOGD_IF(DEBUG_COPYBIT, "texture format not supported");
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700156 return false;
157 }
158 return true;
159}
160
161
162static bool copybit(GLint x, GLint y,
163 GLint w, GLint h,
164 EGLTextureObject* textureObject,
165 const GLint* crop_rect,
166 int transform,
167 ogles_context_t* c)
168{
Mathias Agopian2ad8ec52009-10-27 23:33:48 -0700169 status_t err = NO_ERROR;
170
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700171 // We assume checkContext has already been called and has already
172 // returned true.
173
174 const GGLSurface& cbSurface = c->rasterizer.state.buffers.color.s;
175
176 y = cbSurface.height - (y + h);
177
178 const GLint Ucr = crop_rect[0];
179 const GLint Vcr = crop_rect[1];
180 const GLint Wcr = crop_rect[2];
181 const GLint Hcr = crop_rect[3];
182
Mathias Agopian295eff22009-06-29 16:36:49 -0700183 GLint screen_w = w;
184 GLint screen_h = h;
185 int32_t dsdx = Wcr << 16; // dsdx = ((Wcr/screen_w)/Wt)*Wt
186 int32_t dtdy = Hcr << 16; // dtdy = -((Hcr/screen_h)/Ht)*Ht
Mathias Agopiane7829b82009-06-23 18:31:06 -0700187 if (transform & COPYBIT_TRANSFORM_ROT_90) {
Mathias Agopian295eff22009-06-29 16:36:49 -0700188 swap(screen_w, screen_h);
Mathias Agopiane7829b82009-06-23 18:31:06 -0700189 }
Mathias Agopian295eff22009-06-29 16:36:49 -0700190 if (dsdx!=screen_w || dtdy!=screen_h) {
191 // in most cases the divide is not needed
192 dsdx /= screen_w;
193 dtdy /= screen_h;
194 }
195 dtdy = -dtdy; // see equation of dtdy above
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700196
Mathias Agopianaa6e88b2009-06-17 21:58:18 -0700197 // copybit doesn't say anything about filtering, so we can't
198 // discriminate. On msm7k, copybit will always filter.
199 // the code below handles min/mag filters, we keep it as a reference.
200
201#ifdef MIN_MAG_FILTER
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700202 int32_t texelArea = gglMulx(dtdy, dsdx);
203 if (texelArea < FIXED_ONE && textureObject->mag_filter != GL_LINEAR) {
204 // Non-linear filtering on a texture enlargement.
Mathias Agopian6d2cad22009-06-17 21:18:56 -0700205 LOGD_IF(DEBUG_COPYBIT, "mag filter is not GL_LINEAR");
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700206 return false;
207 }
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700208 if (texelArea > FIXED_ONE && textureObject->min_filter != GL_LINEAR) {
209 // Non-linear filtering on an texture shrink.
Mathias Agopian6d2cad22009-06-17 21:18:56 -0700210 LOGD_IF(DEBUG_COPYBIT, "min filter is not GL_LINEAR");
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700211 return false;
212 }
Mathias Agopianaa6e88b2009-06-17 21:58:18 -0700213#endif
214
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700215 const uint32_t enables = c->rasterizer.state.enables;
216 int planeAlpha = 255;
Mathias Agopian2ad8ec52009-10-27 23:33:48 -0700217 bool alphaPlaneWorkaround = false;
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700218 static const int tmu = 0;
219 texture_t& tev(c->rasterizer.state.texture[tmu]);
Mathias Agopian6dbedd72009-10-16 16:17:58 -0700220 int32_t opFormat = textureObject->surface.format;
221 const bool srcTextureHasAlpha = hasAlpha(opFormat);
Mathias Agopiane7829b82009-06-23 18:31:06 -0700222 if (!srcTextureHasAlpha) {
223 planeAlpha = fixedToByte(c->currentColorClamped.a);
224 }
225
Mathias Agopian6dbedd72009-10-16 16:17:58 -0700226 const bool cbHasAlpha = hasAlpha(cbSurface.format);
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700227 bool blending = false;
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700228 if ((enables & GGL_ENABLE_BLENDING)
229 && !(c->rasterizer.state.blend.src == GL_ONE
230 && c->rasterizer.state.blend.dst == GL_ZERO)) {
231 // Blending is OK if it is
232 // the exact kind of blending that the copybits hardware supports.
233 // Note: The hardware only supports
234 // GL_SRC_ALPHA / GL_ONE_MINUS_SRC_ALPHA,
235 // But the surface flinger uses GL_ONE / GL_ONE_MINUS_SRC_ALPHA.
236 // We substitute GL_SRC_ALPHA / GL_ONE_MINUS_SRC_ALPHA in that case,
237 // because the performance is worth it, even if the results are
238 // not correct.
239 if (!((c->rasterizer.state.blend.src == GL_SRC_ALPHA
240 || c->rasterizer.state.blend.src == GL_ONE)
241 && c->rasterizer.state.blend.dst == GL_ONE_MINUS_SRC_ALPHA
242 && c->rasterizer.state.blend.alpha_separate == 0)) {
243 // Incompatible blend mode.
Mathias Agopian6d2cad22009-06-17 21:18:56 -0700244 LOGD_IF(DEBUG_COPYBIT, "incompatible blend mode");
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700245 return false;
246 }
247 blending = true;
248 } else {
Mathias Agopian6dbedd72009-10-16 16:17:58 -0700249 if (cbHasAlpha) {
250 // NOTE: the result will be slightly wrong in this case because
251 // the destination alpha channel will be set to 1.0 instead of
252 // the iterated alpha value. *shrug*.
253 }
254 // disable plane blending and src blending for supported formats
255 planeAlpha = 255;
256 if (opFormat == COPYBIT_FORMAT_RGBA_8888) {
257 opFormat = COPYBIT_FORMAT_RGBX_8888;
258 } else {
259 if (srcTextureHasAlpha) {
260 LOGD_IF(DEBUG_COPYBIT, "texture format requires blending");
261 return false;
262 }
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700263 }
264 }
265
Mathias Agopian6dbedd72009-10-16 16:17:58 -0700266 switch (tev.env) {
267 case GGL_REPLACE:
268 break;
269 case GGL_MODULATE:
270 // only cases allowed is:
271 // RGB source, color={1,1,1,a} -> can be done with GL_REPLACE
272 // RGBA source, color={1,1,1,1} -> can be done with GL_REPLACE
273 if (blending) {
274 if (c->currentColorClamped.r == c->currentColorClamped.a &&
275 c->currentColorClamped.g == c->currentColorClamped.a &&
276 c->currentColorClamped.b == c->currentColorClamped.a) {
Mathias Agopian2ad8ec52009-10-27 23:33:48 -0700277 // TODO: RGBA source, color={1,1,1,a} / regular-blending
278 // is equivalent
279 alphaPlaneWorkaround = true;
280 break;
Mathias Agopian6dbedd72009-10-16 16:17:58 -0700281 }
282 }
283 LOGD_IF(DEBUG_COPYBIT, "GGL_MODULATE");
284 return false;
285 default:
286 // Incompatible texture environment.
287 LOGD_IF(DEBUG_COPYBIT, "incompatible texture environment");
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700288 return false;
289 }
290
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700291 copybit_device_t* copybit = c->copybits.blitEngine;
Mathias Agopian54ba51d2009-10-26 20:12:37 -0700292 copybit_image_t src;
Mathias Agopian6fee0642009-11-02 17:48:33 -0800293 textureToCopyBitImage(&textureObject->surface, opFormat,
294 textureObject->buffer, &src);
Mathias Agopian54ba51d2009-10-26 20:12:37 -0700295 copybit_rect_t srect = { Ucr, Vcr + Hcr, Ucr + Wcr, Vcr };
296
297 /*
298 * Below we perform extra passes needed to emulate things the h/w
299 * cannot do.
300 */
301
302 const GLfixed minScaleInv = gglDivQ(0x10000, c->copybits.minScale, 16);
303 const GLfixed maxScaleInv = gglDivQ(0x10000, c->copybits.maxScale, 16);
304
305 sp<GraphicBuffer> tempBitmap;
306
307 if (dsdx < maxScaleInv || dsdx > minScaleInv ||
308 dtdy < maxScaleInv || dtdy > minScaleInv)
309 {
310 // The requested scale is out of the range the hardware
311 // can support.
312 LOGD_IF(DEBUG_COPYBIT,
313 "scale out of range dsdx=%08x (Wcr=%d / w=%d), "
314 "dtdy=%08x (Hcr=%d / h=%d), Ucr=%d, Vcr=%d",
315 dsdx, Wcr, w, dtdy, Hcr, h, Ucr, Vcr);
316
317 int32_t xscale=0x10000, yscale=0x10000;
318 if (dsdx > minScaleInv) xscale = c->copybits.minScale;
319 else if (dsdx < maxScaleInv) xscale = c->copybits.maxScale;
320 if (dtdy > minScaleInv) yscale = c->copybits.minScale;
321 else if (dtdy < maxScaleInv) yscale = c->copybits.maxScale;
322 dsdx = gglMulx(dsdx, xscale);
323 dtdy = gglMulx(dtdy, yscale);
324
325 /* we handle only one step of resizing below. Handling an arbitrary
326 * number is relatively easy (replace "if" above by "while"), but requires
327 * two intermediate buffers and so far we never had the need.
328 */
329
330 if (dsdx < maxScaleInv || dsdx > minScaleInv ||
331 dtdy < maxScaleInv || dtdy > minScaleInv) {
332 LOGD_IF(DEBUG_COPYBIT,
333 "scale out of range dsdx=%08x (Wcr=%d / w=%d), "
334 "dtdy=%08x (Hcr=%d / h=%d), Ucr=%d, Vcr=%d",
335 dsdx, Wcr, w, dtdy, Hcr, h, Ucr, Vcr);
336 return false;
337 }
338
339 const int tmp_w = gglMulx(srect.r - srect.l, xscale, 16);
340 const int tmp_h = gglMulx(srect.b - srect.t, yscale, 16);
341
342 LOGD_IF(DEBUG_COPYBIT,
343 "xscale=%08x, yscale=%08x, dsdx=%08x, dtdy=%08x, tmp_w=%d, tmp_h=%d",
344 xscale, yscale, dsdx, dtdy, tmp_w, tmp_h);
345
346 tempBitmap = new GraphicBuffer(
347 tmp_w, tmp_h, src.format,
348 GraphicBuffer::USAGE_HW_2D);
349
Mathias Agopian2ad8ec52009-10-27 23:33:48 -0700350 err = tempBitmap->initCheck();
Mathias Agopian54ba51d2009-10-26 20:12:37 -0700351 if (err == NO_ERROR) {
352 copybit_image_t tmp_dst;
353 copybit_rect_t tmp_rect;
354 tmp_dst.w = tmp_w;
355 tmp_dst.h = tmp_h;
Mathias Agopian2ad8ec52009-10-27 23:33:48 -0700356 tmp_dst.format = tempBitmap->format;
Mathias Agopian54ba51d2009-10-26 20:12:37 -0700357 tmp_dst.handle = (native_handle_t*)tempBitmap->getNativeBuffer()->handle;
358 tmp_rect.l = 0;
359 tmp_rect.t = 0;
360 tmp_rect.r = tmp_dst.w;
361 tmp_rect.b = tmp_dst.h;
362 region_iterator tmp_it(Region(Rect(tmp_rect.r, tmp_rect.b)));
363 copybit->set_parameter(copybit, COPYBIT_TRANSFORM, 0);
364 copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, 0xFF);
365 copybit->set_parameter(copybit, COPYBIT_DITHER, COPYBIT_DISABLE);
366 err = copybit->stretch(copybit,
367 &tmp_dst, &src, &tmp_rect, &srect, &tmp_it);
368 src = tmp_dst;
369 srect = tmp_rect;
370 }
371 }
Mathias Agopian0a3139a2009-06-10 16:01:54 -0700372
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700373 copybit_image_t dst;
Mathias Agopian6fee0642009-11-02 17:48:33 -0800374 textureToCopyBitImage(&cbSurface, cbSurface.format,
375 c->copybits.drawSurfaceBuffer, &dst);
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700376 copybit_rect_t drect = {x, y, x+w, y+h};
377
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700378
Mathias Agopian2ad8ec52009-10-27 23:33:48 -0700379 /* and now the alpha-plane hack. This handles the "Fade" case of a
380 * texture with an alpha channel.
381 */
382 if (alphaPlaneWorkaround) {
383 sp<GraphicBuffer> tempCb = new GraphicBuffer(
384 w, h, COPYBIT_FORMAT_RGB_565,
385 GraphicBuffer::USAGE_HW_2D);
386
387 err = tempCb->initCheck();
388
389 copybit_image_t tmpCbImg;
390 copybit_rect_t tmpCbRect;
Mathias Agopian19834032009-11-09 17:55:59 -0800391 copybit_rect_t tmpdrect = drect;
Mathias Agopian2ad8ec52009-10-27 23:33:48 -0700392 tmpCbImg.w = w;
393 tmpCbImg.h = h;
394 tmpCbImg.format = tempCb->format;
395 tmpCbImg.handle = (native_handle_t*)tempCb->getNativeBuffer()->handle;
396 tmpCbRect.l = 0;
397 tmpCbRect.t = 0;
Mathias Agopian19834032009-11-09 17:55:59 -0800398
399 if (drect.l < 0) {
400 tmpCbRect.l = -tmpdrect.l;
401 tmpdrect.l = 0;
402 }
403 if (drect.t < 0) {
404 tmpCbRect.t = -tmpdrect.t;
405 tmpdrect.t = 0;
406 }
407 if (drect.l + tmpCbImg.w > dst.w) {
408 tmpCbImg.w = dst.w - drect.l;
409 tmpdrect.r = dst.w;
410 }
411 if (drect.t + tmpCbImg.h > dst.h) {
412 tmpCbImg.h = dst.h - drect.t;
413 tmpdrect.b = dst.h;
414 }
415
416 tmpCbRect.r = tmpCbImg.w;
417 tmpCbRect.b = tmpCbImg.h;
Mathias Agopian2ad8ec52009-10-27 23:33:48 -0700418
419 if (!err) {
420 // first make a copy of the destination buffer
421 region_iterator tmp_it(Region(Rect(w, h)));
422 copybit->set_parameter(copybit, COPYBIT_TRANSFORM, 0);
423 copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, 0xFF);
424 copybit->set_parameter(copybit, COPYBIT_DITHER, COPYBIT_DISABLE);
425 err = copybit->stretch(copybit,
Mathias Agopian19834032009-11-09 17:55:59 -0800426 &tmpCbImg, &dst, &tmpCbRect, &tmpdrect, &tmp_it);
Mathias Agopian2ad8ec52009-10-27 23:33:48 -0700427 }
428 if (!err) {
429 // then proceed as usual, but without the alpha plane
430 copybit->set_parameter(copybit, COPYBIT_TRANSFORM, transform);
431 copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, 0xFF);
432 copybit->set_parameter(copybit, COPYBIT_DITHER,
433 (enables & GGL_ENABLE_DITHER) ?
434 COPYBIT_ENABLE : COPYBIT_DISABLE);
435 clipRectRegion it(c);
436 err = copybit->stretch(copybit, &dst, &src, &drect, &srect, &it);
437 }
438 if (!err) {
439 // finally copy back the destination on top with 1-alphaplane
440 int invPlaneAlpha = 0xFF - fixedToByte(c->currentColorClamped.a);
441 clipRectRegion it(c);
442 copybit->set_parameter(copybit, COPYBIT_TRANSFORM, 0);
443 copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, invPlaneAlpha);
444 copybit->set_parameter(copybit, COPYBIT_DITHER, COPYBIT_ENABLE);
445 err = copybit->stretch(copybit,
Mathias Agopian19834032009-11-09 17:55:59 -0800446 &dst, &tmpCbImg, &tmpdrect, &tmpCbRect, &it);
Mathias Agopian2ad8ec52009-10-27 23:33:48 -0700447 }
448 } else {
449 copybit->set_parameter(copybit, COPYBIT_TRANSFORM, transform);
450 copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, planeAlpha);
451 copybit->set_parameter(copybit, COPYBIT_DITHER,
452 (enables & GGL_ENABLE_DITHER) ?
453 COPYBIT_ENABLE : COPYBIT_DISABLE);
454 clipRectRegion it(c);
Mathias Agopiandf2d9292009-10-28 21:00:29 -0700455
Iliyan Malchevd95c3222009-10-30 18:29:08 -0700456 LOGD_IF(0,
457 "dst={%d, %d, %d, %p, %p}, "
Mathias Agopiandf2d9292009-10-28 21:00:29 -0700458 "src={%d, %d, %d, %p, %p}, "
459 "drect={%d,%d,%d,%d}, "
460 "srect={%d,%d,%d,%d}, "
461 "it={%d,%d,%d,%d}, " ,
462 dst.w, dst.h, dst.format, dst.base, dst.handle,
463 src.w, src.h, src.format, src.base, src.handle,
464 drect.l, drect.t, drect.r, drect.b,
465 srect.l, srect.t, srect.r, srect.b,
466 it.r.l, it.r.t, it.r.r, it.r.b
467 );
468
Mathias Agopian2ad8ec52009-10-27 23:33:48 -0700469 err = copybit->stretch(copybit, &dst, &src, &drect, &srect, &it);
470 }
Mathias Agopianf13901e2009-07-15 18:53:32 -0700471 if (err != NO_ERROR) {
472 c->textures.tmu[0].texture->try_copybit = false;
473 }
Mathias Agopian295eff22009-06-29 16:36:49 -0700474 return err == NO_ERROR ? true : false;
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700475}
476
477/*
478 * Try to draw a triangle fan with copybit, return false if we fail.
479 */
Mathias Agopian6d2cad22009-06-17 21:18:56 -0700480bool drawTriangleFanWithCopybit_impl(ogles_context_t* c, GLint first, GLsizei count)
481{
482 if (!checkContext(c)) {
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700483 return false;
484 }
485
Mathias Agopian7272add2009-06-18 19:31:07 -0700486 // FIXME: we should handle culling here
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700487 c->arrays.compileElements(c, c->vc.vBuffer, 0, 4);
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700488
Mathias Agopian6d2cad22009-06-17 21:18:56 -0700489 // we detect if we're dealing with a rectangle, by comparing the
490 // rectangles {v0,v2} and {v1,v3} which should be identical.
491
Mathias Agopianaa6e88b2009-06-17 21:58:18 -0700492 // NOTE: we should check that the rectangle is window aligned, however
493 // if we do that, the optimization won't be taken in a lot of cases.
494 // Since this code is intended to be used with SurfaceFlinger only,
495 // so it's okay...
496
Mathias Agopian6d2cad22009-06-17 21:18:56 -0700497 const vec4_t& v0 = c->vc.vBuffer[0].window;
498 const vec4_t& v1 = c->vc.vBuffer[1].window;
499 const vec4_t& v2 = c->vc.vBuffer[2].window;
500 const vec4_t& v3 = c->vc.vBuffer[3].window;
501 int l = min(v0.x, v2.x);
502 int b = min(v0.y, v2.y);
503 int r = max(v0.x, v2.x);
504 int t = max(v0.y, v2.y);
505 if ((l != min(v1.x, v3.x)) || (b != min(v1.y, v3.y)) ||
506 (r != max(v1.x, v3.x)) || (t != max(v1.y, v3.y))) {
507 LOGD_IF(DEBUG_COPYBIT, "geometry not a rectangle");
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700508 return false;
509 }
Mathias Agopian7272add2009-06-18 19:31:07 -0700510
511 // fetch and transform texture coordinates
512 // NOTE: maybe it would be better to have a "compileElementsAll" method
513 // that would ensure all vertex data are fetched and transformed
514 const transform_t& tr = c->transforms.texture[0].transform;
515 for (size_t i=0 ; i<4 ; i++) {
516 const GLubyte* tp = c->arrays.texture[0].element(i);
517 vertex_t* const v = &c->vc.vBuffer[i];
518 c->arrays.texture[0].fetch(c, v->texture[0].v, tp);
519 // FIXME: we should bail if q!=1
520 c->arrays.tex_transform[0](&tr, &v->texture[0], &v->texture[0]);
521 }
Mathias Agopian6d2cad22009-06-17 21:18:56 -0700522
523 const vec4_t& t0 = c->vc.vBuffer[0].texture[0];
524 const vec4_t& t1 = c->vc.vBuffer[1].texture[0];
525 const vec4_t& t2 = c->vc.vBuffer[2].texture[0];
526 const vec4_t& t3 = c->vc.vBuffer[3].texture[0];
527 int txl = min(t0.x, t2.x);
528 int txb = min(t0.y, t2.y);
529 int txr = max(t0.x, t2.x);
530 int txt = max(t0.y, t2.y);
531 if ((txl != min(t1.x, t3.x)) || (txb != min(t1.y, t3.y)) ||
532 (txr != max(t1.x, t3.x)) || (txt != max(t1.y, t3.y))) {
533 LOGD_IF(DEBUG_COPYBIT, "texcoord not a rectangle");
534 return false;
535 }
536 if ((txl != 0) || (txb != 0) ||
537 (txr != FIXED_ONE) || (txt != FIXED_ONE)) {
538 // we could probably handle this case, if we wanted to
Mathias Agopian7272add2009-06-18 19:31:07 -0700539 LOGD_IF(DEBUG_COPYBIT, "texture is cropped: %08x,%08x,%08x,%08x",
540 txl, txb, txr, txt);
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700541 return false;
542 }
543
Mathias Agopian6d2cad22009-06-17 21:18:56 -0700544 // at this point, we know we are dealing with a rectangle, so we
545 // only need to consider 3 vertices for computing the jacobians
546
547 const int dx01 = v1.x - v0.x;
Mathias Agopian6d2cad22009-06-17 21:18:56 -0700548 const int dx02 = v2.x - v0.x;
Mathias Agopian295eff22009-06-29 16:36:49 -0700549 const int dy01 = v1.y - v0.y;
Mathias Agopian6d2cad22009-06-17 21:18:56 -0700550 const int dy02 = v2.y - v0.y;
551 const int ds01 = t1.S - t0.S;
Mathias Agopian6d2cad22009-06-17 21:18:56 -0700552 const int ds02 = t2.S - t0.S;
Mathias Agopian295eff22009-06-29 16:36:49 -0700553 const int dt01 = t1.T - t0.T;
Mathias Agopian6d2cad22009-06-17 21:18:56 -0700554 const int dt02 = t2.T - t0.T;
555 const int area = dx01*dy02 - dy01*dx02;
556 int dsdx, dsdy, dtdx, dtdy;
557 if (area >= 0) {
558 dsdx = ds01*dy02 - ds02*dy01;
Mathias Agopian6d2cad22009-06-17 21:18:56 -0700559 dtdx = dt01*dy02 - dt02*dy01;
Mathias Agopian295eff22009-06-29 16:36:49 -0700560 dsdy = ds02*dx01 - ds01*dx02;
Mathias Agopian6d2cad22009-06-17 21:18:56 -0700561 dtdy = dt02*dx01 - dt01*dx02;
562 } else {
563 dsdx = ds02*dy01 - ds01*dy02;
Mathias Agopian6d2cad22009-06-17 21:18:56 -0700564 dtdx = dt02*dy01 - dt01*dy02;
Mathias Agopian295eff22009-06-29 16:36:49 -0700565 dsdy = ds01*dx02 - ds02*dx01;
Mathias Agopian6d2cad22009-06-17 21:18:56 -0700566 dtdy = dt01*dx02 - dt02*dx01;
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700567 }
568
Mathias Agopian6d2cad22009-06-17 21:18:56 -0700569 // here we rely on the fact that we know the transform is
570 // a rigid-body transform AND that it can only rotate in 90 degrees
571 // increments
572
573 int transform = 0;
574 if (dsdx == 0) {
575 // 90 deg rotation case
576 // [ 0 dtdx ]
577 // [ dsdx 0 ]
578 transform |= COPYBIT_TRANSFORM_ROT_90;
579 // FIXME: not sure if FLIP_H and FLIP_V shouldn't be inverted
580 if (dtdx > 0)
581 transform |= COPYBIT_TRANSFORM_FLIP_H;
582 if (dsdy < 0)
583 transform |= COPYBIT_TRANSFORM_FLIP_V;
584 } else {
585 // [ dsdx 0 ]
586 // [ 0 dtdy ]
587 if (dsdx < 0)
588 transform |= COPYBIT_TRANSFORM_FLIP_H;
589 if (dtdy < 0)
590 transform |= COPYBIT_TRANSFORM_FLIP_V;
591 }
592
593 //LOGD("l=%d, b=%d, w=%d, h=%d, tr=%d", x, y, w, h, transform);
594 //LOGD("A=%f\tB=%f\nC=%f\tD=%f",
595 // dsdx/65536.0, dtdx/65536.0, dsdy/65536.0, dtdy/65536.0);
596
597 int x = l >> 4;
598 int y = b >> 4;
599 int w = (r-l) >> 4;
600 int h = (t-b) >> 4;
601 texture_unit_t& u(c->textures.tmu[0]);
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700602 EGLTextureObject* textureObject = u.texture;
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700603 GLint tWidth = textureObject->surface.width;
604 GLint tHeight = textureObject->surface.height;
605 GLint crop_rect[4] = {0, tHeight, tWidth, -tHeight};
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700606 const GGLSurface& cbSurface = c->rasterizer.state.buffers.color.s;
607 y = cbSurface.height - (y + h);
Mathias Agopian6d2cad22009-06-17 21:18:56 -0700608 return copybit(x, y, w, h, textureObject, crop_rect, transform, c);
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700609}
610
611/*
612 * Try to drawTexiOESWithCopybit, return false if we fail.
613 */
614
615bool drawTexiOESWithCopybit_impl(GLint x, GLint y, GLint z,
616 GLint w, GLint h, ogles_context_t* c)
617{
618 // quickly process empty rects
619 if ((w|h) <= 0) {
620 return true;
621 }
Mathias Agopian6d2cad22009-06-17 21:18:56 -0700622 if (!checkContext(c)) {
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700623 return false;
624 }
Mathias Agopian6d2cad22009-06-17 21:18:56 -0700625 texture_unit_t& u(c->textures.tmu[0]);
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700626 EGLTextureObject* textureObject = u.texture;
Mathias Agopian6d2cad22009-06-17 21:18:56 -0700627 return copybit(x, y, w, h, textureObject, textureObject->crop_rect, 0, c);
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700628}
629
630} // namespace android
631