void LayerBase::dump(String8& result, char* buffer, size_t SIZE) const
{
    const Layer::State& s(drawingState());

    snprintf(buffer, SIZE,
            "+ %s %p (%s)\n",
            getTypeId(), this, getName().string());
    result.append(buffer);

    s.transparentRegion.dump(result, "transparentRegion");
    visibleRegion.dump(result, "visibleRegion");

    snprintf(buffer, SIZE,
            "      "
            "layerStack=%4d, z=%9d, pos=(%g,%g), size=(%4d,%4d), crop=(%4d,%4d,%4d,%4d), "
            "isOpaque=%1d, needsDithering=%1d, invalidate=%1d, "
            "alpha=0x%02x, flags=0x%08x, tr=[%.2f, %.2f][%.2f, %.2f]\n",
            s.layerStack, s.z, s.transform.tx(), s.transform.ty(), s.active.w, s.active.h,
            s.active.crop.left, s.active.crop.top,
            s.active.crop.right, s.active.crop.bottom,
            isOpaque(), needsDithering(), contentDirty,
            s.alpha, s.flags,
            s.transform[0][0], s.transform[0][1],
            s.transform[1][0], s.transform[1][1]);
    result.append(buffer);
}
void LayerBase::dump(String8& result, char* buffer, size_t SIZE) const
{
    const Layer::State& s(drawingState());
    snprintf(buffer, SIZE,
            "+ %s %p\n"
            "      "
            "z=%9d, pos=(%4d,%4d), size=(%4d,%4d), "
            "needsBlending=%1d, needsDithering=%1d, invalidate=%1d, "
            "alpha=0x%02x, flags=0x%08x, tr=[%.2f, %.2f][%.2f, %.2f]\n",
            getTypeId(), this, s.z, tx(), ty(), s.w, s.h,
            needsBlending(), needsDithering(), contentDirty,
            s.alpha, s.flags,
            s.transform[0][0], s.transform[0][1],
            s.transform[1][0], s.transform[1][1]);
    result.append(buffer);
}
void Layer::drawWithOpenGL(
        const sp<const DisplayDevice>& hw, const Region& clip) const {
    const uint32_t fbHeight = hw->getHeight();
    const State& s(getDrawingState());

    computeGeometry(hw, mMesh);

    /*
     * NOTE: the way we compute the texture coordinates here produces
     * different results than when we take the HWC path -- in the later case
     * the "source crop" is rounded to texel boundaries.
     * This can produce significantly different results when the texture
     * is scaled by a large amount.
     *
     * The GL code below is more logical (imho), and the difference with
     * HWC is due to a limitation of the HWC API to integers -- a question
     * is suspend is whether we should ignore this problem or revert to
     * GL composition when a buffer scaling is applied (maybe with some
     * minimal value)? Or, we could make GL behave like HWC -- but this feel
     * like more of a hack.
     */
    const Rect win(computeBounds());

    float left   = float(win.left)   / float(s.active.w);
    float top    = float(win.top)    / float(s.active.h);
    float right  = float(win.right)  / float(s.active.w);
    float bottom = float(win.bottom) / float(s.active.h);

    // TODO: we probably want to generate the texture coords with the mesh
    // here we assume that we only have 4 vertices
    Mesh::VertexArray<vec2> texCoords(mMesh.getTexCoordArray<vec2>());
    texCoords[0] = vec2(left, 1.0f - top);
    texCoords[1] = vec2(left, 1.0f - bottom);
    texCoords[2] = vec2(right, 1.0f - bottom);
    texCoords[3] = vec2(right, 1.0f - top);

    RenderEngine& engine(mFlinger->getRenderEngine());
    engine.setDither(needsDithering());
    engine.setupLayerBlending(mPremultipliedAlpha, isOpaque(), s.alpha);
    engine.drawMesh(mMesh);
    engine.disableBlending();
}
void LayerBase::drawWithOpenGL(const Region& clip, const Texture& texture) const
{
    const DisplayHardware& hw(graphicPlane(0).displayHardware());
    const uint32_t fbHeight = hw.getHeight();
    const State& s(drawingState());
    
    // bind our texture
    TextureManager::activateTexture(texture, needsFiltering());
    uint32_t width  = texture.width; 
    uint32_t height = texture.height;

    GLenum src = mPremultipliedAlpha ? GL_ONE : GL_SRC_ALPHA;

    int renderEffect = mFlinger->getRenderEffect();
    int renderColorR = mFlinger->getRenderColorR();
    int renderColorG = mFlinger->getRenderColorG();
    int renderColorB = mFlinger->getRenderColorB();

    bool noEffect = renderEffect == 0;

    if (UNLIKELY(s.alpha < 0xFF) && noEffect) {
        const GLfloat alpha = s.alpha * (1.0f/255.0f);
        if (mPremultipliedAlpha) {
            glColor4f(alpha, alpha, alpha, alpha);
        } else {
            glColor4f(1, 1, 1, alpha);
        }
        glEnable(GL_BLEND);
        glBlendFunc(src, GL_ONE_MINUS_SRC_ALPHA);
        glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
    } else if (noEffect) {
        glColor4f(1, 1, 1, 1);
        glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
        if (needsBlending()) {
            glEnable(GL_BLEND);
            glBlendFunc(src, GL_ONE_MINUS_SRC_ALPHA);
        } else {
            glDisable(GL_BLEND);
        }
    } else {
        // Apply a render effect, which is simple color masks for now.
        GLenum env, src;
        env = GL_MODULATE;
        src = mPremultipliedAlpha ? GL_ONE : GL_SRC_ALPHA;
        const GGLfixed alpha = (s.alpha << 16)/255;
        switch (renderEffect) {
            case RENDER_EFFECT_NIGHT:
                glColor4x(alpha, alpha*0.6204, alpha*0.3018, alpha);
                break;
            case RENDER_EFFECT_TERMINAL:
                glColor4x(0, alpha, 0, alpha);
                break;
            case RENDER_EFFECT_BLUE:
                glColor4x(0, 0, alpha, alpha);
                break;
            case RENDER_EFFECT_AMBER:
                glColor4x(alpha, alpha*0.75, 0, alpha);
                break;
            case RENDER_EFFECT_SALMON:
                glColor4x(alpha, alpha*0.5, alpha*0.5, alpha);
                break;
            case RENDER_EFFECT_FUSCIA:
                glColor4x(alpha, 0, alpha*0.5, alpha);
                break;
            case RENDER_EFFECT_N1_CALIBRATED_N:
                glColor4x(alpha*renderColorR/1000, alpha*renderColorG/1000, alpha*renderColorB/1000, alpha);
                break;
            case RENDER_EFFECT_N1_CALIBRATED_R:
                glColor4x(alpha*(renderColorR-50)/1000, alpha*renderColorG/1000, alpha*(renderColorB-30)/1000, alpha);
                break;
            case RENDER_EFFECT_N1_CALIBRATED_C:
                glColor4x(alpha*renderColorR/1000, alpha*renderColorG/1000, alpha*(renderColorB+30)/1000, alpha);
                break;
            case RENDER_EFFECT_RED:
                glColor4x(alpha, 0, 0, alpha);
                break;
        }
        glEnable(GL_BLEND);
        glBlendFunc(src, GL_ONE_MINUS_SRC_ALPHA);
        glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, env);
    }

    /*
     *  compute texture coordinates
     *  here, we handle NPOT, cropping and buffer transformations
     */

    GLfloat cl, ct, cr, cb;
    if (!mBufferCrop.isEmpty()) {
        // source is cropped
        const GLfloat us = (texture.NPOTAdjust ? texture.wScale : 1.0f) / width;
        const GLfloat vs = (texture.NPOTAdjust ? texture.hScale : 1.0f) / height;
        cl = mBufferCrop.left   * us;
        ct = mBufferCrop.top    * vs;
        cr = mBufferCrop.right  * us;
        cb = mBufferCrop.bottom * vs;
    } else {
        cl = 0;
        ct = 0;
        cr = (texture.NPOTAdjust ? texture.wScale : 1.0f);
        cb = (texture.NPOTAdjust ? texture.hScale : 1.0f);
    }

    /*
     * For the buffer transformation, we apply the rotation last.
     * Since we're transforming the texture-coordinates, we need
     * to apply the inverse of the buffer transformation:
     *   inverse( FLIP_V -> FLIP_H -> ROT_90 )
     *   <=> inverse( ROT_90 * FLIP_H * FLIP_V )
     *    =  inverse(FLIP_V) * inverse(FLIP_H) * inverse(ROT_90)
     *    =  FLIP_V * FLIP_H * ROT_270
     *   <=> ROT_270 -> FLIP_H -> FLIP_V
     *
     * The rotation is performed first, in the texture coordinate space.
     *
     */

    struct TexCoords {
        GLfloat u;
        GLfloat v;
    };

    enum {
        // name of the corners in the texture map
        LB = 0, // left-bottom
        LT = 1, // left-top
        RT = 2, // right-top
        RB = 3  // right-bottom
    };

    // vertices in screen space
    int vLT = LB;
    int vLB = LT;
    int vRB = RT;
    int vRT = RB;

    // the texture's source is rotated
    uint32_t transform = mBufferTransform;
    if (transform & HAL_TRANSFORM_ROT_90) {
        vLT = RB;
        vLB = LB;
        vRB = LT;
        vRT = RT;
    }
    if (transform & HAL_TRANSFORM_FLIP_V) {
        swap(vLT, vLB);
        swap(vRT, vRB);
    }
    if (transform & HAL_TRANSFORM_FLIP_H) {
        swap(vLT, vRT);
        swap(vLB, vRB);
    }

    TexCoords texCoords[4];
    texCoords[vLT].u = cl;
    texCoords[vLT].v = ct;
    texCoords[vLB].u = cl;
    texCoords[vLB].v = cb;
    texCoords[vRB].u = cr;
    texCoords[vRB].v = cb;
    texCoords[vRT].u = cr;
    texCoords[vRT].v = ct;

    if (needsDithering()) {
        glEnable(GL_DITHER);
    } else {
        glDisable(GL_DITHER);
    }

    glEnableClientState(GL_TEXTURE_COORD_ARRAY);
    glVertexPointer(2, GL_FLOAT, 0, mVertices);
    glTexCoordPointer(2, GL_FLOAT, 0, texCoords);

    Region::const_iterator it = clip.begin();
    Region::const_iterator const end = clip.end();
    while (it != end) {
        const Rect& r = *it++;
        const GLint sy = fbHeight - (r.top + r.height());
        glScissor(r.left, sy, r.width(), r.height());
        glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
    }
    glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}
