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

Commit 5cbbce53 authored by Romain Guy's avatar Romain Guy
Browse files

Reduced the complexity of layers composition.

This change also refactors the code base a bit by moving classes out of
OpenGLRenderer into separate headers/implementations. This makes the code
more manageable.

This change also adds documentation for implementation methods. The
undocumented methods are simply Skia's Canvas methods.

Change-Id: I54c68b443580a0129251dddc1a7ac95813d5289e
parent 1d58b498
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -3,7 +3,8 @@ include $(CLEAR_VARS)

LOCAL_SRC_FILES:= \
	Matrix.cpp \
	OpenGLRenderer.cpp
	OpenGLRenderer.cpp \
	Program.cpp

LOCAL_C_INCLUDES += \
	$(JNI_H_INCLUDE) \
+1 −1
Original line number Diff line number Diff line
@@ -14,7 +14,7 @@
 * limitations under the License.
 */

#define LOG_TAG "Matrix"
#define LOG_TAG "OpenGLRenderer"

#include <math.h>
#include <stdlib.h>
+36 −144
Original line number Diff line number Diff line
@@ -20,19 +20,11 @@
#include <stdint.h>
#include <sys/types.h>

#include <utils/Errors.h>
#include <utils/KeyedVector.h>
#include <utils/Log.h>

#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>

#include <SkCanvas.h>
#include <SkPaint.h>
#include <SkXfermode.h>

#include <utils/Log.h>

#include "OpenGLRenderer.h"
#include "Matrix.h"

