• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 #include "TextureObjectManager.h"
31 
32 #include <hardware/gralloc.h>
33 #include <hardware/copybit.h>
34 #include <private/ui/android_natives_priv.h>
35 
36 #include <ui/GraphicBuffer.h>
37 #include <ui/Region.h>
38 #include <ui/Rect.h>
39 
40 
41 #define DEBUG_COPYBIT true
42 
43 // ----------------------------------------------------------------------------
44 
45 namespace android {
46 
textureToCopyBitImage(const GGLSurface * surface,int32_t opFormat,android_native_buffer_t * buffer,copybit_image_t * img)47 static void textureToCopyBitImage(
48         const GGLSurface* surface, int32_t opFormat,
49         android_native_buffer_t* buffer, copybit_image_t* img)
50 {
51     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 
62     img->w      = surface->stride;
63     img->h      = vstride ? vstride : surface->height;
64     img->format = opFormat;
65     img->base   = surface->data;
66     img->handle = (native_handle_t *)buffer->handle;
67 }
68 
69 struct clipRectRegion : public copybit_region_t {
clipRectRegionandroid::clipRectRegion70     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;
78     }
79 private:
iterateandroid::clipRectRegion80     static int iterate(copybit_region_t const * self, copybit_rect_t* rect) {
81         *rect = static_cast<clipRectRegion const*>(self)->r;
82         const_cast<copybit_region_t *>(self)->next = iterate_done;
83         return 1;
84     }
iterate_doneandroid::clipRectRegion85     static int iterate_done(copybit_region_t const *, copybit_rect_t*) {
86         return 0;
87     }
88 public:
89     copybit_rect_t r;
90 };
91 
supportedCopybitsFormat(int format)92 static bool supportedCopybitsFormat(int format) {
93     switch (format) {
94     case COPYBIT_FORMAT_RGBA_8888:
95     case COPYBIT_FORMAT_RGBX_8888:
96     case COPYBIT_FORMAT_RGB_888:
97     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 
hasAlpha(int format)109 static 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 
fixedToByte(GGLfixed val)121 static 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 
checkContext(ogles_context_t * c)130 static bool checkContext(ogles_context_t* c) {
131 
132 	// By convention copybitQuickCheckContext() has already returned true.
133 	// avoid checking the same information again.
134 
135     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");
143         return false;
144     }
145 
146     // Note: The drawSurfaceBuffer is only set for destination
147     // 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)) {
155         LOGD_IF(DEBUG_COPYBIT, "texture format not supported");
156         return false;
157     }
158     return true;
159 }
160 
161 
copybit(GLint x,GLint y,GLint w,GLint h,EGLTextureObject * textureObject,const GLint * crop_rect,int transform,ogles_context_t * c)162 static 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 {
169     status_t err = NO_ERROR;
170 
171     // 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 
183     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
187     if (transform & COPYBIT_TRANSFORM_ROT_90) {
188         swap(screen_w, screen_h);
189     }
190     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
196 
197     // 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
202     int32_t texelArea = gglMulx(dtdy, dsdx);
203     if (texelArea < FIXED_ONE && textureObject->mag_filter != GL_LINEAR) {
204         // Non-linear filtering on a texture enlargement.
205         LOGD_IF(DEBUG_COPYBIT, "mag filter is not GL_LINEAR");
206         return false;
207     }
208     if (texelArea > FIXED_ONE && textureObject->min_filter != GL_LINEAR) {
209         // Non-linear filtering on an texture shrink.
210         LOGD_IF(DEBUG_COPYBIT, "min filter is not GL_LINEAR");
211         return false;
212     }
213 #endif
214 
215     const uint32_t enables = c->rasterizer.state.enables;
216     int planeAlpha = 255;
217     bool alphaPlaneWorkaround = false;
218     static const int tmu = 0;
219     texture_t& tev(c->rasterizer.state.texture[tmu]);
220     int32_t opFormat = textureObject->surface.format;
221     const bool srcTextureHasAlpha = hasAlpha(opFormat);
222     if (!srcTextureHasAlpha) {
223         planeAlpha = fixedToByte(c->currentColorClamped.a);
224     }
225 
226     const bool cbHasAlpha = hasAlpha(cbSurface.format);
227     bool blending = false;
228     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.
244             LOGD_IF(DEBUG_COPYBIT, "incompatible blend mode");
245             return false;
246         }
247         blending = true;
248     } else {
249         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             }
263         }
264     }
265 
266     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) {
277                 // TODO: RGBA source, color={1,1,1,a} / regular-blending
278                 // is equivalent
279                 alphaPlaneWorkaround = true;
280                 break;
281             }
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");
288         return false;
289     }
290 
291     copybit_device_t* copybit = c->copybits.blitEngine;
292     copybit_image_t src;
293     textureToCopyBitImage(&textureObject->surface, opFormat,
294             textureObject->buffer, &src);
295     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 
350         err = tempBitmap->initCheck();
351         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;
356             tmp_dst.format = tempBitmap->format;
357             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     }
372 
373     copybit_image_t dst;
374     textureToCopyBitImage(&cbSurface, cbSurface.format,
375             c->copybits.drawSurfaceBuffer, &dst);
376     copybit_rect_t drect = {x, y, x+w, y+h};
377 
378 
379     /* 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;
391         copybit_rect_t tmpdrect = drect;
392         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;
398 
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;
418 
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,
426                     &tmpCbImg, &dst, &tmpCbRect, &tmpdrect, &tmp_it);
427         }
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,
446                     &dst, &tmpCbImg, &tmpdrect, &tmpCbRect, &it);
447         }
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);
455 
456         LOGD_IF(0,
457              "dst={%d, %d, %d, %p, %p}, "
458              "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 
469         err = copybit->stretch(copybit, &dst, &src, &drect, &srect, &it);
470     }
471     if (err != NO_ERROR) {
472         c->textures.tmu[0].texture->try_copybit = false;
473     }
474     return err == NO_ERROR ? true : false;
475 }
476 
477 /*
478  * Try to draw a triangle fan with copybit, return false if we fail.
479  */
drawTriangleFanWithCopybit_impl(ogles_context_t * c,GLint first,GLsizei count)480 bool drawTriangleFanWithCopybit_impl(ogles_context_t* c, GLint first, GLsizei count)
481 {
482     if (!checkContext(c)) {
483         return false;
484     }
485 
486     // FIXME: we should handle culling  here
487     c->arrays.compileElements(c, c->vc.vBuffer, 0, 4);
488 
489     // we detect if we're dealing with a rectangle, by comparing the
490     // rectangles {v0,v2} and {v1,v3} which should be identical.
491 
492     // 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 
497     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");
508         return false;
509     }
510 
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     }
522 
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
539         LOGD_IF(DEBUG_COPYBIT, "texture is cropped: %08x,%08x,%08x,%08x",
540                 txl, txb, txr, txt);
541         return false;
542     }
543 
544     // 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;
548     const int dx02 = v2.x - v0.x;
549     const int dy01 = v1.y - v0.y;
550     const int dy02 = v2.y - v0.y;
551     const int ds01 = t1.S - t0.S;
552     const int ds02 = t2.S - t0.S;
553     const int dt01 = t1.T - t0.T;
554     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;
559         dtdx = dt01*dy02 - dt02*dy01;
560         dsdy = ds02*dx01 - ds01*dx02;
561         dtdy = dt02*dx01 - dt01*dx02;
562     } else {
563         dsdx = ds02*dy01 - ds01*dy02;
564         dtdx = dt02*dy01 - dt01*dy02;
565         dsdy = ds01*dx02 - ds02*dx01;
566         dtdy = dt01*dx02 - dt02*dx01;
567     }
568 
569     // 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]);
602     EGLTextureObject* textureObject = u.texture;
603     GLint tWidth = textureObject->surface.width;
604     GLint tHeight = textureObject->surface.height;
605     GLint crop_rect[4] = {0, tHeight, tWidth, -tHeight};
606     const GGLSurface& cbSurface = c->rasterizer.state.buffers.color.s;
607     y = cbSurface.height - (y + h);
608     return copybit(x, y, w, h, textureObject, crop_rect, transform, c);
609 }
610 
611 /*
612  * Try to drawTexiOESWithCopybit, return false if we fail.
613  */
614 
drawTexiOESWithCopybit_impl(GLint x,GLint y,GLint z,GLint w,GLint h,ogles_context_t * c)615 bool 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     }
622     if (!checkContext(c)) {
623         return false;
624     }
625     texture_unit_t& u(c->textures.tmu[0]);
626     EGLTextureObject* textureObject = u.texture;
627     return copybit(x, y, w, h, textureObject, textureObject->crop_rect, 0, c);
628 }
629 
630 } // namespace android
631 
632