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

Commit 858aa93d authored by Chet Haase's avatar Chet Haase
Browse files

Antialiasing for rectangles

Change-Id: I7ca6931606541ddd504bd5db7f8dc04b9cde8cd9
parent e4ba346f
Loading
Loading
Loading
Loading
+78 −1
Original line number Diff line number Diff line
@@ -1457,6 +1457,79 @@ void OpenGLRenderer::drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const int
    }
}

/**
 * This function uses a similar approach to that of AA lines in the drawLines() function.
 * We expand the rectangle by a half pixel in screen space on all sides, and use a fragment
 * shader to compute the translucency of the color, determined by whether a given pixel is
 * within that boundary region and how far into the region it is.
 */
void OpenGLRenderer::drawAARect(float left, float top, float right, float bottom,
        int color, SkXfermode::Mode mode)
{
    float inverseScaleX = 1.0f;
    float inverseScaleY = 1.0f;
    // The quad that we use needs to account for scaling.
    if (!mSnapshot->transform->isPureTranslate()) {
        Matrix4 *mat = mSnapshot->transform;
        float m00 = mat->data[Matrix4::kScaleX];
        float m01 = mat->data[Matrix4::kSkewY];
        float m02 = mat->data[2];
        float m10 = mat->data[Matrix4::kSkewX];
        float m11 = mat->data[Matrix4::kScaleX];
        float m12 = mat->data[6];
        float scaleX = sqrt(m00 * m00 + m01 * m01);
        float scaleY = sqrt(m10 * m10 + m11 * m11);
        inverseScaleX = (scaleX != 0) ? (inverseScaleX / scaleX) : 0;
        inverseScaleY = (scaleY != 0) ? (inverseScaleY / scaleY) : 0;
    }

    setupDraw();
    setupDrawAALine();
    setupDrawColor(color);
    setupDrawColorFilter();
    setupDrawShader();
    setupDrawBlending(true, mode);
    setupDrawProgram();
    setupDrawModelViewIdentity(true);
    setupDrawColorUniforms();
    setupDrawColorFilterUniforms();
    setupDrawShaderIdentityUniforms();

    AAVertex rects[4];
    AAVertex* aaVertices = &rects[0];
    void* widthCoords = ((GLbyte*) aaVertices) + gVertexAAWidthOffset;
    void* lengthCoords = ((GLbyte*) aaVertices) + gVertexAALengthOffset;

    float boundarySizeX = .5 * inverseScaleX;
    float boundarySizeY = .5 * inverseScaleY;

    // Adjust the rect by the AA boundary padding
    left -= boundarySizeX;
    right += boundarySizeX;
    top -= boundarySizeY;
    bottom += boundarySizeY;

    float width = right - left;
    float height = bottom - top;

    float boundaryWidthProportion = (width != 0) ? (2 * boundarySizeX) / width : 0;
    float boundaryHeightProportion = (height != 0) ? (2 * boundarySizeY) / height : 0;
    setupDrawAALine((void*) aaVertices, widthCoords, lengthCoords, boundaryWidthProportion);
    int boundaryLengthSlot = mCaches.currentProgram->getUniform("boundaryLength");
    int inverseBoundaryLengthSlot = mCaches.currentProgram->getUniform("inverseBoundaryLength");
    glUniform1f(boundaryLengthSlot, boundaryHeightProportion);
    glUniform1f(inverseBoundaryLengthSlot, (1 / boundaryHeightProportion));

    if (!quickReject(left, top, right, bottom)) {
        AAVertex::set(aaVertices++, left, bottom, 1, 1);
        AAVertex::set(aaVertices++, left, top, 1, 0);
        AAVertex::set(aaVertices++, right, bottom, 0, 1);
        AAVertex::set(aaVertices++, right, top, 0, 0);
        dirtyLayer(left, top, right, bottom, *mSnapshot->transform);
        glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
    }
}

