s/w OpenGL no detects and handles all any combinations of triangle fans corresponding to a rectangle
this allows fallback to faster copybit code in almost all cases.
diff --git a/opengl/libagl/copybit.cpp b/opengl/libagl/copybit.cpp
index d57a6e4..0736b6b 100644
--- a/opengl/libagl/copybit.cpp
+++ b/opengl/libagl/copybit.cpp
@@ -34,6 +34,9 @@
#include <private/ui/android_natives_priv.h>
#include "gralloc_priv.h"
+
+#define DEBUG_COPYBIT true
+
// ----------------------------------------------------------------------------
namespace android {
@@ -114,9 +117,14 @@
// By convention copybitQuickCheckContext() has already returned true.
// avoid checking the same information again.
- if (c->copybits.blitEngine == NULL
- || (c->rasterizer.state.enables
- & (GGL_ENABLE_DEPTH_TEST|GGL_ENABLE_FOG)) != 0) {
+ if (c->copybits.blitEngine == NULL) {
+ LOGD_IF(DEBUG_COPYBIT, "no copybit hal");
+ return false;
+ }
+
+ if (c->rasterizer.state.enables
+ & (GGL_ENABLE_DEPTH_TEST|GGL_ENABLE_FOG)) {
+ LOGD_IF(DEBUG_COPYBIT, "depth test and/or fog");
return false;
}
@@ -129,6 +137,7 @@
EGLTextureObject* textureObject = u.texture;
if (!supportedCopybitsFormat(textureObject->surface.format)) {
+ LOGD_IF(DEBUG_COPYBIT, "texture format not supported");
return false;
}
return true;
@@ -161,19 +170,25 @@
|| dtdy < c->copybits.minScale || dtdy > c->copybits.maxScale) {
// The requested scale is out of the range the hardware
// can support.
+ LOGD_IF(DEBUG_COPYBIT,
+ "scale out of range dsdx=%08x, dtdy=%08x", dsdx, dtdy);
return false;
}
+ /*
int32_t texelArea = gglMulx(dtdy, dsdx);
if (texelArea < FIXED_ONE && textureObject->mag_filter != GL_LINEAR) {
// Non-linear filtering on a texture enlargement.
+ LOGD_IF(DEBUG_COPYBIT, "mag filter is not GL_LINEAR");
return false;
}
if (texelArea > FIXED_ONE && textureObject->min_filter != GL_LINEAR) {
// Non-linear filtering on an texture shrink.
+ LOGD_IF(DEBUG_COPYBIT, "min filter is not GL_LINEAR");
return false;
}
+ */
const uint32_t enables = c->rasterizer.state.enables;
int planeAlpha = 255;
@@ -192,6 +207,7 @@
if (! (c->currentColorClamped.r == FIXED_ONE
&& c->currentColorClamped.g == FIXED_ONE
&& c->currentColorClamped.b == FIXED_ONE)) {
+ LOGD_IF(DEBUG_COPYBIT, "MODULATE and non white color");
return false;
}
planeAlpha = fixedToByte(c->currentColorClamped.a);
@@ -199,6 +215,7 @@
default:
// Incompatible texture environment.
+ LOGD_IF(DEBUG_COPYBIT, "incompatible texture environment");
return false;
}
@@ -220,6 +237,7 @@
&& c->rasterizer.state.blend.dst == GL_ONE_MINUS_SRC_ALPHA
&& c->rasterizer.state.blend.alpha_separate == 0)) {
// Incompatible blend mode.
+ LOGD_IF(DEBUG_COPYBIT, "incompatible blend mode");
return false;
}
blending = true;
@@ -227,12 +245,14 @@
// No blending is OK if we are not using alpha.
if (srcTextureHasAlpha || planeAlpha != 255) {
// Incompatible alpha
+ LOGD_IF(DEBUG_COPYBIT, "incompatible alpha");
return false;
}
}
if (srcTextureHasAlpha && planeAlpha != 255) {
// Can't do two types of alpha at once.
+ LOGD_IF(DEBUG_COPYBIT, "src alpha and plane alpha");
return false;
}
@@ -264,86 +284,116 @@
/*
* Try to draw a triangle fan with copybit, return false if we fail.
*/
-bool drawTrangleFanWithCopybit_impl(ogles_context_t* c, GLint first, GLsizei count) {
- if (! checkContext(c)) {
+bool drawTriangleFanWithCopybit_impl(ogles_context_t* c, GLint first, GLsizei count)
+{
+ if (!checkContext(c)) {
return false;
}
c->arrays.compileElements(c, c->vc.vBuffer, 0, 4);
- // Is the result a screen aligned rectangle?
- int sx[4];
- int sy[4];
- for (int i = 0; i < 4; i++) {
- GLfixed x = c->vc.vBuffer[i].window.x;
- GLfixed y = c->vc.vBuffer[i].window.y;
- if (x < 0 || y < 0 || (x & 0xf) != 0 || (y & 0xf) != 0) {
- return false;
- }
- sx[i] = x >> 4;
- sy[i] = y >> 4;
- }
- /*
- * This is the pattern we're looking for:
- * (2)--(3)
- * |\ |
- * | \ |
- * | \ |
- * | \|
- * (1)--(0)
- *
- */
- int dx[4];
- int dy[4];
- for (int i = 0; i < 4; i++) {
- int i1 = (i + 1) & 3;
- dx[i] = sx[i] - sx[i1];
- dy[i] = sy[i] - sy[i1];
- }
- if (dx[1] | dx[3] | dy[0] | dy[2]) {
+ // we detect if we're dealing with a rectangle, by comparing the
+ // rectangles {v0,v2} and {v1,v3} which should be identical.
+
+ const vec4_t& v0 = c->vc.vBuffer[0].window;
+ const vec4_t& v1 = c->vc.vBuffer[1].window;
+ const vec4_t& v2 = c->vc.vBuffer[2].window;
+ const vec4_t& v3 = c->vc.vBuffer[3].window;
+ int l = min(v0.x, v2.x);
+ int b = min(v0.y, v2.y);
+ int r = max(v0.x, v2.x);
+ int t = max(v0.y, v2.y);
+ if ((l != min(v1.x, v3.x)) || (b != min(v1.y, v3.y)) ||
+ (r != max(v1.x, v3.x)) || (t != max(v1.y, v3.y))) {
+ LOGD_IF(DEBUG_COPYBIT, "geometry not a rectangle");
return false;
}
- if (dx[0] != -dx[2] || dy[1] != -dy[3]) {
+
+ const vec4_t& t0 = c->vc.vBuffer[0].texture[0];
+ const vec4_t& t1 = c->vc.vBuffer[1].texture[0];
+ const vec4_t& t2 = c->vc.vBuffer[2].texture[0];
+ const vec4_t& t3 = c->vc.vBuffer[3].texture[0];
+ int txl = min(t0.x, t2.x);
+ int txb = min(t0.y, t2.y);
+ int txr = max(t0.x, t2.x);
+ int txt = max(t0.y, t2.y);
+ if ((txl != min(t1.x, t3.x)) || (txb != min(t1.y, t3.y)) ||
+ (txr != max(t1.x, t3.x)) || (txt != max(t1.y, t3.y))) {
+ LOGD_IF(DEBUG_COPYBIT, "texcoord not a rectangle");
+ return false;
+ }
+ if ((txl != 0) || (txb != 0) ||
+ (txr != FIXED_ONE) || (txt != FIXED_ONE)) {
+ // we could probably handle this case, if we wanted to
+ LOGD_IF(DEBUG_COPYBIT, "texture is cropped");
return false;
}
- int x = sx[1];
- int y = sy[1];
- int w = dx[0];
- int h = dy[3];
-
- // We expect the texture coordinates to always be the unit square:
-
- static const GLfixed kExpectedUV[8] = {
- 0, 0,
- 0, FIXED_ONE,
- FIXED_ONE, FIXED_ONE,
- FIXED_ONE, 0
- };
- {
- const GLfixed* pExpected = &kExpectedUV[0];
- for (int i = 0; i < 4; i++) {
- GLfixed u = c->vc.vBuffer[i].texture[0].x;
- GLfixed v = c->vc.vBuffer[i].texture[0].y;
- if (u != *pExpected++ || v != *pExpected++) {
- return false;
- }
- }
+ // at this point, we know we are dealing with a rectangle, so we
+ // only need to consider 3 vertices for computing the jacobians
+
+ const int dx01 = v1.x - v0.x;
+ const int dy01 = v1.y - v0.y;
+ const int dx02 = v2.x - v0.x;
+ const int dy02 = v2.y - v0.y;
+ const int ds01 = t1.S - t0.S;
+ const int dt01 = t1.T - t0.T;
+ const int ds02 = t2.S - t0.S;
+ const int dt02 = t2.T - t0.T;
+ const int area = dx01*dy02 - dy01*dx02;
+ int dsdx, dsdy, dtdx, dtdy;
+ if (area >= 0) {
+ dsdx = ds01*dy02 - ds02*dy01;
+ dsdy = ds02*dx01 - ds01*dx02;
+ dtdx = dt01*dy02 - dt02*dy01;
+ dtdy = dt02*dx01 - dt01*dx02;
+ } else {
+ dsdx = ds02*dy01 - ds01*dy02;
+ dsdy = ds01*dx02 - ds02*dx01;
+ dtdx = dt02*dy01 - dt01*dy02;
+ dtdy = dt01*dx02 - dt02*dx01;
}
- static const int tmu = 0;
- texture_unit_t& u(c->textures.tmu[tmu]);
+ // here we rely on the fact that we know the transform is
+ // a rigid-body transform AND that it can only rotate in 90 degrees
+ // increments
+
+ int transform = 0;
+ if (dsdx == 0) {
+ // 90 deg rotation case
+ // [ 0 dtdx ]
+ // [ dsdx 0 ]
+ transform |= COPYBIT_TRANSFORM_ROT_90;
+ // FIXME: not sure if FLIP_H and FLIP_V shouldn't be inverted
+ if (dtdx > 0)
+ transform |= COPYBIT_TRANSFORM_FLIP_H;
+ if (dsdy < 0)
+ transform |= COPYBIT_TRANSFORM_FLIP_V;
+ } else {
+ // [ dsdx 0 ]
+ // [ 0 dtdy ]
+ if (dsdx < 0)
+ transform |= COPYBIT_TRANSFORM_FLIP_H;
+ if (dtdy < 0)
+ transform |= COPYBIT_TRANSFORM_FLIP_V;
+ }
+
+ //LOGD("l=%d, b=%d, w=%d, h=%d, tr=%d", x, y, w, h, transform);
+ //LOGD("A=%f\tB=%f\nC=%f\tD=%f",
+ // dsdx/65536.0, dtdx/65536.0, dsdy/65536.0, dtdy/65536.0);
+
+ int x = l >> 4;
+ int y = b >> 4;
+ int w = (r-l) >> 4;
+ int h = (t-b) >> 4;
+ texture_unit_t& u(c->textures.tmu[0]);
EGLTextureObject* textureObject = u.texture;
-
GLint tWidth = textureObject->surface.width;
GLint tHeight = textureObject->surface.height;
GLint crop_rect[4] = {0, tHeight, tWidth, -tHeight};
-
const GGLSurface& cbSurface = c->rasterizer.state.buffers.color.s;
y = cbSurface.height - (y + h);
-
- return copybit(x, y, w, h, textureObject, crop_rect,
- COPYBIT_TRANSFORM_ROT_90, c);
+ return copybit(x, y, w, h, textureObject, crop_rect, transform, c);
}
/*
@@ -357,17 +407,12 @@
if ((w|h) <= 0) {
return true;
}
-
- if (! checkContext(c)) {
+ if (!checkContext(c)) {
return false;
}
-
- static const int tmu = 0;
- texture_unit_t& u(c->textures.tmu[tmu]);
+ texture_unit_t& u(c->textures.tmu[0]);
EGLTextureObject* textureObject = u.texture;
-
- return copybit(x, y, w, h, textureObject, textureObject->crop_rect,
- 0, c);
+ return copybit(x, y, w, h, textureObject, textureObject->crop_rect, 0, c);
}
} // namespace android