Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6d2cad2c authored by Mathias Agopian's avatar Mathias Agopian
Browse files

s/w OpenGL no detects and handles all any combinations of triangle fans...

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.
parent cf251b9e
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -708,7 +708,7 @@ void drawPrimitivesTriangleStrip(ogles_context_t* c,
void drawPrimitivesTriangleFan(ogles_context_t* c,
        GLint first, GLsizei count) {
#ifdef LIBAGL_USE_GRALLOC_COPYBITS
    if (drawTrangleFanWithCopybit(c, first, count)) {
    if (drawTriangleFanWithCopybit(c, first, count)) {
        return;
    }
#endif // LIBAGL_USE_GRALLOC_COPYBITS
+116 −71
Original line number Diff line number Diff line
@@ -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 @@ static bool checkContext(ogles_context_t* c) {
	// 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 @@ static bool checkContext(ogles_context_t* c) {
    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 @@ static bool copybit(GLint x, GLint y,
            || 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 @@ static bool copybit(GLint x, GLint y,
        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 @@ static bool copybit(GLint x, GLint y,

    default:
        // Incompatible texture environment.
        LOGD_IF(DEBUG_COPYBIT, "incompatible texture environment");
        return false;
    }

@@ -220,6 +237,7 @@ static bool copybit(GLint x, GLint y,
                && 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 @@ static bool copybit(GLint x, GLint y,
        // 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 @@ static bool copybit(GLint x, GLint y,
/*
 * Try to draw a triangle fan with copybit, return false if we fail.
 */
bool drawTrangleFanWithCopybit_impl(ogles_context_t* c, GLint first, GLsizei count) {
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]) {
        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++) {
    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;
    }

    static const int tmu = 0;
    texture_unit_t& u(c->textures.tmu[tmu]);
    // 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;
    }

    // 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 @@ bool drawTexiOESWithCopybit_impl(GLint x, GLint y, GLint z,
    if ((w|h) <= 0) {
        return true;
    }

    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
+5 −5
Original line number Diff line number Diff line
@@ -28,7 +28,8 @@ namespace android {

bool drawTexiOESWithCopybit_impl(GLint x, GLint y, GLint z,
        GLint w, GLint h, ogles_context_t* c);
bool drawTrangleFanWithCopybit_impl(ogles_context_t* c, GLint first,

bool drawTriangleFanWithCopybit_impl(ogles_context_t* c, GLint first,
        GLsizei count);

inline bool copybitQuickCheckContext(ogles_context_t* c) {
@@ -54,17 +55,16 @@ inline bool drawTexiOESWithCopybit(GLint x, GLint y, GLint z,
 * Tries to draw a triangle fan using copybit hardware.
 * Returns true if successful.
 */
inline bool drawTrangleFanWithCopybit(ogles_context_t* c, GLint first,
inline bool drawTriangleFanWithCopybit(ogles_context_t* c, GLint first,
        GLsizei count) {
    /*
     * We are looking for the glDrawArrays call made by SurfaceFlinger.
     */

    if (!(copybitQuickCheckContext(c) && first == 0 && count == 4)) {
    if ((count!=4) || first || !copybitQuickCheckContext(c))
        return false;
    }
    
    return drawTrangleFanWithCopybit_impl(c, first, count);
    return drawTriangleFanWithCopybit_impl(c, first, count);
}