void LayerBase::drawWithOpenGL(const Region& clip) const
{
    const DisplayHardware& hw(graphicPlane(0).displayHardware());
    const uint32_t fbHeight = hw.getHeight();
    const State& s(drawingState());

    GLenum src = mPremultipliedAlpha ? GL_ONE : GL_SRC_ALPHA;
    if (CC_UNLIKELY(s.alpha < 0xFF)) {
        const GLfloat alpha = s.alpha * (1.0f/255.0f);
        if (mPremultipliedAlpha) {
            glColor4f(alpha, alpha, alpha, alpha);
        } else {
            glColor4f(1, 1, 1, alpha);
        }
        glEnable(GL_BLEND);
        glBlendFunc(src, GL_ONE_MINUS_SRC_ALPHA);
        glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
    } else {
        glColor4f(1, 1, 1, 1);
        glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
        if (!isOpaque()) {
            glEnable(GL_BLEND);
            glBlendFunc(src, GL_ONE_MINUS_SRC_ALPHA);
        } else {
            glDisable(GL_BLEND);
        }
    }

    struct TexCoords {
        GLfloat u;
        GLfloat v;
    };

    Rect crop(s.active.w, s.active.h);
    if (!s.active.crop.isEmpty()) {
        crop = s.active.crop;
    }
    GLfloat left = GLfloat(crop.left) / GLfloat(s.active.w);
    GLfloat top = GLfloat(crop.top) / GLfloat(s.active.h);
    GLfloat right = GLfloat(crop.right) / GLfloat(s.active.w);
    GLfloat bottom = GLfloat(crop.bottom) / GLfloat(s.active.h);

    TexCoords texCoords[4];
    texCoords[0].u = left;
    texCoords[0].v = top;
    texCoords[1].u = left;
    texCoords[1].v = bottom;
    texCoords[2].u = right;
    texCoords[2].v = bottom;
    texCoords[3].u = right;
    texCoords[3].v = top;
    for (int i = 0; i < 4; i++) {
        texCoords[i].v = 1.0f - texCoords[i].v;
    }

    if (needsDithering()) {
        glEnable(GL_DITHER);
    } else {
        glDisable(GL_DITHER);
    }

    glEnableClientState(GL_TEXTURE_COORD_ARRAY);
    glVertexPointer(2, GL_FLOAT, 0, mVertices);
    glTexCoordPointer(2, GL_FLOAT, 0, texCoords);
    glDrawArrays(GL_TRIANGLE_FAN, 0, mNumVertices);

    glDisableClientState(GL_TEXTURE_COORD_ARRAY);
    glDisable(GL_BLEND);
}
Beispiel #6
0
void Layer::onDraw(const Region& clip) const
{
    if (CC_UNLIKELY(mActiveBuffer == 0)) {
        // the texture has not been created yet, this Layer has
        // in fact never been drawn into. This happens frequently with
        // SurfaceView because the WindowManager can't know when the client
        // has drawn the first time.

        // If there is nothing under us, we paint the screen in black, otherwise
        // we just skip this update.

        // figure out if there is something below us
        Region under;
        const SurfaceFlinger::LayerVector& drawingLayers(
                mFlinger->mDrawingState.layersSortedByZ);
        const size_t count = drawingLayers.size();
        for (size_t i=0 ; i<count ; ++i) {
            const sp<LayerBase>& layer(drawingLayers[i]);
            if (layer.get() == static_cast<LayerBase const*>(this))
                break;
            under.orSelf(layer->visibleRegionScreen);
        }
        // if not everything below us is covered, we plug the holes!
        Region holes(clip.subtract(under));
        if (!holes.isEmpty()) {
            clearWithOpenGL(holes, 0, 0, 0, 1);
        }
        return;
    }

    if (!isGPUSupportedFormat(mActiveBuffer->format)) {
         clearWithOpenGL(clip, 0, 0, 0, 1);
        return;
    }

    if (!isProtected()) {
        glBindTexture(GL_TEXTURE_EXTERNAL_OES, mTextureName);
        GLenum filter = GL_NEAREST;
        if (getFiltering() || needsFiltering() || isFixedSize() || isCropped()) {
            // TODO: we could be more subtle with isFixedSize()
            filter = GL_LINEAR;
        }
        glTexParameterx(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, filter);
        glTexParameterx(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, filter);
        glMatrixMode(GL_TEXTURE);
        glLoadMatrixf(mTextureMatrix);
        glMatrixMode(GL_MODELVIEW);
        glDisable(GL_TEXTURE_2D);
        glEnable(GL_TEXTURE_EXTERNAL_OES);
    } else {
        glBindTexture(GL_TEXTURE_2D, mFlinger->getProtectedTexName());
        glMatrixMode(GL_TEXTURE);
        glLoadIdentity();
        glMatrixMode(GL_MODELVIEW);
        glDisable(GL_TEXTURE_EXTERNAL_OES);
        glEnable(GL_TEXTURE_2D);
    }

    if(needsDithering()) {
        glEnable(GL_DITHER);
    }

    int composeS3DFormat = mQCLayer->needsS3DCompose();
    if (composeS3DFormat)
        drawS3DUIWithOpenGL(clip);
    else
        drawWithOpenGL(clip);
    glDisable(GL_TEXTURE_EXTERNAL_OES);
    glDisable(GL_TEXTURE_2D);
    if(needsDithering()) {
        glDisable(GL_DITHER);
    }
}