/frameworks/base/libs/hwui/OpenGLRenderer.cpp
C++ | 1516 lines | 1088 code | 260 blank | 168 comment | 186 complexity | 6efd5a1a2190706eae066af5d15ea33d MD5 | raw file
- /*
- * 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 <stdlib.h>
- #include <stdint.h>
- #include <sys/types.h>
- #include <SkCanvas.h>
- #include <SkPathMeasure.h>
- #include <SkTypeface.h>
- #include <utils/Log.h>
- #include <utils/StopWatch.h>
- #include <private/hwui/DrawGlInfo.h>
- #include <ui/Rect.h>
- #include "OpenGLRenderer.h"
- #include "DisplayListRenderer.h"
- #include "PathRenderer.h"
- #include "Properties.h"
- #include "Vector.h"
- namespace android {
- namespace uirenderer {
- ///////////////////////////////////////////////////////////////////////////////
- // Defines
- ///////////////////////////////////////////////////////////////////////////////
- #define RAD_TO_DEG (180.0f / 3.14159265f)
- #define MIN_ANGLE 0.001f
- #define ALPHA_THRESHOLD 0
- #define FILTER(paint) (!paint || paint->isFilterBitmap() ? GL_LINEAR : GL_NEAREST)
- ///////////////////////////////////////////////////////////////////////////////
- // Globals
- ///////////////////////////////////////////////////////////////////////////////
- /**
- * Structure mapping Skia xfermodes to OpenGL blending factors.
- */
- struct Blender {
- SkXfermode::Mode mode;
- GLenum src;
- GLenum dst;
- }; // struct Blender
- // In this array, the index of each Blender equals the value of the first
- // entry. For instance, gBlends[1] == gBlends[SkXfermode::kSrc_Mode]
- static const Blender gBlends[] = {
- { SkXfermode::kClear_Mode, GL_ZERO, GL_ONE_MINUS_SRC_ALPHA },
- { SkXfermode::kSrc_Mode, GL_ONE, GL_ZERO },
- { SkXfermode::kDst_Mode, GL_ZERO, GL_ONE },
- { SkXfermode::kSrcOver_Mode, GL_ONE, GL_ONE_MINUS_SRC_ALPHA },
- { SkXfermode::kDstOver_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ONE },
- { SkXfermode::kSrcIn_Mode, GL_DST_ALPHA, GL_ZERO },
- { SkXfermode::kDstIn_Mode, GL_ZERO, GL_SRC_ALPHA },
- { SkXfermode::kSrcOut_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ZERO },
- { SkXfermode::kDstOut_Mode, GL_ZERO, GL_ONE_MINUS_SRC_ALPHA },
- { SkXfermode::kSrcATop_Mode, GL_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA },
- { SkXfermode::kDstATop_Mode, GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA },
- { SkXfermode::kXor_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA },
- { SkXfermode::kPlus_Mode, GL_ONE, GL_ONE },
- { SkXfermode::kMultiply_Mode, GL_ZERO, GL_SRC_COLOR },
- { SkXfermode::kScreen_Mode, GL_ONE, GL_ONE_MINUS_SRC_COLOR }
- };
- // This array contains the swapped version of each SkXfermode. For instance
- // this array's SrcOver blending mode is actually DstOver. You can refer to
- // createLayer() for more information on the purpose of this array.
- static const Blender gBlendsSwap[] = {
- { SkXfermode::kClear_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ZERO },
- { SkXfermode::kSrc_Mode, GL_ZERO, GL_ONE },
- { SkXfermode::kDst_Mode, GL_ONE, GL_ZERO },
- { SkXfermode::kSrcOver_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ONE },
- { SkXfermode::kDstOver_Mode, GL_ONE, GL_ONE_MINUS_SRC_ALPHA },
- { SkXfermode::kSrcIn_Mode, GL_ZERO, GL_SRC_ALPHA },
- { SkXfermode::kDstIn_Mode, GL_DST_ALPHA, GL_ZERO },
- { SkXfermode::kSrcOut_Mode, GL_ZERO, GL_ONE_MINUS_SRC_ALPHA },
- { SkXfermode::kDstOut_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ZERO },
- { SkXfermode::kSrcATop_Mode, GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA },
- { SkXfermode::kDstATop_Mode, GL_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA },
- { SkXfermode::kXor_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA },
- { SkXfermode::kPlus_Mode, GL_ONE, GL_ONE },
- { SkXfermode::kMultiply_Mode, GL_DST_COLOR, GL_ZERO },
- { SkXfermode::kScreen_Mode, GL_ONE_MINUS_DST_COLOR, GL_ONE }
- };
- ///////////////////////////////////////////////////////////////////////////////
- // Constructors/destructor
- ///////////////////////////////////////////////////////////////////////////////
- static int EnableDither = 0;
- char* GetProgramName(char* buf, int size)
- {
- char procName[64];
- pid_t pid = getpid();
- FILE* fp = NULL;
- snprintf(procName, sizeof(procName), "/proc/%i/cmdline", pid);
- fp = fopen(procName, "r");
- if(fp)
- {
- fread(buf, 1, size, fp);
- fclose(fp);
- fp = NULL;
- }
- else
- {
- ALOGD("%s : %d : open file %s failed \n", __FUNCTION__, __LINE__, procName);
- }
- return buf;
- }
- OpenGLRenderer::OpenGLRenderer(): mCaches(Caches::getInstance()) {
- mShader = NULL;
- mColorFilter = NULL;
- mHasShadow = false;
- mHasDrawFilter = false;
- mOrientation = -1;
- memcpy(mMeshVertices, gMeshVertices, sizeof(gMeshVertices));
- mFirstSnapshot = new Snapshot;
- mScissorOptimizationDisabled = false;
- char property[PROPERTY_VALUE_MAX];
- property_get("ro.sf.lcdc_composer", property, NULL) > 0;
- char exeName[64] = {0};
- GetProgramName(exeName, 64 - 1);
- if( ((0 == strcmp("com.android.browser", exeName)) ||
- (0 == strcmp("com.android.launcher", exeName))) &&
- !strcmp(property, "1"))
- {
- EnableDither = 1;
- } else {
- EnableDither = 0;
- }
- }
- OpenGLRenderer::~OpenGLRenderer() {
- // The context has already been destroyed at this point, do not call
- // GL APIs. All GL state should be kept in Caches.h
- }
- void OpenGLRenderer::initProperties() {
- char property[PROPERTY_VALUE_MAX];
- if (property_get(PROPERTY_DISABLE_SCISSOR_OPTIMIZATION, property, "false")) {
- mScissorOptimizationDisabled = !strcasecmp(property, "true");
- INIT_LOGD(" Scissor optimization %s",
- mScissorOptimizationDisabled ? "disabled" : "enabled");
- } else {
- INIT_LOGD(" Scissor optimization enabled");
- }
- }
- ///////////////////////////////////////////////////////////////////////////////
- // Setup
- ///////////////////////////////////////////////////////////////////////////////
- bool OpenGLRenderer::isDeferred() {
- return false;
- }
- bool OpenGLRenderer::queryHWRenderEngine(const char* property) {
- //get gpu renderer, make sure gl context has created.
- const char *renderer = (const char *)glGetString(GL_RENDERER);
- if (renderer != NULL) {
- if (!strcmp(property, "debug.hwui.render_dirty_regions")) {
- if (!strcmp(renderer, "Mali-400 MP")) {
- return false;
- } else if (!strcmp(renderer, "PowerVR SGX 540")) {
- return true;
- }
- }
- }
- return false;
- }
- void OpenGLRenderer::setOrientation(int orientation) {
- //ALOGD("setOrientation: %d", orientation);
- mOrientation = orientation;
- }
- void OpenGLRenderer::setViewport(int width, int height) {
- initViewport(width, height);
- if(EnableDither)
- glEnable(GL_DITHER);
- else
- glDisable(GL_DITHER);
- glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
- glEnableVertexAttribArray(Program::kBindingPosition);
- }
- void OpenGLRenderer::initViewport(int width, int height) {
- mOrthoMatrix.loadOrtho(0, width, height, 0, -1, 1);
- mWidth = width;
- mHeight = height;
- mFirstSnapshot->height = height;
- mFirstSnapshot->viewport.set(0, 0, width, height);
- }
- status_t OpenGLRenderer::prepare(bool opaque) {
- if (mOrientation != -1 && mOrientation % 2 == 1) {
- return prepareDirty(0.0f, 0.0f, mHeight, mWidth, opaque);
- } else {
- return prepareDirty(0.0f, 0.0f, mWidth, mHeight, opaque);
- }
- }
- status_t OpenGLRenderer::prepareDirty(float left, float top, float right, float bottom,
- bool opaque) {
- mCaches.clearGarbage();
- mSnapshot = new Snapshot(mFirstSnapshot,
- SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
- mSnapshot->fbo = getTargetFbo();
- int convertLeft = left;
- int convertTop = top;
- int convertRight = right;
- int convertBottom = bottom;
- switch (mOrientation) {
- case 3:
- rotate(-90);
- translate(-mHeight, 0);
- left = convertTop;
- bottom = mHeight - convertLeft;
- right = convertBottom;
- top = mHeight - convertRight;
- break;
- case 1:
- rotate(90);
- translate(0, -mWidth);
- left = mWidth - convertBottom;
- bottom = convertRight;
- right = mWidth - convertTop;
- top = convertLeft;
- break;
- case 2:
- rotate(180);
- translate(-mWidth, -mHeight);
- left = mWidth - convertRight;
- bottom = mHeight - convertTop;
- right = mWidth - convertLeft;
- top = mHeight - convertBottom;
- break;
- }
- mSaveCount = 1;
- mSnapshot->setClip(left, top, right, bottom);
- mDirtyClip = true;
- updateLayers();
- // If we know that we are going to redraw the entire framebuffer,
- // perform a discard to let the driver know we don't need to preserve
- // the back buffer for this frame.
- if (mCaches.extensions.hasDiscardFramebuffer() &&
- left <= 0.0f && top <= 0.0f && right >= mWidth && bottom >= mHeight) {
- const GLenum attachments[] = { getTargetFbo() == 0 ? GL_COLOR_EXT : GL_COLOR_ATTACHMENT0 };
- glDiscardFramebufferEXT(GL_FRAMEBUFFER, 1, attachments);
- }
- syncState();
- // Functors break the tiling extension in pretty spectacular ways
- // This ensures we don't use tiling when a functor is going to be
- // invoked during the frame
- mSuppressTiling = mCaches.hasRegisteredFunctors();
- mTilingSnapshot = mSnapshot;
- startTiling(mTilingSnapshot, true);
- debugOverdraw(true, true);
- return clear(left, top, right, bottom, opaque);
- }
- status_t OpenGLRenderer::clear(float left, float top, float right, float bottom, bool opaque) {
- if (!opaque) {
- mCaches.enableScissor();
- mCaches.setScissor(left, mSnapshot->height - bottom, right - left, bottom - top);
- glClear(GL_COLOR_BUFFER_BIT);
- return DrawGlInfo::kStatusDrew;
- }
- mCaches.resetScissor();
- return DrawGlInfo::kStatusDone;
- }
- void OpenGLRenderer::syncState() {
- glViewport(0, 0, mWidth, mHeight);
- if (mCaches.blend) {
- glEnable(GL_BLEND);
- } else {
- glDisable(GL_BLEND);
- }
- }
- void OpenGLRenderer::startTiling(const sp<Snapshot>& s, bool opaque) {
- if (!mSuppressTiling) {
- Rect* clip = mTilingSnapshot->clipRect;
- if (s->flags & Snapshot::kFlagIsFboLayer) {
- clip = s->clipRect;
- }
- mCaches.startTiling(clip->left, s->height - clip->bottom,
- clip->right - clip->left, clip->bottom - clip->top, opaque);
- }
- }
- void OpenGLRenderer::endTiling() {
- if (!mSuppressTiling) mCaches.endTiling();
- }
- void OpenGLRenderer::finish() {
- renderOverdraw();
- endTiling();
- if (!suppressErrorChecks()) {
- #if DEBUG_OPENGL
- GLenum status = GL_NO_ERROR;
- while ((status = glGetError()) != GL_NO_ERROR) {
- ALOGD("GL error from OpenGLRenderer: 0x%x", status);
- switch (status) {
- case GL_INVALID_ENUM:
- ALOGE(" GL_INVALID_ENUM");
- break;
- case GL_INVALID_VALUE:
- ALOGE(" GL_INVALID_VALUE");
- break;
- case GL_INVALID_OPERATION:
- ALOGE(" GL_INVALID_OPERATION");
- break;
- case GL_OUT_OF_MEMORY:
- ALOGE(" Out of memory!");
- break;
- }
- }
- #endif
- #if DEBUG_MEMORY_USAGE
- mCaches.dumpMemoryUsage();
- #else
- if (mCaches.getDebugLevel() & kDebugMemory) {
- mCaches.dumpMemoryUsage();
- }
- #endif
- }
- }
- void OpenGLRenderer::interrupt() {
- if (mCaches.currentProgram) {
- if (mCaches.currentProgram->isInUse()) {
- mCaches.currentProgram->remove();
- mCaches.currentProgram = NULL;
- }
- }
- mCaches.unbindMeshBuffer();
- mCaches.unbindIndicesBuffer();
- mCaches.resetVertexPointers();
- mCaches.disbaleTexCoordsVertexArray();
- debugOverdraw(false, false);
- }
- void OpenGLRenderer::resume() {
- sp<Snapshot> snapshot = (mSnapshot != NULL) ? mSnapshot : mFirstSnapshot;
- glViewport(0, 0, snapshot->viewport.getWidth(), snapshot->viewport.getHeight());
- glBindFramebuffer(GL_FRAMEBUFFER, snapshot->fbo);
- debugOverdraw(true, false);
- glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
- mCaches.scissorEnabled = glIsEnabled(GL_SCISSOR_TEST);
- mCaches.enableScissor();
- mCaches.resetScissor();
- dirtyClip();
- mCaches.activeTexture(0);
- mCaches.blend = true;
- glEnable(GL_BLEND);
- glBlendFunc(mCaches.lastSrcMode, mCaches.lastDstMode);
- glBlendEquation(GL_FUNC_ADD);
- }
- void OpenGLRenderer::resumeAfterLayer() {
- sp<Snapshot> snapshot = (mSnapshot != NULL) ? mSnapshot : mFirstSnapshot;
- glViewport(0, 0, snapshot->viewport.getWidth(), snapshot->viewport.getHeight());
- glBindFramebuffer(GL_FRAMEBUFFER, snapshot->fbo);
- debugOverdraw(true, false);
- mCaches.resetScissor();
- dirtyClip();
- }
- void OpenGLRenderer::detachFunctor(Functor* functor) {
- mFunctors.remove(functor);
- }
- void OpenGLRenderer::attachFunctor(Functor* functor) {
- mFunctors.add(functor);
- }
- status_t OpenGLRenderer::invokeFunctors(Rect& dirty) {
- status_t result = DrawGlInfo::kStatusDone;
- size_t count = mFunctors.size();
- if (count > 0) {
- interrupt();
- SortedVector<Functor*> functors(mFunctors);
- mFunctors.clear();
- DrawGlInfo info;
- info.clipLeft = 0;
- info.clipTop = 0;
- info.clipRight = 0;
- info.clipBottom = 0;
- info.isLayer = false;
- info.width = 0;
- info.height = 0;
- memset(info.transform, 0, sizeof(float) * 16);
- for (size_t i = 0; i < count; i++) {
- Functor* f = functors.itemAt(i);
- result |= (*f)(DrawGlInfo::kModeProcess, &info);
- if (result & DrawGlInfo::kStatusDraw) {
- Rect localDirty(info.dirtyLeft, info.dirtyTop, info.dirtyRight, info.dirtyBottom);
- dirty.unionWith(localDirty);
- }
- if (result & DrawGlInfo::kStatusInvoke) {
- mFunctors.add(f);
- }
- }
- resume();
- }
- return result;
- }
- status_t OpenGLRenderer::callDrawGLFunction(Functor* functor, Rect& dirty) {
- interrupt();
- detachFunctor(functor);
- mCaches.enableScissor();
- if (mDirtyClip) {
- setScissorFromClip();
- }
- Rect clip(*mSnapshot->clipRect);
- clip.snapToPixelBoundaries();
- // Since we don't know what the functor will draw, let's dirty
- // tne entire clip region
- if (hasLayer()) {
- dirtyLayerUnchecked(clip, getRegion());
- }
- DrawGlInfo info;
- info.clipLeft = clip.left;
- info.clipTop = clip.top;
- info.clipRight = clip.right;
- info.clipBottom = clip.bottom;
- info.isLayer = hasLayer();
- info.width = getSnapshot()->viewport.getWidth();
- info.height = getSnapshot()->height;
- getSnapshot()->transform->copyTo(&info.transform[0]);
- status_t result = (*functor)(DrawGlInfo::kModeDraw, &info) | DrawGlInfo::kStatusDrew;
- if (result != DrawGlInfo::kStatusDone) {
- Rect localDirty(info.dirtyLeft, info.dirtyTop, info.dirtyRight, info.dirtyBottom);
- dirty.unionWith(localDirty);
- if (result & DrawGlInfo::kStatusInvoke) {
- mFunctors.add(functor);
- }
- }
- resume();
- return result;
- }
- ///////////////////////////////////////////////////////////////////////////////
- // Debug
- ///////////////////////////////////////////////////////////////////////////////
- void OpenGLRenderer::startMark(const char* name) const {
- mCaches.startMark(0, name);
- }
- void OpenGLRenderer::endMark() const {
- mCaches.endMark();
- }
- void OpenGLRenderer::debugOverdraw(bool enable, bool clear) {
- if (mCaches.debugOverdraw && getTargetFbo() == 0) {
- if (clear) {
- mCaches.disableScissor();
- mCaches.stencil.clear();
- }
- if (enable) {
- mCaches.stencil.enableDebugWrite();
- } else {
- mCaches.stencil.disable();
- }
- }
- }
- void OpenGLRenderer::renderOverdraw() {
- if (mCaches.debugOverdraw && getTargetFbo() == 0) {
- const Rect* clip = mTilingSnapshot->clipRect;
- mCaches.enableScissor();
- mCaches.setScissor(clip->left, mTilingSnapshot->height - clip->bottom,
- clip->right - clip->left, clip->bottom - clip->top);
- mCaches.stencil.enableDebugTest(2);
- drawColor(0x2f0000ff, SkXfermode::kSrcOver_Mode);
- mCaches.stencil.enableDebugTest(3);
- drawColor(0x2f00ff00, SkXfermode::kSrcOver_Mode);
- mCaches.stencil.enableDebugTest(4);
- drawColor(0x3fff0000, SkXfermode::kSrcOver_Mode);
- mCaches.stencil.enableDebugTest(4, true);
- drawColor(0x7fff0000, SkXfermode::kSrcOver_Mode);
- mCaches.stencil.disable();
- }
- }
- ///////////////////////////////////////////////////////////////////////////////
- // Layers
- ///////////////////////////////////////////////////////////////////////////////
- bool OpenGLRenderer::updateLayer(Layer* layer, bool inFrame) {
- if (layer->deferredUpdateScheduled && layer->renderer && layer->displayList) {
- OpenGLRenderer* renderer = layer->renderer;
- Rect& dirty = layer->dirtyRect;
- if (inFrame) {
- endTiling();
- debugOverdraw(false, false);
- }
- int ori = mOrientation;
- if (mOrientation != -1) {
- renderer->setOrientation(0);
- }
- renderer->setViewport(layer->layer.getWidth(), layer->layer.getHeight());
- renderer->prepareDirty(dirty.left, dirty.top, dirty.right, dirty.bottom, !layer->isBlend());
- renderer->drawDisplayList(layer->displayList, dirty, DisplayList::kReplayFlag_ClipChildren);
- renderer->finish();
- renderer->setOrientation(ori);
- if (inFrame) {
- resumeAfterLayer();
- startTiling(mSnapshot);
- }
- dirty.setEmpty();
- layer->deferredUpdateScheduled = false;
- layer->renderer = NULL;
- layer->displayList = NULL;
- return true;
- }
- return false;
- }
- void OpenGLRenderer::updateLayers() {
- int count = mLayerUpdates.size();
- if (count > 0) {
- startMark("Layer Updates");
- // Note: it is very important to update the layers in reverse order
- for (int i = count - 1; i >= 0; i--) {
- Layer* layer = mLayerUpdates.itemAt(i);
- updateLayer(layer, false);
- mCaches.resourceCache.decrementRefcount(layer);
- }
- mLayerUpdates.clear();
- glBindFramebuffer(GL_FRAMEBUFFER, getTargetFbo());
- endMark();
- }
- }
- void OpenGLRenderer::pushLayerUpdate(Layer* layer) {
- if (layer) {
- mLayerUpdates.push_back(layer);
- mCaches.resourceCache.incrementRefcount(layer);
- }
- }
- void OpenGLRenderer::clearLayerUpdates() {
- size_t count = mLayerUpdates.size();
- if (count > 0) {
- mCaches.resourceCache.lock();
- for (size_t i = 0; i < count; i++) {
- mCaches.resourceCache.decrementRefcountLocked(mLayerUpdates.itemAt(i));
- }
- mCaches.resourceCache.unlock();
- mLayerUpdates.clear();
- }
- }
- ///////////////////////////////////////////////////////////////////////////////
- // State management
- ///////////////////////////////////////////////////////////////////////////////
- int OpenGLRenderer::getSaveCount() const {
- return mSaveCount;
- }
- int OpenGLRenderer::save(int flags) {
- return saveSnapshot(flags);
- }
- void OpenGLRenderer::restore() {
- if (mSaveCount > 1) {
- restoreSnapshot();
- }
- }
- void OpenGLRenderer::restoreToCount(int saveCount) {
- if (saveCount < 1) saveCount = 1;
- while (mSaveCount > saveCount) {
- restoreSnapshot();
- }
- }
- int OpenGLRenderer::saveSnapshot(int flags) {
- mSnapshot = new Snapshot(mSnapshot, flags);
- return mSaveCount++;
- }
- bool OpenGLRenderer::restoreSnapshot() {
- bool restoreClip = mSnapshot->flags & Snapshot::kFlagClipSet;
- bool restoreLayer = mSnapshot->flags & Snapshot::kFlagIsLayer;
- bool restoreOrtho = mSnapshot->flags & Snapshot::kFlagDirtyOrtho;
- sp<Snapshot> current = mSnapshot;
- sp<Snapshot> previous = mSnapshot->previous;
- if (restoreOrtho) {
- Rect& r = previous->viewport;
- glViewport(r.left, r.top, r.right, r.bottom);
- mOrthoMatrix.load(current->orthoMatrix);
- }
- mSaveCount--;
- mSnapshot = previous;
- if (restoreClip) {
- dirtyClip();
- }
- if (restoreLayer) {
- composeLayer(current, previous);
- }
- return restoreClip;
- }
- ///////////////////////////////////////////////////////////////////////////////
- // Layers
- ///////////////////////////////////////////////////////////////////////////////
- int OpenGLRenderer::saveLayer(float left, float top, float right, float bottom,
- SkPaint* p, int flags) {
- const GLuint previousFbo = mSnapshot->fbo;
- const int count = saveSnapshot(flags);
- if (!mSnapshot->isIgnored()) {
- int alpha = 255;
- SkXfermode::Mode mode;
- if (p) {
- alpha = p->getAlpha();
- mode = getXfermode(p->getXfermode());
- } else {
- mode = SkXfermode::kSrcOver_Mode;
- }
- createLayer(left, top, right, bottom, alpha, mode, flags, previousFbo);
- }
- return count;
- }
- int OpenGLRenderer::saveLayerAlpha(float left, float top, float right, float bottom,
- int alpha, int flags) {
- if (alpha >= 255) {
- return saveLayer(left, top, right, bottom, NULL, flags);
- } else {
- SkPaint paint;
- paint.setAlpha(alpha);
- return saveLayer(left, top, right, bottom, &paint, flags);
- }
- }
- /**
- * Layers are viewed by Skia are slightly different than layers in image editing
- * programs (for instance.) When a layer is created, previously created layers
- * and the frame buffer still receive every drawing command. For instance, if a
- * layer is created and a shape intersecting the bounds of the layers and the
- * framebuffer is draw, the shape will be drawn on both (unless the layer was
- * created with the SkCanvas::kClipToLayer_SaveFlag flag.)
- *
- * A way to implement layers is to create an FBO for each layer, backed by an RGBA
- * texture. Unfortunately, this is inefficient as it requires every primitive to
- * be drawn n + 1 times, where n is the number of active layers. In practice this
- * means, for every primitive:
- * - Switch active frame buffer
- * - Change viewport, clip and projection matrix
- * - Issue the drawing
- *
- * Switching rendering target n + 1 times per drawn primitive is extremely costly.
- * To avoid this, layers are implemented in a different way here, at least in the
- * general case. FBOs are used, as an optimization, when the "clip to layer" flag
- * is set. When this flag is set we can redirect all drawing operations into a
- * single FBO.
- *
- * This implementation relies on the frame buffer being at least RGBA 8888. When
- * a layer is created, only a texture is created, not an FBO. The content of the
- * frame buffer contained within the layer's bounds is copied into this texture
- * using glCopyTexImage2D(). The layer's region is then cleared(1) in the frame
- * buffer and drawing continues as normal. This technique therefore treats the
- * frame buffer as a scratch buffer for the layers.
- *
- * To compose the layers back onto the frame buffer, each layer texture
- * (containing the original frame buffer data) is drawn as a simple quad over
- * the frame buffer. The trick is that the quad is set as the composition
- * destination in the blending equation, and the frame buffer becomes the source
- * of the composition.
- *
- * Drawing layers with an alpha value requires an extra step before composition.
- * An empty quad is drawn over the layer's region in the frame buffer. This quad
- * is drawn with the rgba color (0,0,0,alpha). The alpha value offered by the
- * quad is used to multiply the colors in the frame buffer. This is achieved by
- * changing the GL blend functions for the GL_FUNC_ADD blend equation to
- * GL_ZERO, GL_SRC_ALPHA.
- *
- * Because glCopyTexImage2D() can be slow, an alternative implementation might
- * be use to draw a single clipped layer. The implementation described above
- * is correct in every case.
- *
- * (1) The frame buffer is actually not cleared right away. To allow the GPU
- * to potentially optimize series of calls to glCopyTexImage2D, the frame
- * buffer is left untouched until the first drawing operation. Only when
- * something actually gets drawn are the layers regions cleared.
- */
- bool OpenGLRenderer::createLayer(float left, float top, float right, float bottom,
- int alpha, SkXfermode::Mode mode, int flags, GLuint previousFbo) {
- LAYER_LOGD("Requesting layer %.2fx%.2f", right - left, bottom - top);
- LAYER_LOGD("Layer cache size = %d", mCaches.layerCache.getSize());
- const bool fboLayer = flags & SkCanvas::kClipToLayer_SaveFlag;
- // Window coordinates of the layer
- Rect clip;
- Rect bounds(left, top, right, bottom);
- Rect untransformedBounds(bounds);
- mSnapshot->transform->mapRect(bounds);
- // Layers only make sense if they are in the framebuffer's bounds
- if (bounds.intersect(*mSnapshot->clipRect)) {
- // We cannot work with sub-pixels in this case
- bounds.snapToPixelBoundaries();
- // When the layer is not an FBO, we may use glCopyTexImage so we
- // need to make sure the layer does not extend outside the bounds
- // of the framebuffer
- if (!bounds.intersect(mSnapshot->previous->viewport)) {
- bounds.setEmpty();
- } else if (fboLayer) {
- clip.set(bounds);
- mat4 inverse;
- inverse.loadInverse(*mSnapshot->transform);
- inverse.mapRect(clip);
- clip.snapToPixelBoundaries();
- if (clip.intersect(untransformedBounds)) {
- clip.translate(-left, -top);
- bounds.set(untransformedBounds);
- } else {
- clip.setEmpty();
- }
- }
- } else {
- bounds.setEmpty();
- }
- if (bounds.isEmpty() || bounds.getWidth() > mCaches.maxTextureSize ||
- bounds.getHeight() > mCaches.maxTextureSize ||
- (fboLayer && clip.isEmpty())) {
- mSnapshot->empty = fboLayer;
- } else {
- mSnapshot->invisible = mSnapshot->invisible || (alpha <= ALPHA_THRESHOLD && fboLayer);
- }
- // Bail out if we won't draw in this snapshot
- if (mSnapshot->invisible || mSnapshot->empty) {
- return false;
- }
- mCaches.activeTexture(0);
- Layer* layer = mCaches.layerCache.get(bounds.getWidth(), bounds.getHeight());
- if (!layer) {
- return false;
- }
- layer->setAlpha(alpha, mode);
- layer->layer.set(bounds);
- layer->texCoords.set(0.0f, bounds.getHeight() / float(layer->getHeight()),
- bounds.getWidth() / float(layer->getWidth()), 0.0f);
- layer->setColorFilter(mColorFilter);
- layer->setBlend(true);
- layer->setDirty(false);
- // Save the layer in the snapshot
- mSnapshot->flags |= Snapshot::kFlagIsLayer;
- mSnapshot->layer = layer;
- if (fboLayer) {
- return createFboLayer(layer, bounds, clip, previousFbo);
- } else {
- // Copy the framebuffer into the layer
- layer->bindTexture();
- if (!bounds.isEmpty()) {
- if (layer->isEmpty()) {
- glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
- bounds.left, mSnapshot->height - bounds.bottom,
- layer->getWidth(), layer->getHeight(), 0);
- layer->setEmpty(false);
- } else {
- glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, bounds.left,
- mSnapshot->height - bounds.bottom, bounds.getWidth(), bounds.getHeight());
- }
- // Enqueue the buffer coordinates to clear the corresponding region later
- mLayers.push(new Rect(bounds));
- }
- }
- return true;
- }
- bool OpenGLRenderer::createFboLayer(Layer* layer, Rect& bounds, Rect& clip, GLuint previousFbo) {
- layer->setFbo(mCaches.fboCache.get());
- mSnapshot->region = &mSnapshot->layer->region;
- mSnapshot->flags |= Snapshot::kFlagFboTarget;
- mSnapshot->flags |= Snapshot::kFlagIsFboLayer;
- mSnapshot->fbo = layer->getFbo();
- mSnapshot->resetTransform(-bounds.left, -bounds.top, 0.0f);
- mSnapshot->resetClip(clip.left, clip.top, clip.right, clip.bottom);
- mSnapshot->viewport.set(0.0f, 0.0f, bounds.getWidth(), bounds.getHeight());
- mSnapshot->height = bounds.getHeight();
- mSnapshot->flags |= Snapshot::kFlagDirtyOrtho;
- mSnapshot->orthoMatrix.load(mOrthoMatrix);
- endTiling();
- debugOverdraw(false, false);
- // Bind texture to FBO
- glBindFramebuffer(GL_FRAMEBUFFER, layer->getFbo());
- layer->bindTexture();
- // Initialize the texture if needed
- if (layer->isEmpty()) {
- layer->allocateTexture(GL_RGBA, GL_UNSIGNED_BYTE);
- layer->setEmpty(false);
- }
- glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
- layer->getTexture(), 0);
- startTiling(mSnapshot);
- // Clear the FBO, expand the clear region by 1 to get nice bilinear filtering
- mCaches.enableScissor();
- mCaches.setScissor(clip.left - 1.0f, bounds.getHeight() - clip.bottom - 1.0f,
- clip.getWidth() + 2.0f, clip.getHeight() + 2.0f);
- glClear(GL_COLOR_BUFFER_BIT);
- dirtyClip();
- // Change the ortho projection
- glViewport(0, 0, bounds.getWidth(), bounds.getHeight());
- mOrthoMatrix.loadOrtho(0.0f, bounds.getWidth(), bounds.getHeight(), 0.0f, -1.0f, 1.0f);
- return true;
- }
- /**
- * Read the documentation of createLayer() before doing anything in this method.
- */
- void OpenGLRenderer::composeLayer(sp<Snapshot> current, sp<Snapshot> previous) {
- if (!current->layer) {
- ALOGE("Attempting to compose a layer that does not exist");
- return;
- }
- const bool fboLayer = current->flags & Snapshot::kFlagIsFboLayer;
- if (fboLayer) {
- endTiling();
- // Detach the texture from the FBO
- glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
- // Unbind current FBO and restore previous one
- glBindFramebuffer(GL_FRAMEBUFFER, previous->fbo);
- debugOverdraw(true, false);
- startTiling(previous);
- }
- Layer* layer = current->layer;
- const Rect& rect = layer->layer;
- if (!fboLayer && layer->getAlpha() < 255) {
- drawColorRect(rect.left, rect.top, rect.right, rect.bottom,
- layer->getAlpha() << 24, SkXfermode::kDstIn_Mode, true);
- // Required below, composeLayerRect() will divide by 255
- layer->setAlpha(255);
- }
- mCaches.unbindMeshBuffer();
- mCaches.activeTexture(0);
- // When the layer is stored in an FBO, we can save a bit of fillrate by
- // drawing only the dirty region
- if (fboLayer) {
- dirtyLayer(rect.left, rect.top, rect.right, rect.bottom, *previous->transform);
- if (layer->getColorFilter()) {
- setupColorFilter(layer->getColorFilter());
- }
- composeLayerRegion(layer, rect);
- if (layer->getColorFilter()) {
- resetColorFilter();
- }
- } else if (!rect.isEmpty()) {
- dirtyLayer(rect.left, rect.top, rect.right, rect.bottom);
- composeLayerRect(layer, rect, true);
- }
- if (fboLayer) {
- // Note: No need to use glDiscardFramebufferEXT() since we never
- // create/compose layers that are not on screen with this
- // code path
- // See LayerRenderer::destroyLayer(Layer*)
- // Put the FBO name back in the cache, if it doesn't fit, it will be destroyed
- mCaches.fboCache.put(current->fbo);
- layer->setFbo(0);
- }
- dirtyClip();
- // Failing to add the layer to the cache should happen only if the layer is too large
- if (!mCaches.layerCache.put(layer)) {
- LAYER_LOGD("Deleting layer");
- Caches::getInstance().resourceCache.decrementRefcount(layer);
- }
- }
- void OpenGLRenderer::drawTextureLayer(Layer* layer, const Rect& rect) {
- float alpha = layer->getAlpha() / 255.0f;
- setupDraw();
- if (layer->getRenderTarget() == GL_TEXTURE_2D) {
- setupDrawWithTexture();
- } else {
- setupDrawWithExternalTexture();
- }
- setupDrawTextureTransform();
- setupDrawColor(alpha, alpha, alpha, alpha);
- setupDrawColorFilter();
- setupDrawBlending(layer->isBlend() || alpha < 1.0f, layer->getMode());
- setupDrawProgram();
- setupDrawPureColorUniforms();
- setupDrawColorFilterUniforms();
- if (layer->getRenderTarget() == GL_TEXTURE_2D) {
- setupDrawTexture(layer->getTexture());
- } else {
- setupDrawExternalTexture(layer->getTexture());
- }
- if (mSnapshot->transform->isPureTranslate() &&
- layer->getWidth() == (uint32_t) rect.getWidth() &&
- layer->getHeight() == (uint32_t) rect.getHeight()) {
- const float x = (int) floorf(rect.left + mSnapshot->transform->getTranslateX() + 0.5f);
- const float y = (int) floorf(rect.top + mSnapshot->transform->getTranslateY() + 0.5f);
- layer->setFilter(GL_NEAREST);
- setupDrawModelView(x, y, x + rect.getWidth(), y + rect.getHeight(), true);
- } else {
- layer->setFilter(GL_LINEAR);
- setupDrawModelView(rect.left, rect.top, rect.right, rect.bottom);
- }
- setupDrawTextureTransformUniforms(layer->getTexTransform());
- setupDrawMesh(&mMeshVertices[0].position[0], &mMeshVertices[0].texture[0]);
- glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount);
- finishDrawTexture();
- }
- void OpenGLRenderer::composeLayerRect(Layer* layer, const Rect& rect, bool swap) {
- if (!layer->isTextureLayer()) {
- const Rect& texCoords = layer->texCoords;
- resetDrawTextureTexCoords(texCoords.left, texCoords.top,
- texCoords.right, texCoords.bottom);
- float x = rect.left;
- float y = rect.top;
- bool simpleTransform = mSnapshot->transform->isPureTranslate() &&
- layer->getWidth() == (uint32_t) rect.getWidth() &&
- layer->getHeight() == (uint32_t) rect.getHeight();
- if (simpleTransform) {
- // When we're swapping, the layer is already in screen coordinates
- if (!swap) {
- x = (int) floorf(rect.left + mSnapshot->transform->getTranslateX() + 0.5f);
- y = (int) floorf(rect.top + mSnapshot->transform->getTranslateY() + 0.5f);
- }
- layer->setFilter(GL_NEAREST, true);
- } else {
- layer->setFilter(GL_LINEAR, true);
- }
- drawTextureMesh(x, y, x + rect.getWidth(), y + rect.getHeight(),
- layer->getTexture(), layer->getAlpha() / 255.0f,
- layer->getMode(), layer->isBlend(),
- &mMeshVertices[0].position[0], &mMeshVertices[0].texture[0],
- GL_TRIANGLE_STRIP, gMeshCount, swap, swap || simpleTransform);
- resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f);
- } else {
- resetDrawTextureTexCoords(0.0f, 1.0f, 1.0f, 0.0f);
- drawTextureLayer(layer, rect);
- resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f);
- }
- }
- void OpenGLRenderer::composeLayerRegion(Layer* layer, const Rect& rect) {
- if (layer->region.isRect()) {
- layer->setRegionAsRect();
- composeLayerRect(layer, layer->regionRect);
- layer->region.clear();
- return;
- }
- // TODO: See LayerRenderer.cpp::generateMesh() for important
- // information about this implementation
- if (CC_LIKELY(!layer->region.isEmpty())) {
- size_t count;
- const android::Rect* rects = layer->region.getArray(&count);
- const float alpha = layer->getAlpha() / 255.0f;
- const float texX = 1.0f / float(layer->getWidth());
- const float texY = 1.0f / float(layer->getHeight());
- const float height = rect.getHeight();
- TextureVertex* mesh = mCaches.getRegionMesh();
- GLsizei numQuads = 0;
- setupDraw();
- setupDrawWithTexture();
- setupDrawColor(alpha, alpha, alpha, alpha);
- setupDrawColorFilter();
- setupDrawBlending(layer->isBlend() || alpha < 1.0f, layer->getMode(), false);
- setupDrawProgram();
- setupDrawDirtyRegionsDisabled();
- setupDrawPureColorUniforms();
- setupDrawColorFilterUniforms();
- setupDrawTexture(layer->getTexture());
- if (mSnapshot->transform->isPureTranslate()) {
- const float x = (int) floorf(rect.left + mSnapshot->transform->getTranslateX() + 0.5f);
- const float y = (int) floorf(rect.top + mSnapshot->transform->getTranslateY() + 0.5f);
- layer->setFilter(GL_NEAREST);
- setupDrawModelViewTranslate(x, y, x + rect.getWidth(), y + rect.getHeight(), true);
- } else {
- layer->setFilter(GL_LINEAR);
- setupDrawModelViewTranslate(rect.left, rect.top, rect.right, rect.bottom);
- }
- setupDrawMeshIndices(&mesh[0].position[0], &mesh[0].texture[0]);
- for (size_t i = 0; i < count; i++) {
- const android::Rect* r = &rects[i];
- const float u1 = r->left * texX;
- const float v1 = (height - r->top) * texY;
- const float u2 = r->right * texX;
- const float v2 = (height - r->bottom) * texY;
- // TODO: Reject quads outside of the clip
- TextureVertex::set(mesh++, r->left, r->top, u1, v1);
- TextureVertex::set(mesh++, r->right, r->top, u2, v1);
- TextureVertex::set(mesh++, r->left, r->bottom, u1, v2);
- TextureVertex::set(mesh++, r->right, r->bottom, u2, v2);
- numQuads++;
- if (numQuads >= REGION_MESH_QUAD_COUNT) {
- glDrawElements(GL_TRIANGLES, numQuads * 6, GL_UNSIGNED_SHORT, NULL);
- numQuads = 0;
- mesh = mCaches.getRegionMesh();
- }
- }
- if (numQuads > 0) {
- glDrawElements(GL_TRIANGLES, numQuads * 6, GL_UNSIGNED_SHORT, NULL);
- }
- finishDrawTexture();
- #if DEBUG_LAYERS_AS_REGIONS
- drawRegionRects(layer->region);
- #endif
- layer->region.clear();
- }
- }
- void OpenGLRenderer::drawRegionRects(const Region& region) {
- #if DEBUG_LAYERS_AS_REGIONS
- size_t count;
- const android::Rect* rects = region.getArray(&count);
- uint32_t colors[] = {
- 0x7fff0000, 0x7f00ff00,
- 0x7f0000ff, 0x7fff00ff,
- };
- int offset = 0;
- int32_t top = rects[0].top;
- for (size_t i = 0; i < count; i++) {
- if (top != rects[i].top) {
- offset ^= 0x2;
- top = rects[i].top;
- }
- Rect r(rects[i].left, rects[i].top, rects[i].right, rects[i].bottom);
- drawColorRect(r.left, r.top, r.right, r.bottom, colors[offset + (i & 0x1)],
- SkXfermode::kSrcOver_Mode);
- }
- #endif
- }
- void OpenGLRenderer::dirtyLayer(const float left, const float top,
- const float right, const float bottom, const mat4 transform) {
- if (hasLayer()) {
- Rect bounds(left, top, right, bottom);
- transform.mapRect(bounds);
- dirtyLayerUnchecked(bounds, getRegion());
- }
- }
- void OpenGLRenderer::dirtyLayer(const float left, const float top,
- const float right, const float bottom) {
- if (hasLayer()) {
- Rect bounds(left, top, right, bottom);
- dirtyLayerUnchecked(bounds, getRegion());
- }
- }
- void OpenGLRenderer::dirtyLayerUnchecked(Rect& bounds, Region* region) {
- if (bounds.intersect(*mSnapshot->clipRect)) {
- bounds.snapToPixelBoundaries();
- android::Rect dirty(bounds.left, bounds.top, bounds.right, bounds.bottom);
- if (!dirty.isEmpty()) {
- region->orSelf(dirty);
- }
- }
- }
- void OpenGLRenderer::clearLayerRegions() {
- const size_t count = mLayers.size();
- if (count == 0) return;
- if (!mSnapshot->isIgnored()) {
- // Doing several glScissor/glClear here can negatively impact
- // GPUs with a tiler architecture, instead we draw quads with
- // the Clear blending mode
- // The list contains bounds that have already been clipped
- // against their initial clip rect, and the current clip
- // is likely different so we need to disable clipping here
- bool scissorChanged = mCaches.disableScissor();
- Vertex mesh[count * 6];
- Vertex* vertex = mesh;
- for (uint32_t i = 0; i < count; i++) {
- Rect* bounds = mLayers.itemAt(i);
- Vertex::set(vertex++, bounds->left, bounds->bottom);
- Vertex::set(vertex++, bounds->left, bounds->top);
- Vertex::set(vertex++, bounds->right, bounds->top);
- Vertex::set(vertex++, bounds->left, bounds->bottom);
- Vertex::set(vertex++, bounds->right, bounds->top);
- Vertex::set(vertex++, bounds->right, bounds->bottom);
- delete bounds;
- }
- setupDraw(false);
- setupDrawColor(0.0f, 0.0f, 0.0f, 1.0f);
- setupDrawBlending(true, SkXfermode::kClear_Mode);
- setupDrawProgram();
- setupDrawPureColorUniforms();
- setupDrawModelViewTranslate(0.0f, 0.0f, 0.0f, 0.0f, true);
- setupDrawVertices(&mesh[0].position[0]);
- glDrawArrays(GL_TRIANGLES, 0, count * 6);
- if (scissorChanged) mCaches.enableScissor();
- } else {
- for (uint32_t i = 0; i < count; i++) {
- delete mLayers.itemAt(i);
- }
- }
- mLayers.clear();
- }
- ///////////////////////////////////////////////////////////////////////////////
- // Transforms
- ///////////////////////////////////////////////////////////////////////////////
- void OpenGLRenderer::translate(float dx, float dy) {
- mSnapshot->transform->translate(dx, dy, 0.0f);
- }
- void OpenGLRenderer::rotate(float degrees) {
- mSnapshot->transform->rotate(degrees, 0.0f, 0.0f, 1.0f);
- }
- void OpenGLRenderer::scale(float sx, float sy) {
- mSnapshot->transform->scale(sx, sy, 1.0f);
- }
- void OpenGLRenderer::skew(float sx, float sy) {
- mSnapshot->transform->skew(sx, sy);
- }
- void OpenGLRenderer::setMatrix(SkMatrix* matrix) {
- if (matrix) {
- mSnapshot->transform->load(*matrix);
- } else {
- mSnapshot->transform->loadIdentity();
- }
- }
- void OpenGLRenderer::getMatrix(SkMatrix* matrix) {
- mSnapshot->transform->copyTo(*matrix);
- }
- void OpenGLRenderer::concatMatrix(SkMatrix* matrix) {
- SkMatrix transform;
- mSnapshot->transform->copyTo(transform);
- transform.preConcat(*matrix);
- mSnapshot->transform->load(transform);
- }
- ///////////////////////////////////////////////////////////////////////////////
- // Clipping
- ///////////////////////////////////////////////////////////////////////////////
- void OpenGLRenderer::setScissorFromClip() {
- Rect clip(*mSnapshot->clipRect);
- clip.snapToPixelBoundaries();
- if (mCaches.setScissor(clip.left, mSnapshot->height - clip.bottom,
- clip.getWidth(), clip.getHeight())) {
- mDirtyClip = false;
- }
- }
- const Rect& OpenGLRenderer::getClipBounds() {
- return mSnapshot->getLocalClip();
- }
- bool OpenGLRenderer::quickRejectNoScissor(float left, float top, float right, float bottom) {
- if (mSnapshot->isIgnored()) {
- return true;
- }
- Rect r(left, top, right, bottom);
- mSnapshot->transform->mapRect(r);
- r.snapToPixelBoundaries();
- Rect clipRect(*mSnapshot->clipRect);
- clipRect.snapToPixelBoundaries();
- return !clipRect.intersects(r);
- }
- bool OpenGLRenderer::quickRejectNoScissor(float left, float top, float right, float bottom,
- Rect& transformed, Rect& clip) {
- if (mSnapshot->isIgnored()) {
- return true;
- }
- transformed.set(left, top, right, bottom);
- mSnapshot->transform->mapRect(transformed);
- transformed.snapToPixelBoundaries();
- clip.set(*mSnapshot->clipRect);
- clip.snapToPixelBoundaries();
- return !clip.intersects(transformed);
- }
- bool OpenGLRenderer::quickRejectPreStroke(float left, float top, float right, float bottom, SkPaint* paint) {
- if (paint->getStyle() != SkPaint::kFill_Style) {
- float outset = paint->getStrokeWidth() * 0.5f;
- return quickReject(left - outset, top - outset, right + outset, bottom + outset);
- } else {
- return quickReject(left, top, right, bottom);
- }
- }
- bool OpenGLRenderer::quickReject(float left, float top, float right, float bottom) {
- if (mSnapshot->isIgnored() || bottom <= top || right <= left) {
- return true;
- }
- Rect r(left, top, right, bottom);
- mSnapshot->transform->mapRect(r);
- r.snapToPixelBoundaries();
- Rect clipRect(*mSnapshot->clipRect);
- clipRect.snapToPixelBoundaries();
- bool rejected = !clipRect.intersects(r);
- if (!isDeferred() && !rejected) {
- mCaches.setScissorEnabled(mScissorOptimizationDisabled || !clipRect.contains(r));
- }
- return rejected;
- }
- bool OpenGLRenderer::clipRect(float left, float top, float right, float bottom, SkRegion::Op op) {
- bool clipped = mSnapshot->clip(left, top, right, bottom, op);
- if (clipped) {
- dirtyClip();
- }
- return !mSnapshot->clipRect->isEmpty();
- }
- Rect* OpenGLRenderer::getClipRect() {
- return mSnapshot->clipRect;
- }
- ///////////////////////////////////////////////////////////////////////////////
- // Drawing commands
- ///////////////////////////////////////////////////////////////////////////////
- void OpenGLRenderer::setupDraw(bool clear) {
- // TODO: It would be best if we could do this before quickReject()
- // changes the scissor test state
- if (clear) clearLayerRegions();
- if (mDirtyClip) {
- setScissorFromClip();
- }
- mDescription.reset();
- mSetShaderColor = false;
- mColorSet = false;
- mColorA = mColorR = mColorG = mColorB = 0.0f;
- mTextureUnit = 0;
- mTrackDirtyRegions = true;
- }
- void OpenGLRenderer::setupDrawWithTexture(bool isAlpha8) {
- mDescription.hasTexture = true;
- mDescription.hasAlpha8Texture = isAlpha8;
- }
- void OpenGLRenderer::setupDrawWithExternalTexture() {
- mDescription.hasExternalTexture = true;
- }
- void OpenGLRenderer::setupDrawNoTexture() {
- mCaches.disbaleTexCoordsVertexArray();
- }
- void OpenGLRenderer::setupDrawAA() {
- mDescription.isAA = true;
- }
- void OpenGLRenderer::setupDrawVertexShape() {
- mDescription.isVertexShape = true;
- }
- void OpenGLRenderer::setupDrawPoint(float pointSize) {
- mDescription.isPoint = true;
- mDescription.pointSize = pointSize;
- }
- void OpenGLRenderer::setupDrawColor(int color) {
- setupDrawColor(color, (color >> 24) & 0xFF);
- }
- void OpenGLRenderer::setupDrawColor(int color, int alpha) {
- mColorA = alpha / 255.0f;
- // Second divide of a by 255 is an optimization, allowing us to simply multiply
- // the rgb values by a instead of also dividing by 255
- const float a = mColorA / 255.0f;
- mColorR = a * ((color >> 16) & 0xFF);
- mColorG = a * ((color >> 8) & 0xFF);
- mColorB = a * ((color ) & 0xFF);
- mColorSet = true;
- mSetShaderColor = mDescription.setColor(mColorR, mColorG, mColorB, mColorA);
- }
- void OpenGLRenderer::setupDrawAlpha8Color(int color, int alpha) {
- mColorA = alpha / 255.0f;
- // Double-divide of a by 255 is an optimization, allowing us to simply multiply
- // the rgb values by a instead of also dividing by 255
- const float a = mColorA / 255.0f;
- mColorR = a * ((color >> 16) & 0xFF);
- mColorG = a * ((color >> 8) & 0xFF);
- mColorB = a * ((color ) & 0xFF);
- mColorSet = true;
- mSetShaderColor = mDescription.setAlpha8Color(mColorR, mColorG, mColorB, mColorA);
- }
- void OpenGLRenderer::setupDrawTextGamma(const SkPaint* paint) {
- mCaches.fontRenderer->describe(mDescription, paint);
- }
- void OpenGLRenderer::setupDrawColor(float r, float g, float b, float a) {
- mColorA = a;
- mColorR = r;
- mColorG = g;
- mColorB = b;
- mColorSet = true;
- mSetShaderColor = mDescription.setColor(r, g, b, a);
- }
- void OpenGLRenderer::setupDrawShader() {
- if (mShader) {
- mShader->describe(mDescription, mCaches.extensions);
- }
- }
- void OpenGLRenderer::setupDrawColorFilter() {
- if (mColorFilter) {
- mColorFilter->describe(mDescription, mCaches.extensions);
- }
- }
- void OpenGLRenderer::accountForClear(SkXfermode::Mode mode) {
- if (mColorSet && mode == SkXfermode::kClear_Mode) {
- mColorA = 1.0f;
- mColorR = mColorG = mColorB = 0.0f;
- mSetShaderColor = mDescription.modulate = true;
- }
- }
- void OpenGLRenderer::setupDrawBlending(SkXfermode::Mode mode, bool swapSrcDst) {
- // When the blending mode is kClear_Mode, we need to use a modulate color
- // argb=1,0,0,0
- accountForClear(mode);
- chooseBlending((mColorSet && mColorA < 1.0f) || (mShader && mShader->blend()), mode,
- mDescription, swapSrcDst);
- }
- void OpenGLRenderer::setupDrawBlending(bool blend, SkXfermode::Mode mode, bool swapSrcDst) {
- // When the blending mode is kClear_Mode, we need to use a modulate color
- // argb=1,0,0,0
- accountForClear(mode);
- chooseBlending(blend || (mColorSet && mColorA < 1.0f) || (mShader && mShader->blend()) ||
- (mColorFilter && mColorFilter->blend()), mode, mDescription, swapSrcDst);
- }
- void OpenGLRenderer::setupDrawP