/**
 * We draw lines as quads (tristrips). Using GL_LINES can be difficult because the rasterization
 * rules for those lines produces some unexpected results, and may vary between hardware devices.
@@ -1848,8 +1921,12 @@ void OpenGLRenderer::drawRect(float left, float top, float right, float bottom,
    }

    int color = p->getColor();
    if (p->isAntiAlias()) {
        drawAARect(left, top, right, bottom, color, mode);
    } else {
        drawColorRect(left, top, right, bottom, color, mode);
    }
}

void OpenGLRenderer::drawText(const char* text, int bytesCount, int count,
        float x, float y, SkPaint* paint) {
+3 −0
Original line number Diff line number Diff line
@@ -285,6 +285,9 @@ private:

    void drawAlphaBitmap(Texture* texture, float left, float top, SkPaint* paint);

    void drawAARect(float left, float top, float right, float bottom,
            int color, SkXfermode::Mode mode);

    /**
     * Draws a textured rectangle with the specified texture. The specified coordinates
     * are transformed by the current snapshot's transform matrix.
+9 −0
Original line number Diff line number Diff line
@@ -92,6 +92,15 @@
            </intent-filter>
        </activity>
        
        <activity
                android:name="ColoredRectsActivity"
                android:label="_Rects">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <activity
                android:name="SimplePatchActivity"
                android:label="_SimplePatch"
+124 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2011 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.test.hwui;

import android.animation.ObjectAnimator;
import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
import android.view.View;
import android.widget.FrameLayout;

@SuppressWarnings({"UnusedDeclaration"})
public class ColoredRectsActivity extends Activity {
    private ObjectAnimator mAnimator;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        getWindow().setBackgroundDrawable(new ColorDrawable(0xff000000));
        FrameLayout frame = new FrameLayout(this);
        final RectsView gpuView = new RectsView(this, 0, Color.GREEN);
        frame.addView(gpuView);
        final RectsView swView = new RectsView(this, 400, Color.RED);
        swView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
        frame.addView(swView);
        final RectsView hwBothView = new RectsView(this, 850, Color.GREEN);
        // Don't actually need to render to a hw layer, but it's a good sanity-check that
        // we're rendering to/from layers correctly
        hwBothView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
        frame.addView(hwBothView);
        final RectsView swBothView = new RectsView(this, 854, Color.RED);
        swBothView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
        frame.addView(swBothView);
        setContentView(frame);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
    }

    public static class RectsView extends View {

        private float mOffset;
        private int mColor;

        public RectsView(Context c, float offset, int color) {
            super(c);
            mOffset = offset;
            mColor = color;
        }

        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            Paint p = new Paint();
            p.setColor(mColor);
            float yOffset = 10;

            for (int i = 0; i < 2; ++i) {
                canvas.save();
                canvas.translate(mOffset, yOffset);
                canvas.drawRect(0, 0, 20, 10, p);
                canvas.drawRect(35, 0, 45, 20, p);
                canvas.translate(0, -yOffset);
                canvas.scale(2, 2);
                canvas.translate(60, yOffset/2);
                canvas.drawRect(0, 0, 20, 10, p);
                canvas.translate(15, 0);
                canvas.drawRect(35, 0, 45, 20, p);
                canvas.restore();

                yOffset += 100;

                canvas.save();
                canvas.save();
                canvas.translate(mOffset + 10, yOffset);
                canvas.rotate(45);
                canvas.drawRect(0, 0, 20, 10, p);
                canvas.restore();
                canvas.save();
                canvas.translate(mOffset + 70, yOffset);
                canvas.rotate(5);
                canvas.drawRect(0, 0, 20, 10, p);
                canvas.restore();
                canvas.save();
                canvas.translate(mOffset + 140, yOffset);
                canvas.scale(2, 2);
                canvas.rotate(5);
                canvas.drawRect(0, 0, 20, 10, p);
                canvas.restore();
                canvas.save();
                canvas.translate(mOffset + 210, yOffset);
                canvas.scale(2, 2);
                canvas.rotate(45);
                canvas.drawRect(0, 0, 20, 10, p);
                canvas.restore();
                canvas.restore();

                yOffset += 100;

                p.setAntiAlias(true);
            }
        }
    }
}