namespace android {
namespace uirenderer {
@@ -57,7 +49,7 @@ const SimpleVertex gDrawColorVertices[] = {
const GLsizei gDrawColorVertexStride = sizeof(SimpleVertex);
const GLsizei gDrawColorVertexCount = 4;

const TextureVertex gDrawTextureVertices[] = {
TextureVertex gDrawTextureVertices[] = {
        FV(0.0f, 0.0f, 0.0f, 1.0f),
        FV(1.0f, 0.0f, 1.0f, 1.0f),
        FV(0.0f, 1.0f, 0.0f, 0.0f),
@@ -66,134 +58,15 @@ const TextureVertex gDrawTextureVertices[] = {
const GLsizei gDrawTextureVertexStride = sizeof(TextureVertex);
const GLsizei gDrawTextureVertexCount = 4;

///////////////////////////////////////////////////////////////////////////////
// Shaders
///////////////////////////////////////////////////////////////////////////////

#define SHADER_SOURCE(name, source) const char* name = #source

#include "shaders/drawColor.vert"
#include "shaders/drawColor.frag"

#include "shaders/drawTexture.vert"
#include "shaders/drawTexture.frag"

Program::Program(const char* vertex, const char* fragment) {
    vertexShader = buildShader(vertex, GL_VERTEX_SHADER);
    fragmentShader = buildShader(fragment, GL_FRAGMENT_SHADER);

    id = glCreateProgram();
    glAttachShader(id, vertexShader);
    glAttachShader(id, fragmentShader);
    glLinkProgram(id);

    GLint status;
    glGetProgramiv(id, GL_LINK_STATUS, &status);
    if (status != GL_TRUE) {
        GLint infoLen = 0;
        glGetProgramiv(id, GL_INFO_LOG_LENGTH, &infoLen);
        if (infoLen > 1) {
            char* log = (char*) malloc(sizeof(char) * infoLen);
            glGetProgramInfoLog(id, infoLen, 0, log);
            LOGE("Error while linking shaders: %s", log);
            delete log;
        }
        glDeleteProgram(id);
    }
}

Program::~Program() {
    glDeleteShader(vertexShader);
    glDeleteShader(fragmentShader);
    glDeleteProgram(id);
}

void Program::use() {
    glUseProgram(id);
}

int Program::addAttrib(const char* name) {
    int slot = glGetAttribLocation(id, name);
    attributes.add(name, slot);
    return slot;
}

int Program::getAttrib(const char* name) {
    return attributes.valueFor(name);
}

int Program::addUniform(const char* name) {
    int slot = glGetUniformLocation(id, name);
    uniforms.add(name, slot);
    return slot;
}

int Program::getUniform(const char* name) {
    return uniforms.valueFor(name);
}

GLuint Program::buildShader(const char* source, GLenum type) {
    GLuint shader = glCreateShader(type);
    glShaderSource(shader, 1, &source, 0);
    glCompileShader(shader);

    GLint status;
    glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
    if (status != GL_TRUE) {
        // Some drivers return wrong values for GL_INFO_LOG_LENGTH
        // use a fixed size instead
        GLchar log[512];
        glGetShaderInfoLog(shader, sizeof(log), 0, &log[0]);
        LOGE("Error while compiling shader: %s", log);
        glDeleteShader(shader);
    }

    return shader;
}

DrawColorProgram::DrawColorProgram():
        Program(gDrawColorVertexShader, gDrawColorFragmentShader) {
    getAttribsAndUniforms();
}

DrawColorProgram::DrawColorProgram(const char* vertex, const char* fragment):
        Program(vertex, fragment) {
    getAttribsAndUniforms();
}

void DrawColorProgram::getAttribsAndUniforms() {
    position = addAttrib("position");
    color = addAttrib("color");
    projection = addUniform("projection");
    modelView = addUniform("modelView");
    transform = addUniform("transform");
}

void DrawColorProgram::use(const GLfloat* projectionMatrix, const GLfloat* modelViewMatrix,
        const GLfloat* transformMatrix) {
    Program::use();
    glUniformMatrix4fv(projection, 1, GL_FALSE, projectionMatrix);
    glUniformMatrix4fv(modelView, 1, GL_FALSE, modelViewMatrix);
    glUniformMatrix4fv(transform, 1, GL_FALSE, transformMatrix);
}

DrawTextureProgram::DrawTextureProgram():
        DrawColorProgram(gDrawTextureVertexShader, gDrawTextureFragmentShader) {
    texCoords = addAttrib("texCoords");
    sampler = addUniform("sampler");
}

///////////////////////////////////////////////////////////////////////////////
// Support
///////////////////////////////////////////////////////////////////////////////

const Rect& Snapshot::getMappedClip() {
    if (flags & kFlagDirtyTransform) {
        flags &= ~kFlagDirtyTransform;
        mappedClip.set(clipRect);
        transform.mapRect(mappedClip);
    }
    return mappedClip;
static inline void resetDrawTextureTexCoords(float u1, float v1, float u2, float v2) {
    gDrawTextureVertices[0].texture[0] = u1;
    gDrawTextureVertices[0].texture[1] = v2;
    gDrawTextureVertices[1].texture[0] = u2;
    gDrawTextureVertices[1].texture[1] = v2;
    gDrawTextureVertices[2].texture[0] = u1;
    gDrawTextureVertices[2].texture[1] = v1;
    gDrawTextureVertices[3].texture[0] = u2;
    gDrawTextureVertices[3].texture[1] = v1;
}

///////////////////////////////////////////////////////////////////////////////
@@ -292,11 +165,28 @@ bool OpenGLRenderer::restoreSnapshot() {
        // Most of the time, previous->fbo will be 0 to bind the default buffer
        glBindFramebuffer(GL_FRAMEBUFFER, previous->fbo);

        // Restore the clip from the previous snapshot
        const Rect& clip = previous->getMappedClip();
        glScissor(clip.left, mHeight - clip.bottom, clip.getWidth(), clip.getHeight());

        // Compute the correct texture coordinates for the FBO texture
        // The texture is currently as big as the window but drawn with
        // a quad of the appropriate size
        const Rect& layer = current->layer;
        clipRect(layer.left, layer.top, layer.right, layer.bottom);
        mSnapshot->transform.loadIdentity();
        Rect texCoords(current->layer);
        mSnapshot->transform.mapRect(texCoords);

        const float u1 = texCoords.left / float(mWidth);
        const float v1 = (mHeight - texCoords.top) / float(mHeight);
        const float u2 = texCoords.right / float(mWidth);
        const float v2 = (mHeight - texCoords.bottom) / float(mHeight);

        drawTextureRect(0.0f, 0.0f, mWidth, mHeight, current->texture, current->alpha);
        resetDrawTextureTexCoords(u1, v1, u2, v1);

        drawTextureRect(layer.left, layer.top, layer.right, layer.bottom,
                current->texture, current->alpha);

        resetDrawTextureTexCoords(0.0f, 1.0f, 1.0f, 0.0f);

        glDeleteFramebuffers(1, &current->fbo);
        glDeleteTextures(1, &current->texture);
@@ -337,11 +227,14 @@ int OpenGLRenderer::saveLayerAlpha(float left, float top, float right, float bot
    // The FBO will not be scaled, so we can use lower quality filtering
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

    // TODO ***** IMPORTANT *****
    // Creating a texture-backed FBO works only if the texture is the same size
    // as the original rendering buffer (in this case, mWidth and mHeight.)
    // This is expensive and wasteful and must be fixed.
    // TODO Additionally we should use an FBO cache

    const GLsizei width = mWidth; //right - left;
    const GLsizei height = mHeight; //bottom - right;
@@ -425,7 +318,6 @@ bool OpenGLRenderer::quickReject(float left, float top, float right, float botto
     *     const Rect& clip = mSnapshot->getMappedClip();
     *     return !clip.intersects(r);
     */

    Rect r(left, top, right, bottom);
    return !mSnapshot->clipRect.intersects(r);
}
@@ -485,7 +377,7 @@ void OpenGLRenderer::drawTextureRect(float left, float top, float right, float b

    mDrawTextureShader->use(&mOrthoMatrix[0], &mModelView.data[0], &mSnapshot->transform.data[0]);

    // TODO Correctly set the blend function
    // TODO Correctly set the blend function, based on texture format and xfermode
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);

+53 −104
Original line number Diff line number Diff line
@@ -23,11 +23,12 @@
#include <SkMatrix.h>
#include <SkXfermode.h>

#include <utils/KeyedVector.h>
#include <utils/RefBase.h>

#include "Matrix.h"
#include "Program.h"
#include "Rect.h"
#include "Snapshot.h"

namespace android {
namespace uirenderer {
@@ -36,122 +37,30 @@ namespace uirenderer {
// Support
///////////////////////////////////////////////////////////////////////////////

class Snapshot: public LightRefBase<Snapshot> {
public:
    Snapshot() {
    }

    Snapshot(const sp<Snapshot> s):
            transform(s->transform),
            clipRect(s->clipRect),
            flags(kFlagDirtyTransform),
            previous(s),
            layer(0.0f, 0.0f, 0.0f, 0.0f),
            texture(0),
            fbo(0),
            alpha(255) {
    }

    enum Flags {
        kFlagClipSet = 0x1,
        kFlagDirtyTransform = 0x2,
        kFlagIsLayer = 0x4,
    };

    const Rect& getMappedClip();

    // Local transformations
    mat4 transform;

    // Clipping rectangle at the time of this snapshot
    Rect clipRect;

    // Dirty flags
    int flags;

    // Previous snapshot in the frames stack
    sp<Snapshot> previous;

    // Layer, only set if kFlagIsLayer is set
    Rect layer;
    GLuint texture;
    GLuint fbo;
    float alpha;

private:
    // Clipping rectangle mapped with the transform
    Rect mappedClip;
}; // class Snapshot

/**
 * Simple structure to describe a vertex with a position.
 * This is used to draw filled rectangles without a texture.
 */
struct SimpleVertex {
    float position[2];
}; // struct SimpleVertex

/**
 * Simple structure to describe a vertex with a position and a texture.
 */
struct TextureVertex {
    float position[2];
    float texture[2];
}; // struct TextureVertex

class Program: public LightRefBase<Program> {
public:
    Program(const char* vertex, const char* fragment);
    ~Program();

    void use();

protected:
    int addAttrib(const char* name);
    int getAttrib(const char* name);

    int addUniform(const char* name);
    int getUniform(const char* name);

private:
    GLuint buildShader(const char* source, GLenum type);

    // Handle of the OpenGL program
    GLuint id;

    // Handles of the shaders
    GLuint vertexShader;
    GLuint fragmentShader;

    // Keeps track of attributes and uniforms slots
    KeyedVector<const char*, int> attributes;
    KeyedVector<const char*, int> uniforms;
}; // class Program

class DrawColorProgram: public Program {
public:
    DrawColorProgram();
    DrawColorProgram(const char* vertex, const char* fragment);

    void use(const GLfloat* projectionMatrix, const GLfloat* modelViewMatrix,
             const GLfloat* transformMatrix);

    int position;
    int color;

    int projection;
    int modelView;
    int transform;

protected:
    void getAttribsAndUniforms();
};

class DrawTextureProgram: public DrawColorProgram {
public:
    DrawTextureProgram();

    int sampler;
    int texCoords;
};

///////////////////////////////////////////////////////////////////////////////
// Renderer
///////////////////////////////////////////////////////////////////////////////

/**
 * OpenGL renderer used to draw accelerated 2D graphics. The API is a
 * simplified version of Skia's Canvas API.
 */
class OpenGLRenderer {
public:
    OpenGLRenderer();
@@ -184,12 +93,52 @@ public:
    void drawRect(float left, float top, float right, float bottom, const SkPaint* paint);

private:
    /**
     * Saves the current state of the renderer as a new snapshot.
     * The new snapshot is saved in mSnapshot and the previous snapshot
     * is linked from mSnapshot->previous.
     *
     * @return The new save count. This value can be passed to #restoreToCount()
     */
    int saveSnapshot();

    /**
     * Restores the current snapshot; mSnapshot becomes mSnapshot->previous.
     *
     * @return True if the clip should be also reapplied by calling
     *         #setScissorFromClip().
     */
    bool restoreSnapshot();

    /**
     * Sets the clipping rectangle using glScissor. The clip is defined by
     * the current snapshot's clipRect member.
     */
    void setScissorFromClip();

    /**
     * Draws a colored rectangle with the specified color. The specified coordinates
     * are transformed by the current snapshot's transform matrix.
     *
     * @param left The left coordinate of the rectangle
     * @param top The top coordinate of the rectangle
     * @param right The right coordinate of the rectangle
     * @param bottom The bottom coordinate of the rectangle
     * @param color The rectangle's ARGB color, defined as a packed 32 bits word
     */
    void drawColorRect(float left, float top, float right, float bottom, int color);

    /**
     * Draws a textured rectangle with the specified texture. The specified coordinates
     * are transformed by the current snapshot's transform matrix.
     *
     * @param left The left coordinate of the rectangle
     * @param top The top coordinate of the rectangle
     * @param right The right coordinate of the rectangle
     * @param bottom The bottom coordinate of the rectangle
     * @param texture The texture name to map onto the rectangle
     * @param alpha An additional translucency parameter, between 0.0f and 1.0f
     */
    void drawTextureRect(float left, float top, float right, float bottom, GLuint texture,
            float alpha);

libs/hwui/Program.cpp

0 → 100644
+154 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2010 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.
 */

#define LOG_TAG "OpenGLRenderer"

#include "Program.h"

namespace android {
namespace uirenderer {

///////////////////////////////////////////////////////////////////////////////
// Shaders
///////////////////////////////////////////////////////////////////////////////

#define SHADER_SOURCE(name, source) const char* name = #source

#include "shaders/drawColor.vert"
#include "shaders/drawColor.frag"

#include "shaders/drawTexture.vert"
#include "shaders/drawTexture.frag"

///////////////////////////////////////////////////////////////////////////////
// Base program
///////////////////////////////////////////////////////////////////////////////

Program::Program(const char* vertex, const char* fragment) {
    vertexShader = buildShader(vertex, GL_VERTEX_SHADER);
    fragmentShader = buildShader(fragment, GL_FRAGMENT_SHADER);

    id = glCreateProgram();
    glAttachShader(id, vertexShader);
    glAttachShader(id, fragmentShader);
    glLinkProgram(id);

    GLint status;
    glGetProgramiv(id, GL_LINK_STATUS, &status);
    if (status != GL_TRUE) {
        GLint infoLen = 0;
        glGetProgramiv(id, GL_INFO_LOG_LENGTH, &infoLen);
        if (infoLen > 1) {
            char* log = (char*) malloc(sizeof(char) * infoLen);
            glGetProgramInfoLog(id, infoLen, 0, log);
            LOGE("Error while linking shaders: %s", log);
            delete log;
        }
        glDeleteProgram(id);
    }
}

Program::~Program() {
    glDeleteShader(vertexShader);
    glDeleteShader(fragmentShader);
    glDeleteProgram(id);
}

void Program::use() {
    glUseProgram(id);
}

int Program::addAttrib(const char* name) {
    int slot = glGetAttribLocation(id, name);
    attributes.add(name, slot);
    return slot;
}

int Program::getAttrib(const char* name) {
    return attributes.valueFor(name);
}

int Program::addUniform(const char* name) {
    int slot = glGetUniformLocation(id, name);
    uniforms.add(name, slot);
    return slot;
}

int Program::getUniform(const char* name) {
    return uniforms.valueFor(name);
}

GLuint Program::buildShader(const char* source, GLenum type) {
    GLuint shader = glCreateShader(type);
    glShaderSource(shader, 1, &source, 0);
    glCompileShader(shader);

    GLint status;
    glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
    if (status != GL_TRUE) {
        // Some drivers return wrong values for GL_INFO_LOG_LENGTH
        // use a fixed size instead
        GLchar log[512];
        glGetShaderInfoLog(shader, sizeof(log), 0, &log[0]);
        LOGE("Error while compiling shader: %s", log);
        glDeleteShader(shader);
    }

    return shader;
}

///////////////////////////////////////////////////////////////////////////////
// Draw color
///////////////////////////////////////////////////////////////////////////////

DrawColorProgram::DrawColorProgram():
        Program(gDrawColorVertexShader, gDrawColorFragmentShader) {
    getAttribsAndUniforms();
}

DrawColorProgram::DrawColorProgram(const char* vertex, const char* fragment):
        Program(vertex, fragment) {
    getAttribsAndUniforms();
}

void DrawColorProgram::getAttribsAndUniforms() {
    position = addAttrib("position");
    color = addAttrib("color");
    projection = addUniform("projection");
    modelView = addUniform("modelView");
    transform = addUniform("transform");
}

void DrawColorProgram::use(const GLfloat* projectionMatrix, const GLfloat* modelViewMatrix,
        const GLfloat* transformMatrix) {
    Program::use();
    glUniformMatrix4fv(projection, 1, GL_FALSE, projectionMatrix);
    glUniformMatrix4fv(modelView, 1, GL_FALSE, modelViewMatrix);
    glUniformMatrix4fv(transform, 1, GL_FALSE, transformMatrix);
}

///////////////////////////////////////////////////////////////////////////////
// Draw texture
///////////////////////////////////////////////////////////////////////////////

DrawTextureProgram::DrawTextureProgram():
        DrawColorProgram(gDrawTextureVertexShader, gDrawTextureFragmentShader) {
    texCoords = addAttrib("texCoords");
    sampler = addUniform("sampler");
}

}; // namespace uirenderer
}; // namespace android
Loading