diff options
Diffstat (limited to 'libs/hwui/OpenGLRenderer.cpp')
| -rw-r--r--[-rwxr-xr-x] | libs/hwui/OpenGLRenderer.cpp | 2001 |
1 files changed, 1111 insertions, 890 deletions
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp index 355a31f..3781969 100755..100644 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -14,7 +14,26 @@ * limitations under the License. */ -#define LOG_TAG "OpenGLRenderer" +#include "OpenGLRenderer.h" + +#include "DeferredDisplayList.h" +#include "DisplayListRenderer.h" +#include "GammaFontRenderer.h" +#include "Glop.h" +#include "GlopBuilder.h" +#include "Patch.h" +#include "PathTessellator.h" +#include "Properties.h" +#include "RenderNode.h" +#include "renderstate/MeshState.h" +#include "renderstate/RenderState.h" +#include "ShadowTessellator.h" +#include "SkiaShader.h" +#include "Vector.h" +#include "VertexBuffer.h" +#include "utils/GLUtils.h" +#include "utils/PaintUtils.h" +#include "utils/TraceUtils.h" #include <stdlib.h> #include <stdint.h> @@ -32,111 +51,30 @@ #include <ui/Rect.h> -#include "OpenGLRenderer.h" -#include "DeferredDisplayList.h" -#include "DisplayListRenderer.h" -#include "Fence.h" -#include "RenderState.h" -#include "PathTessellator.h" -#include "Properties.h" -#include "ShadowTessellator.h" -#include "SkiaShader.h" -#include "utils/GLUtils.h" -#include "utils/TraceUtils.h" -#include "Vector.h" -#include "VertexBuffer.h" - #if DEBUG_DETAILED_EVENTS #define EVENT_LOGD(...) eventMarkDEBUG(__VA_ARGS__) #else #define EVENT_LOGD(...) #endif +#define USE_GLOPS true + namespace android { namespace uirenderer { -static GLenum getFilter(const SkPaint* paint) { - if (!paint || paint->getFilterLevel() != SkPaint::kNone_FilterLevel) { - return GL_LINEAR; - } - return 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::kModulate_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::kModulate_Mode, GL_DST_COLOR, GL_ZERO }, - { SkXfermode::kScreen_Mode, GL_ONE_MINUS_DST_COLOR, GL_ONE } -}; - -/////////////////////////////////////////////////////////////////////////////// -// Functions -/////////////////////////////////////////////////////////////////////////////// - -template<typename T> -static inline T min(T a, T b) { - return a < b ? a : b; -} - /////////////////////////////////////////////////////////////////////////////// // Constructors/destructor /////////////////////////////////////////////////////////////////////////////// OpenGLRenderer::OpenGLRenderer(RenderState& renderState) - : mFrameStarted(false) + : mState(*this) , mCaches(Caches::getInstance()) - , mExtensions(Extensions::getInstance()) , mRenderState(renderState) + , mFrameStarted(false) , mScissorOptimizationDisabled(false) , mSuppressTiling(false) , mFirstFrameAfterResize(true) + , mDirty(false) , mLightCenter((Vector3){FLT_MIN, FLT_MIN, FLT_MIN}) , mLightRadius(FLT_MIN) , mAmbientShadowAlpha(0) @@ -145,7 +83,7 @@ OpenGLRenderer::OpenGLRenderer(RenderState& renderState) memset(&mDrawModifiers, 0, sizeof(mDrawModifiers)); mDrawModifiers.mOverrideLayerAlpha = 1.0f; - memcpy(mMeshVertices, gMeshVertices, sizeof(gMeshVertices)); + memcpy(mMeshVertices, kUnitQuadVertices, sizeof(kUnitQuadVertices)); } OpenGLRenderer::~OpenGLRenderer() { @@ -179,28 +117,26 @@ void OpenGLRenderer::initLight(const Vector3& lightCenter, float lightRadius, void OpenGLRenderer::onViewportInitialized() { glDisable(GL_DITHER); glClearColor(0.0f, 0.0f, 0.0f, 0.0f); - - glEnableVertexAttribArray(Program::kBindingPosition); mFirstFrameAfterResize = true; } void OpenGLRenderer::setupFrameState(float left, float top, float right, float bottom, bool opaque) { mCaches.clearGarbage(); - initializeSaveStack(left, top, right, bottom, mLightCenter); + mState.initializeSaveStack(left, top, right, bottom, mLightCenter); mOpaque = opaque; mTilingClip.set(left, top, right, bottom); } -status_t OpenGLRenderer::startFrame() { - if (mFrameStarted) return DrawGlInfo::kStatusDone; +void OpenGLRenderer::startFrame() { + if (mFrameStarted) return; mFrameStarted = true; - mDirtyClip = true; + mState.setDirtyClip(true); discardFramebuffer(mTilingClip.left, mTilingClip.top, mTilingClip.right, mTilingClip.bottom); - mRenderState.setViewport(getWidth(), getHeight()); + mRenderState.setViewport(mState.getWidth(), mState.getHeight()); // Functors break the tiling extension in pretty spectacular ways // This ensures we don't use tiling when a functor is going to be @@ -213,11 +149,11 @@ status_t OpenGLRenderer::startFrame() { debugOverdraw(true, true); - return clear(mTilingClip.left, mTilingClip.top, + clear(mTilingClip.left, mTilingClip.top, mTilingClip.right, mTilingClip.bottom, mOpaque); } -status_t OpenGLRenderer::prepareDirty(float left, float top, +void OpenGLRenderer::prepareDirty(float left, float top, float right, float bottom, bool opaque) { setupFrameState(left, top, right, bottom, opaque); @@ -227,21 +163,19 @@ status_t OpenGLRenderer::prepareDirty(float left, float top, // for each layer and wait until the first drawing command // to start the frame if (currentSnapshot()->fbo == 0) { - syncState(); + mRenderState.blend().syncEnabled(); updateLayers(); } else { - return startFrame(); + startFrame(); } - - return DrawGlInfo::kStatusDone; } void OpenGLRenderer::discardFramebuffer(float left, float top, float right, float bottom) { // 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 (mExtensions.hasDiscardFramebuffer() && - left <= 0.0f && top <= 0.0f && right >= getWidth() && bottom >= getHeight()) { + if (mCaches.extensions().hasDiscardFramebuffer() && + left <= 0.0f && top <= 0.0f && right >= mState.getWidth() && bottom >= mState.getHeight()) { const bool isFbo = getTargetFbo() == 0; const GLenum attachments[] = { isFbo ? (const GLenum) GL_COLOR_EXT : (const GLenum) GL_COLOR_ATTACHMENT0, @@ -250,24 +184,16 @@ void OpenGLRenderer::discardFramebuffer(float left, float top, float right, floa } } -status_t OpenGLRenderer::clear(float left, float top, float right, float bottom, bool opaque) { +void OpenGLRenderer::clear(float left, float top, float right, float bottom, bool opaque) { if (!opaque) { - mCaches.enableScissor(); - mCaches.setScissor(left, getViewportHeight() - bottom, right - left, bottom - top); + mRenderState.scissor().setEnabled(true); + mRenderState.scissor().set(left, getViewportHeight() - bottom, right - left, bottom - top); glClear(GL_COLOR_BUFFER_BIT); - return DrawGlInfo::kStatusDrew; + mDirty = true; + return; } - mCaches.resetScissor(); - return DrawGlInfo::kStatusDone; -} - -void OpenGLRenderer::syncState() { - if (mCaches.blend) { - glEnable(GL_BLEND); - } else { - glDisable(GL_BLEND); - } + mRenderState.scissor().reset(); } void OpenGLRenderer::startTilingCurrentClip(bool opaque, bool expand) { @@ -307,13 +233,9 @@ void OpenGLRenderer::endTiling() { if (!mSuppressTiling) mCaches.endTiling(); } -void OpenGLRenderer::finish() { +bool OpenGLRenderer::finish() { renderOverdraw(); endTiling(); - - for (size_t i = 0; i < mTempPaths.size(); i++) { - delete mTempPaths[i]; - } mTempPaths.clear(); // When finish() is invoked on FBO 0 we've reached the end @@ -338,6 +260,8 @@ void OpenGLRenderer::finish() { } mFrameStarted = false; + + return reportAndClearDirty(); } void OpenGLRenderer::resumeAfterLayer() { @@ -345,14 +269,14 @@ void OpenGLRenderer::resumeAfterLayer() { mRenderState.bindFramebuffer(currentSnapshot()->fbo); debugOverdraw(true, false); - mCaches.resetScissor(); + mRenderState.scissor().reset(); dirtyClip(); } -status_t OpenGLRenderer::callDrawGLFunction(Functor* functor, Rect& dirty) { - if (currentSnapshot()->isIgnored()) return DrawGlInfo::kStatusDone; +void OpenGLRenderer::callDrawGLFunction(Functor* functor, Rect& dirty) { + if (mState.currentlyIgnored()) return; - Rect clip(*currentClipRect()); + Rect clip(mState.currentClipRect()); clip.snapToPixelBoundaries(); // Since we don't know what the functor will draw, let's dirty @@ -371,12 +295,12 @@ status_t OpenGLRenderer::callDrawGLFunction(Functor* functor, Rect& dirty) { info.height = getViewportHeight(); currentTransform()->copyTo(&info.transform[0]); - bool prevDirtyClip = mDirtyClip; + bool prevDirtyClip = mState.getDirtyClip(); // setup GL state for functor - if (mDirtyClip) { + if (mState.getDirtyClip()) { setStencilFromClip(); // can issue draws, so must precede enableScissor()/interrupt() } - if (mCaches.enableScissor() || prevDirtyClip) { + if (mRenderState.scissor().setEnabled(true) || prevDirtyClip) { setScissorFromClip(); } @@ -384,7 +308,7 @@ status_t OpenGLRenderer::callDrawGLFunction(Functor* functor, Rect& dirty) { // Scissor may have been modified, reset dirty clip dirtyClip(); - return DrawGlInfo::kStatusDrew; + mDirty = true; } /////////////////////////////////////////////////////////////////////////////// @@ -402,8 +326,6 @@ void OpenGLRenderer::eventMarkDEBUG(const char* fmt, ...) const { va_end(ap); eventMark(buf); -#else - (void)fmt; #endif } @@ -428,27 +350,29 @@ void OpenGLRenderer::renderOverdraw() { if (mCaches.debugOverdraw && getTargetFbo() == 0) { const Rect* clip = &mTilingClip; - mCaches.enableScissor(); - mCaches.setScissor(clip->left, firstSnapshot()->getViewportHeight() - clip->bottom, - clip->right - clip->left, clip->bottom - clip->top); + mRenderState.scissor().setEnabled(true); + mRenderState.scissor().set(clip->left, + mState.firstSnapshot()->getViewportHeight() - clip->bottom, + clip->right - clip->left, + clip->bottom - clip->top); // 1x overdraw - mCaches.stencil.enableDebugTest(2); + mRenderState.stencil().enableDebugTest(2); drawColor(mCaches.getOverdrawColor(1), SkXfermode::kSrcOver_Mode); // 2x overdraw - mCaches.stencil.enableDebugTest(3); + mRenderState.stencil().enableDebugTest(3); drawColor(mCaches.getOverdrawColor(2), SkXfermode::kSrcOver_Mode); // 3x overdraw - mCaches.stencil.enableDebugTest(4); + mRenderState.stencil().enableDebugTest(4); drawColor(mCaches.getOverdrawColor(3), SkXfermode::kSrcOver_Mode); // 4x overdraw and higher - mCaches.stencil.enableDebugTest(4, true); + mRenderState.stencil().enableDebugTest(4, true); drawColor(mCaches.getOverdrawColor(4), SkXfermode::kSrcOver_Mode); - mCaches.stencil.disable(); + mRenderState.stencil().disable(); } } @@ -556,11 +480,11 @@ void OpenGLRenderer::cancelLayerUpdate(Layer* layer) { void OpenGLRenderer::flushLayerUpdates() { ATRACE_NAME("Update HW Layers"); - syncState(); + mRenderState.blend().syncEnabled(); updateLayers(); flushLayers(); // Wait for all the layer updates to be executed - AutoFence fence; + glFinish(); } void OpenGLRenderer::markLayersAsBuildLayers() { @@ -604,9 +528,9 @@ int OpenGLRenderer::saveLayer(float left, float top, float right, float bottom, // force matrix/clip isolation for layer flags |= SkCanvas::kClip_SaveFlag | SkCanvas::kMatrix_SaveFlag; - const int count = saveSnapshot(flags); + const int count = mState.saveSnapshot(flags); - if (!currentSnapshot()->isIgnored()) { + if (!mState.currentlyIgnored()) { createLayer(left, top, right, bottom, paint, flags, convexMask); } @@ -619,7 +543,7 @@ void OpenGLRenderer::calculateLayerBoundsAndClip(Rect& bounds, Rect& clip, bool currentTransform()->mapRect(bounds); // Layers only make sense if they are in the framebuffer's bounds - if (bounds.intersect(*currentClipRect())) { + if (bounds.intersect(mState.currentClipRect())) { // We cannot work with sub-pixels in this case bounds.snapToPixelBoundaries(); @@ -653,17 +577,17 @@ void OpenGLRenderer::updateSnapshotIgnoreForLayer(const Rect& bounds, const Rect if (bounds.isEmpty() || bounds.getWidth() > mCaches.maxTextureSize || bounds.getHeight() > mCaches.maxTextureSize || (fboLayer && clip.isEmpty())) { - mSnapshot->empty = fboLayer; + writableSnapshot()->empty = fboLayer; } else { - mSnapshot->invisible = mSnapshot->invisible || (alpha <= 0 && fboLayer); + writableSnapshot()->invisible = writableSnapshot()->invisible || (alpha <= 0 && fboLayer); } } int OpenGLRenderer::saveLayerDeferred(float left, float top, float right, float bottom, const SkPaint* paint, int flags) { - const int count = saveSnapshot(flags); + const int count = mState.saveSnapshot(flags); - if (!currentSnapshot()->isIgnored() && (flags & SkCanvas::kClipToLayer_SaveFlag)) { + if (!mState.currentlyIgnored() && (flags & SkCanvas::kClipToLayer_SaveFlag)) { // initialize the snapshot as though it almost represents an FBO layer so deferred draw // operations will be able to store and restore the current clip and transform info, and // quick rejection will be correct (for display lists) @@ -673,11 +597,11 @@ int OpenGLRenderer::saveLayerDeferred(float left, float top, float right, float calculateLayerBoundsAndClip(bounds, clip, true); updateSnapshotIgnoreForLayer(bounds, clip, true, getAlphaDirect(paint)); - if (!currentSnapshot()->isIgnored()) { - mSnapshot->resetTransform(-bounds.left, -bounds.top, 0.0f); - mSnapshot->resetClip(clip.left, clip.top, clip.right, clip.bottom); - mSnapshot->initializeViewport(bounds.getWidth(), bounds.getHeight()); - mSnapshot->roundRectClipState = NULL; + if (!mState.currentlyIgnored()) { + writableSnapshot()->resetTransform(-bounds.left, -bounds.top, 0.0f); + writableSnapshot()->resetClip(clip.left, clip.top, clip.right, clip.bottom); + writableSnapshot()->initializeViewport(bounds.getWidth(), bounds.getHeight()); + writableSnapshot()->roundRectClipState = nullptr; } } @@ -737,10 +661,8 @@ int OpenGLRenderer::saveLayerDeferred(float left, float top, float right, float */ bool OpenGLRenderer::createLayer(float left, float top, float right, float bottom, const SkPaint* paint, int flags, const SkPath* convexMask) { - if (kDebugLayers) { - ALOGD("Requesting layer %.2fx%.2f", right - left, bottom - top); - ALOGD("Layer cache size = %d", mCaches.layerCache.getSize()); - } + 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; @@ -751,11 +673,11 @@ bool OpenGLRenderer::createLayer(float left, float top, float right, float botto updateSnapshotIgnoreForLayer(bounds, clip, fboLayer, getAlphaDirect(paint)); // Bail out if we won't draw in this snapshot - if (currentSnapshot()->isIgnored()) { + if (mState.currentlyIgnored()) { return false; } - mCaches.activeTexture(0); + mCaches.textureState().activateTexture(0); Layer* layer = mCaches.layerCache.get(mRenderState, bounds.getWidth(), bounds.getHeight()); if (!layer) { return false; @@ -771,8 +693,8 @@ bool OpenGLRenderer::createLayer(float left, float top, float right, float botto layer->setConvexMask(convexMask); // note: the mask must be cleared before returning to the cache // Save the layer in the snapshot - mSnapshot->flags |= Snapshot::kFlagIsLayer; - mSnapshot->layer = layer; + writableSnapshot()->flags |= Snapshot::kFlagIsLayer; + writableSnapshot()->layer = layer; ATRACE_FORMAT_BEGIN("%ssaveLayer %ux%u", fboLayer ? "" : "unclipped ", @@ -790,7 +712,7 @@ bool OpenGLRenderer::createLayer(float left, float top, float right, float botto // Unfortunately some drivers will turn the entire target texture black // when reading outside of the window. glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, layer->getWidth(), layer->getHeight(), - 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); layer->setEmpty(false); } @@ -799,7 +721,7 @@ bool OpenGLRenderer::createLayer(float left, float top, float right, float botto bounds.getWidth(), bounds.getHeight()); // Enqueue the buffer coordinates to clear the corresponding region later - mLayers.push(new Rect(bounds)); + mLayers.push_back(Rect(bounds)); } } @@ -810,13 +732,13 @@ bool OpenGLRenderer::createFboLayer(Layer* layer, Rect& bounds, Rect& clip) { layer->clipRect.set(clip); layer->setFbo(mCaches.fboCache.get()); - mSnapshot->region = &mSnapshot->layer->region; - mSnapshot->flags |= Snapshot::kFlagFboTarget | 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->initializeViewport(bounds.getWidth(), bounds.getHeight()); - mSnapshot->roundRectClipState = NULL; + writableSnapshot()->region = &writableSnapshot()->layer->region; + writableSnapshot()->flags |= Snapshot::kFlagFboTarget | Snapshot::kFlagIsFboLayer; + writableSnapshot()->fbo = layer->getFbo(); + writableSnapshot()->resetTransform(-bounds.left, -bounds.top, 0.0f); + writableSnapshot()->resetClip(clip.left, clip.top, clip.right, clip.bottom); + writableSnapshot()->initializeViewport(bounds.getWidth(), bounds.getHeight()); + writableSnapshot()->roundRectClipState = nullptr; endTiling(); debugOverdraw(false, false); @@ -831,14 +753,14 @@ bool OpenGLRenderer::createFboLayer(Layer* layer, Rect& bounds, Rect& clip) { } glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, - layer->getTexture(), 0); + layer->getTextureId(), 0); // Expand the startTiling region by 1 startTilingCurrentClip(true, true); // 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, + mRenderState.scissor().setEnabled(true); + mRenderState.scissor().set(clip.left - 1.0f, bounds.getHeight() - clip.bottom - 1.0f, clip.getWidth() + 2.0f, clip.getHeight() + 2.0f); glClear(GL_COLOR_BUFFER_BIT); @@ -863,9 +785,9 @@ void OpenGLRenderer::composeLayer(const Snapshot& removed, const Snapshot& resto const bool fboLayer = removed.flags & Snapshot::kFlagIsFboLayer; bool clipRequired = false; - calculateQuickRejectForScissor(rect.left, rect.top, rect.right, rect.bottom, - &clipRequired, NULL, false); // safely ignore return, should never be rejected - mCaches.setScissorEnabled(mScissorOptimizationDisabled || clipRequired); + mState.calculateQuickRejectForScissor(rect.left, rect.top, rect.right, rect.bottom, + &clipRequired, nullptr, false); // safely ignore return, should never be rejected + mRenderState.scissor().setEnabled(mScissorOptimizationDisabled || clipRequired); if (fboLayer) { endTiling(); @@ -893,9 +815,9 @@ void OpenGLRenderer::composeLayer(const Snapshot& removed, const Snapshot& resto layer->setAlpha(255); } - mCaches.unbindMeshBuffer(); + mRenderState.meshState().unbindMeshBuffer(); - mCaches.activeTexture(0); + mCaches.textureState().activateTexture(0); // When the layer is stored in an FBO, we can save a bit of fillrate by // drawing only the dirty region @@ -908,7 +830,7 @@ void OpenGLRenderer::composeLayer(const Snapshot& removed, const Snapshot& resto save(0); // the layer contains screen buffer content that shouldn't be alpha modulated // (and any necessary alpha modulation was handled drawing into the layer) - mSnapshot->alpha = 1.0f; + writableSnapshot()->alpha = 1.0f; composeLayerRect(layer, rect, true); restore(); } @@ -916,18 +838,29 @@ void OpenGLRenderer::composeLayer(const Snapshot& removed, const Snapshot& resto dirtyClip(); // Failing to add the layer to the cache should happen only if the layer is too large - layer->setConvexMask(NULL); + layer->setConvexMask(nullptr); if (!mCaches.layerCache.put(layer)) { - if (kDebugLayers) { - ALOGD("Deleting layer"); - } - layer->decStrong(0); + LAYER_LOGD("Deleting layer"); + layer->decStrong(nullptr); } } void OpenGLRenderer::drawTextureLayer(Layer* layer, const Rect& rect) { - float alpha = getLayerAlpha(layer); + if (USE_GLOPS) { + bool snap = !layer->getForceFilter() + && layer->getWidth() == (uint32_t) rect.getWidth() + && layer->getHeight() == (uint32_t) rect.getHeight(); + Glop glop; + GlopBuilder(mRenderState, mCaches, &glop) + .setMeshTexturedUvQuad(nullptr, Rect(0, 1, 1, 0)) // TODO: simplify with VBO + .setFillTextureLayer(*layer, getLayerAlpha(layer)) + .setTransform(currentSnapshot()->getOrthoMatrix(), *currentTransform(), false) + .setModelViewMapUnitToRectOptionalSnap(snap, rect) + .setRoundRectClipState(currentSnapshot()->roundRectClipState) + .build(); + } + float alpha = getLayerAlpha(layer); setupDraw(); if (layer->getRenderTarget() == GL_TEXTURE_2D) { setupDrawWithTexture(); @@ -942,16 +875,16 @@ void OpenGLRenderer::drawTextureLayer(Layer* layer, const Rect& rect) { setupDrawPureColorUniforms(); setupDrawColorFilterUniforms(layer->getColorFilter()); if (layer->getRenderTarget() == GL_TEXTURE_2D) { - setupDrawTexture(layer->getTexture()); + setupDrawTexture(layer->getTextureId()); } else { - setupDrawExternalTexture(layer->getTexture()); + setupDrawExternalTexture(layer->getTextureId()); } - if (currentTransform()->isPureTranslate() && - !layer->getForceFilter() && - layer->getWidth() == (uint32_t) rect.getWidth() && - layer->getHeight() == (uint32_t) rect.getHeight()) { - const float x = (int) floorf(rect.left + currentTransform()->getTranslateX() + 0.5f); - const float y = (int) floorf(rect.top + currentTransform()->getTranslateY() + 0.5f); + if (currentTransform()->isPureTranslate() + && !layer->getForceFilter() + && layer->getWidth() == (uint32_t) rect.getWidth() + && layer->getHeight() == (uint32_t) rect.getHeight()) { + const float x = floorf(rect.left + currentTransform()->getTranslateX() + 0.5f); + const float y = floorf(rect.top + currentTransform()->getTranslateY() + 0.5f); layer->setFilter(GL_NEAREST); setupDrawModelView(kModelViewMode_TranslateAndScale, false, @@ -964,7 +897,7 @@ void OpenGLRenderer::drawTextureLayer(Layer* layer, const Rect& rect) { setupDrawTextureTransformUniforms(layer->getTexTransform()); setupDrawMesh(&mMeshVertices[0].x, &mMeshVertices[0].u); - glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount); + glDrawArrays(GL_TRIANGLE_STRIP, 0, kUnitQuadCount); } void OpenGLRenderer::composeLayerRect(Layer* layer, const Rect& rect, bool swap) { @@ -975,21 +908,41 @@ void OpenGLRenderer::composeLayerRect(Layer* layer, const Rect& rect, bool swap) resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f); } else { EVENT_LOGD("composeHardwareLayerRect"); + + if (USE_GLOPS) { + Blend::ModeOrderSwap modeUsage = swap ? + Blend::ModeOrderSwap::Swap : Blend::ModeOrderSwap::NoSwap; + const Matrix4& transform = swap ? Matrix4::identity() : *currentTransform(); + bool snap = !swap + && layer->getWidth() == static_cast<uint32_t>(rect.getWidth()) + && layer->getHeight() == static_cast<uint32_t>(rect.getHeight()); + Glop glop; + GlopBuilder(mRenderState, mCaches, &glop) + .setMeshTexturedUvQuad(nullptr, layer->texCoords) + .setFillLayer(layer->getTexture(), layer->getColorFilter(), getLayerAlpha(layer), layer->getMode(), modeUsage) + .setTransform(currentSnapshot()->getOrthoMatrix(), transform, false) + .setModelViewMapUnitToRectOptionalSnap(snap, rect) + .setRoundRectClipState(currentSnapshot()->roundRectClipState) + .build(); + renderGlop(glop); + return; + } + const Rect& texCoords = layer->texCoords; resetDrawTextureTexCoords(texCoords.left, texCoords.top, texCoords.right, texCoords.bottom); float x = rect.left; float y = rect.top; - bool simpleTransform = currentTransform()->isPureTranslate() && - layer->getWidth() == (uint32_t) rect.getWidth() && - layer->getHeight() == (uint32_t) rect.getHeight(); + bool simpleTransform = currentTransform()->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 + currentTransform()->getTranslateX() + 0.5f); - y = (int) floorf(rect.top + currentTransform()->getTranslateY() + 0.5f); + x = floorf(rect.left + currentTransform()->getTranslateX() + 0.5f); + y = floorf(rect.top + currentTransform()->getTranslateY() + 0.5f); } layer->setFilter(GL_NEAREST, true); @@ -1004,9 +957,9 @@ void OpenGLRenderer::composeLayerRect(Layer* layer, const Rect& rect, bool swap) bool blend = layer->isBlend() || getLayerAlpha(layer) < 1.0f; drawTextureMesh(x, y, x + rect.getWidth(), y + rect.getHeight(), - layer->getTexture(), &layerPaint, blend, + layer->getTextureId(), &layerPaint, blend, &mMeshVertices[0].x, &mMeshVertices[0].u, - GL_TRIANGLE_STRIP, gMeshCount, swap, swap || simpleTransform); + GL_TRIANGLE_STRIP, kUnitQuadCount, swap, swap || simpleTransform); resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f); } @@ -1038,14 +991,14 @@ public: , mLayer(layer) { } - virtual bool asACustomShader(void** data) const { + virtual bool asACustomShader(void** data) const override { if (data) { *data = static_cast<void*>(mLayer); } return true; } - virtual bool isOpaque() const { + virtual bool isOpaque() const override { return !mLayer->isBlend(); } @@ -1054,13 +1007,13 @@ protected: LOG_ALWAYS_FATAL("LayerShader should never be drawn with raster backend."); } - virtual void flatten(SkWriteBuffer&) const { + virtual void flatten(SkWriteBuffer&) const override { LOG_ALWAYS_FATAL("LayerShader should never be flattened."); } - virtual Factory getFactory() const { + virtual Factory getFactory() const override { LOG_ALWAYS_FATAL("LayerShader should never be created from a stream."); - return NULL; + return nullptr; } private: // Unowned. @@ -1093,7 +1046,7 @@ void OpenGLRenderer::composeLayerRegion(Layer* layer, const Rect& rect) { const SkPath* maskPath = layer->getConvexMask(); DRAW_DOUBLE_STENCIL(drawConvexPath(*maskPath, &paint)); - paint.setShader(NULL); + paint.setShader(nullptr); restore(); return; @@ -1120,11 +1073,42 @@ void OpenGLRenderer::composeLayerRegion(Layer* layer, const Rect& rect) { rects = safeRegion.getArray(&count); } - const float alpha = getLayerAlpha(layer); const float texX = 1.0f / float(layer->getWidth()); const float texY = 1.0f / float(layer->getHeight()); const float height = rect.getHeight(); + if (USE_GLOPS) { + TextureVertex quadVertices[count * 4]; + //std::unique_ptr<TextureVertex[]> quadVertices(new TextureVertex[count * 4]); + TextureVertex* mesh = &quadVertices[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); + } + Glop glop; + GlopBuilder(mRenderState, mCaches, &glop) + .setMeshTexturedIndexedQuads(&quadVertices[0], count * 6) + .setFillLayer(layer->getTexture(), layer->getColorFilter(), getLayerAlpha(layer), layer->getMode(), Blend::ModeOrderSwap::NoSwap) + .setTransform(currentSnapshot()->getOrthoMatrix(), *currentTransform(), false) + .setModelViewOffsetRectSnap(0, 0, rect) + .setRoundRectClipState(currentSnapshot()->roundRectClipState) + .build(); + DRAW_DOUBLE_STENCIL_IF(!layer->hasDrawnSinceUpdate, renderGlop(glop)); + return; + } + + const float alpha = getLayerAlpha(layer); + setupDraw(); // We must get (and therefore bind) the region mesh buffer @@ -1141,10 +1125,10 @@ void OpenGLRenderer::composeLayerRegion(Layer* layer, const Rect& rect) { setupDrawDirtyRegionsDisabled(); setupDrawPureColorUniforms(); setupDrawColorFilterUniforms(layer->getColorFilter()); - setupDrawTexture(layer->getTexture()); + setupDrawTexture(layer->getTextureId()); if (currentTransform()->isPureTranslate()) { - const float x = (int) floorf(rect.left + currentTransform()->getTranslateX() + 0.5f); - const float y = (int) floorf(rect.top + currentTransform()->getTranslateY() + 0.5f); + const float x = floorf(rect.left + currentTransform()->getTranslateX() + 0.5f); + const float y = floorf(rect.top + currentTransform()->getTranslateY() + 0.5f); layer->setFilter(GL_NEAREST); setupDrawModelView(kModelViewMode_Translate, false, @@ -1172,9 +1156,9 @@ void OpenGLRenderer::composeLayerRegion(Layer* layer, const Rect& rect) { numQuads++; - if (numQuads >= gMaxNumberOfQuads) { + if (numQuads >= kMaxNumberOfQuads) { DRAW_DOUBLE_STENCIL(glDrawElements(GL_TRIANGLES, numQuads * 6, - GL_UNSIGNED_SHORT, NULL)); + GL_UNSIGNED_SHORT, nullptr)); numQuads = 0; mesh = mCaches.getRegionMesh(); } @@ -1182,7 +1166,7 @@ void OpenGLRenderer::composeLayerRegion(Layer* layer, const Rect& rect) { if (numQuads > 0) { DRAW_DOUBLE_STENCIL(glDrawElements(GL_TRIANGLES, numQuads * 6, - GL_UNSIGNED_SHORT, NULL)); + GL_UNSIGNED_SHORT, nullptr)); } #if DEBUG_LAYERS_AS_REGIONS @@ -1236,7 +1220,7 @@ void OpenGLRenderer::drawRegionRects(const SkRegion& region, const SkPaint& pain } void OpenGLRenderer::dirtyLayer(const float left, const float top, - const float right, const float bottom, const mat4 transform) { + const float right, const float bottom, const Matrix4& transform) { if (hasLayer()) { Rect bounds(left, top, right, bottom); transform.mapRect(bounds); @@ -1253,7 +1237,7 @@ void OpenGLRenderer::dirtyLayer(const float left, const float top, } void OpenGLRenderer::dirtyLayerUnchecked(Rect& bounds, Region* region) { - if (bounds.intersect(*currentClipRect())) { + if (bounds.intersect(mState.currentClipRect())) { bounds.snapToPixelBoundaries(); android::Rect dirty(bounds.left, bounds.top, bounds.right, bounds.bottom); if (!dirty.isEmpty()) { @@ -1265,10 +1249,10 @@ void OpenGLRenderer::dirtyLayerUnchecked(Rect& bounds, Region* region) { void OpenGLRenderer::issueIndexedQuadDraw(Vertex* mesh, GLsizei quadsCount) { GLsizei elementsCount = quadsCount * 6; while (elementsCount > 0) { - GLsizei drawCount = min(elementsCount, (GLsizei) gMaxNumberOfQuads * 6); + GLsizei drawCount = MathUtils::min(elementsCount, (GLsizei) kMaxNumberOfQuads * 6); setupDrawIndexedVertices(&mesh[0].x); - glDrawElements(GL_TRIANGLES, drawCount, GL_UNSIGNED_SHORT, NULL); + glDrawElements(GL_TRIANGLES, drawCount, GL_UNSIGNED_SHORT, nullptr); elementsCount -= drawCount; // Though there are 4 vertices in a quad, we use 6 indices per @@ -1278,10 +1262,10 @@ void OpenGLRenderer::issueIndexedQuadDraw(Vertex* mesh, GLsizei quadsCount) { } void OpenGLRenderer::clearLayerRegions() { - const size_t count = mLayers.size(); - if (count == 0) return; + const size_t quadCount = mLayers.size(); + if (quadCount == 0) return; - if (!currentSnapshot()->isIgnored()) { + if (!mState.currentlyIgnored()) { EVENT_LOGD("clearLayerRegions"); // Doing several glScissor/glClear here can negatively impact // GPUs with a tiler architecture, instead we draw quads with @@ -1290,44 +1274,51 @@ void OpenGLRenderer::clearLayerRegions() { // 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(); + bool scissorChanged = mRenderState.scissor().setEnabled(false); - Vertex mesh[count * 4]; + Vertex mesh[quadCount * 4]; Vertex* vertex = mesh; - for (uint32_t i = 0; i < count; i++) { - Rect* bounds = mLayers.itemAt(i); + for (uint32_t i = 0; i < quadCount; i++) { + const Rect& bounds = mLayers[i]; - 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->bottom); - - delete bounds; + 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.bottom); } // We must clear the list of dirty rects before we // call setupDraw() to prevent stencil setup to do // the same thing again mLayers.clear(); - SkPaint clearPaint; - clearPaint.setXfermodeMode(SkXfermode::kClear_Mode); + if (USE_GLOPS) { + Glop glop; + GlopBuilder(mRenderState, mCaches, &glop) + .setMeshIndexedQuads(&mesh[0], quadCount) + .setFillClear() + .setTransform(currentSnapshot()->getOrthoMatrix(), Matrix4::identity(), false) + .setModelViewOffsetRect(0, 0, Rect(currentSnapshot()->getClipRect())) + .setRoundRectClipState(currentSnapshot()->roundRectClipState) + .build(); + renderGlop(glop, false); + } else { + SkPaint clearPaint; + clearPaint.setXfermodeMode(SkXfermode::kClear_Mode); - setupDraw(false); - setupDrawColor(0.0f, 0.0f, 0.0f, 1.0f); - setupDrawBlending(&clearPaint, true); - setupDrawProgram(); - setupDrawPureColorUniforms(); - setupDrawModelView(kModelViewMode_Translate, false, - 0.0f, 0.0f, 0.0f, 0.0f, true); + setupDraw(false); + setupDrawColor(0.0f, 0.0f, 0.0f, 1.0f); + setupDrawBlending(&clearPaint, true); + setupDrawProgram(); + setupDrawPureColorUniforms(); + setupDrawModelView(kModelViewMode_Translate, false, + 0.0f, 0.0f, 0.0f, 0.0f, true); - issueIndexedQuadDraw(&mesh[0], count); + issueIndexedQuadDraw(&mesh[0], quadCount); + } - if (scissorChanged) mCaches.enableScissor(); + if (scissorChanged) mRenderState.scissor().setEnabled(true); } else { - for (uint32_t i = 0; i < count; i++) { - delete mLayers.itemAt(i); - } mLayers.clear(); } } @@ -1337,7 +1328,7 @@ void OpenGLRenderer::clearLayerRegions() { /////////////////////////////////////////////////////////////////////////////// bool OpenGLRenderer::storeDisplayState(DeferredDisplayState& state, int stateDeferFlags) { - const Rect* currentClip = currentClipRect(); + const Rect& currentClip = mState.currentClipRect(); const mat4* currentMatrix = currentTransform(); if (stateDeferFlags & kStateDeferFlag_Draw) { @@ -1349,32 +1340,32 @@ bool OpenGLRenderer::storeDisplayState(DeferredDisplayState& state, int stateDef // is used, it should more closely duplicate the quickReject logic (in how it uses // snapToPixelBoundaries) - if(!clippedBounds.intersect(*currentClip)) { + if (!clippedBounds.intersect(currentClip)) { // quick rejected return true; } state.mClipSideFlags = kClipSide_None; - if (!currentClip->contains(state.mBounds)) { + if (!currentClip.contains(state.mBounds)) { int& flags = state.mClipSideFlags; // op partially clipped, so record which sides are clipped for clip-aware merging - if (currentClip->left > state.mBounds.left) flags |= kClipSide_Left; - if (currentClip->top > state.mBounds.top) flags |= kClipSide_Top; - if (currentClip->right < state.mBounds.right) flags |= kClipSide_Right; - if (currentClip->bottom < state.mBounds.bottom) flags |= kClipSide_Bottom; + if (currentClip.left > state.mBounds.left) flags |= kClipSide_Left; + if (currentClip.top > state.mBounds.top) flags |= kClipSide_Top; + if (currentClip.right < state.mBounds.right) flags |= kClipSide_Right; + if (currentClip.bottom < state.mBounds.bottom) flags |= kClipSide_Bottom; } state.mBounds.set(clippedBounds); } else { // Empty bounds implies size unknown. Label op as conservatively clipped to disable // overdraw avoidance (since we don't know what it overlaps) state.mClipSideFlags = kClipSide_ConservativeFull; - state.mBounds.set(*currentClip); + state.mBounds.set(currentClip); } } state.mClipValid = (stateDeferFlags & kStateDeferFlag_Clip); if (state.mClipValid) { - state.mClip.set(*currentClip); + state.mClip.set(currentClip); } // Transform, drawModifiers, and alpha always deferred, since they are used by state operations @@ -1390,12 +1381,12 @@ bool OpenGLRenderer::storeDisplayState(DeferredDisplayState& state, int stateDef void OpenGLRenderer::restoreDisplayState(const DeferredDisplayState& state, bool skipClipRestore) { setMatrix(state.mMatrix); - mSnapshot->alpha = state.mAlpha; + writableSnapshot()->alpha = state.mAlpha; mDrawModifiers = state.mDrawModifiers; - mSnapshot->roundRectClipState = state.mRoundRectClipState; + writableSnapshot()->roundRectClipState = state.mRoundRectClipState; if (state.mClipValid && !skipClipRestore) { - mSnapshot->setClip(state.mClip.left, state.mClip.top, + writableSnapshot()->setClip(state.mClip.left, state.mClip.top, state.mClip.right, state.mClip.bottom); dirtyClip(); } @@ -1409,13 +1400,14 @@ void OpenGLRenderer::restoreDisplayState(const DeferredDisplayState& state, bool * This method should be called when restoreDisplayState() won't be restoring the clip */ void OpenGLRenderer::setupMergedMultiDraw(const Rect* clipRect) { - if (clipRect != NULL) { - mSnapshot->setClip(clipRect->left, clipRect->top, clipRect->right, clipRect->bottom); + if (clipRect != nullptr) { + writableSnapshot()->setClip(clipRect->left, clipRect->top, clipRect->right, clipRect->bottom); } else { - mSnapshot->setClip(0, 0, getWidth(), getHeight()); + writableSnapshot()->setClip(0, 0, mState.getWidth(), mState.getHeight()); } dirtyClip(); - mCaches.setScissorEnabled(clipRect != NULL || mScissorOptimizationDisabled); + bool enableScissor = (clipRect != nullptr) || mScissorOptimizationDisabled; + mRenderState.scissor().setEnabled(enableScissor); } /////////////////////////////////////////////////////////////////////////////// @@ -1423,12 +1415,12 @@ void OpenGLRenderer::setupMergedMultiDraw(const Rect* clipRect) { /////////////////////////////////////////////////////////////////////////////// void OpenGLRenderer::setScissorFromClip() { - Rect clip(*currentClipRect()); + Rect clip(mState.currentClipRect()); clip.snapToPixelBoundaries(); - if (mCaches.setScissor(clip.left, getViewportHeight() - clip.bottom, + if (mRenderState.scissor().set(clip.left, getViewportHeight() - clip.bottom, clip.getWidth(), clip.getHeight())) { - mDirtyClip = false; + mState.setDirtyClip(false); } } @@ -1450,34 +1442,123 @@ void OpenGLRenderer::attachStencilBufferToLayer(Layer* layer) { endTiling(); RenderBuffer* buffer = mCaches.renderBufferCache.get( - Stencil::getSmallestStencilFormat(), layer->getWidth(), layer->getHeight()); + Stencil::getSmallestStencilFormat(), + layer->getWidth(), layer->getHeight()); layer->setStencilRenderBuffer(buffer); startTiling(layer->clipRect, layer->layer.getHeight()); } } +static void handlePoint(std::vector<Vertex>& rectangleVertices, const Matrix4& transform, + float x, float y) { + Vertex v; + v.x = x; + v.y = y; + transform.mapPoint(v.x, v.y); + rectangleVertices.push_back(v); +} + +static void handlePointNoTransform(std::vector<Vertex>& rectangleVertices, float x, float y) { + Vertex v; + v.x = x; + v.y = y; + rectangleVertices.push_back(v); +} + +void OpenGLRenderer::drawRectangleList(const RectangleList& rectangleList) { + int quadCount = rectangleList.getTransformedRectanglesCount(); + std::vector<Vertex> rectangleVertices(quadCount * 4); + Rect scissorBox = rectangleList.calculateBounds(); + scissorBox.snapToPixelBoundaries(); + for (int i = 0; i < quadCount; ++i) { + const TransformedRectangle& tr(rectangleList.getTransformedRectangle(i)); + const Matrix4& transform = tr.getTransform(); + Rect bounds = tr.getBounds(); + if (transform.rectToRect()) { + transform.mapRect(bounds); + if (!bounds.intersect(scissorBox)) { + bounds.setEmpty(); + } else { + handlePointNoTransform(rectangleVertices, bounds.left, bounds.top); + handlePointNoTransform(rectangleVertices, bounds.right, bounds.top); + handlePointNoTransform(rectangleVertices, bounds.left, bounds.bottom); + handlePointNoTransform(rectangleVertices, bounds.right, bounds.bottom); + } + } else { + handlePoint(rectangleVertices, transform, bounds.left, bounds.top); + handlePoint(rectangleVertices, transform, bounds.right, bounds.top); + handlePoint(rectangleVertices, transform, bounds.left, bounds.bottom); + handlePoint(rectangleVertices, transform, bounds.right, bounds.bottom); + } + } + + mRenderState.scissor().set(scissorBox.left, getViewportHeight() - scissorBox.bottom, + scissorBox.getWidth(), scissorBox.getHeight()); + + if (USE_GLOPS) { + Glop glop; + GlopBuilder(mRenderState, mCaches, &glop) + .setMeshIndexedQuads(&rectangleVertices[0], rectangleVertices.size() / 4) + .setFillBlack() + .setTransform(currentSnapshot()->getOrthoMatrix(), Matrix4::identity(), false) + .setModelViewOffsetRect(0, 0, scissorBox) + .setRoundRectClipState(currentSnapshot()->roundRectClipState) + .build(); + renderGlop(glop); + return; + } + + const SkPaint* paint = nullptr; + setupDraw(); + setupDrawNoTexture(); + setupDrawColor(0, 0xff * currentSnapshot()->alpha); + setupDrawShader(getShader(paint)); + setupDrawColorFilter(getColorFilter(paint)); + setupDrawBlending(paint); + setupDrawProgram(); + setupDrawDirtyRegionsDisabled(); + setupDrawModelView(kModelViewMode_Translate, false, + 0.0f, 0.0f, 0.0f, 0.0f, true); + setupDrawColorUniforms(getShader(paint)); + setupDrawShaderUniforms(getShader(paint)); + setupDrawColorFilterUniforms(getColorFilter(paint)); + + issueIndexedQuadDraw(&rectangleVertices[0], rectangleVertices.size() / 4); +} + void OpenGLRenderer::setStencilFromClip() { if (!mCaches.debugOverdraw) { - if (!currentSnapshot()->clipRegion->isEmpty()) { + if (!currentSnapshot()->clipIsSimple()) { + int incrementThreshold; EVENT_LOGD("setStencilFromClip - enabling"); // NOTE: The order here is important, we must set dirtyClip to false // before any draw call to avoid calling back into this method - mDirtyClip = false; + mState.setDirtyClip(false); ensureStencilBuffer(); - mCaches.stencil.enableWrite(); + const ClipArea& clipArea = currentSnapshot()->getClipArea(); + + bool isRectangleList = clipArea.isRectangleList(); + if (isRectangleList) { + incrementThreshold = clipArea.getRectangleList().getTransformedRectanglesCount(); + } else { + incrementThreshold = 0; + } + + mRenderState.stencil().enableWrite(incrementThreshold); - // Clear and update the stencil, but first make sure we restrict drawing + // Clean and update the stencil, but first make sure we restrict drawing // to the region's bounds - bool resetScissor = mCaches.enableScissor(); + bool resetScissor = mRenderState.scissor().setEnabled(true); if (resetScissor) { // The scissor was not set so we now need to update it setScissorFromClip(); } - mCaches.stencil.clear(); + + mRenderState.stencil().clear(); // stash and disable the outline clip state, since stencil doesn't account for outline bool storedSkipOutlineClip = mSkipOutlineClip; @@ -1487,28 +1568,34 @@ void OpenGLRenderer::setStencilFromClip() { paint.setColor(SK_ColorBLACK); paint.setXfermodeMode(SkXfermode::kSrc_Mode); - // NOTE: We could use the region contour path to generate a smaller mesh - // Since we are using the stencil we could use the red book path - // drawing technique. It might increase bandwidth usage though. + if (isRectangleList) { + drawRectangleList(clipArea.getRectangleList()); + } else { + // NOTE: We could use the region contour path to generate a smaller mesh + // Since we are using the stencil we could use the red book path + // drawing technique. It might increase bandwidth usage though. - // The last parameter is important: we are not drawing in the color buffer - // so we don't want to dirty the current layer, if any - drawRegionRects(*(currentSnapshot()->clipRegion), paint, false); - if (resetScissor) mCaches.disableScissor(); + // The last parameter is important: we are not drawing in the color buffer + // so we don't want to dirty the current layer, if any + drawRegionRects(clipArea.getClipRegion(), paint, false); + } + if (resetScissor) mRenderState.scissor().setEnabled(false); mSkipOutlineClip = storedSkipOutlineClip; - mCaches.stencil.enableTest(); + mRenderState.stencil().enableTest(incrementThreshold); // Draw the region used to generate the stencil if the appropriate debug // mode is enabled - if (mCaches.debugStencilClip == Caches::kStencilShowRegion) { + // TODO: Implement for rectangle list clip areas + if (mCaches.debugStencilClip == Caches::kStencilShowRegion && + !clipArea.isRectangleList()) { paint.setColor(0x7f0000ff); paint.setXfermodeMode(SkXfermode::kSrcOver_Mode); - drawRegionRects(*(currentSnapshot()->clipRegion), paint); + drawRegionRects(currentSnapshot()->getClipRegion(), paint); } } else { EVENT_LOGD("setStencilFromClip - disabling"); - mCaches.stencil.disable(); + mRenderState.stencil().disable(); } } } @@ -1533,13 +1620,13 @@ bool OpenGLRenderer::quickRejectSetupScissor(float left, float top, float right, bool clipRequired = false; bool roundRectClipRequired = false; - if (calculateQuickRejectForScissor(left, top, right, bottom, + if (mState.calculateQuickRejectForScissor(left, top, right, bottom, &clipRequired, &roundRectClipRequired, snapOut)) { return true; } // not quick rejected, so enable the scissor if clipRequired - mCaches.setScissorEnabled(mScissorOptimizationDisabled || clipRequired); + mRenderState.scissor().setEnabled(mScissorOptimizationDisabled || clipRequired); mSkipOutlineClip = !roundRectClipRequired; return false; } @@ -1555,6 +1642,27 @@ void OpenGLRenderer::debugClip() { #endif } +void OpenGLRenderer::renderGlop(const Glop& glop, bool clearLayer) { + // TODO: It would be best if we could do this before quickRejectSetupScissor() + // changes the scissor test state + if (clearLayer) clearLayerRegions(); + + if (mState.getDirtyClip()) { + if (mRenderState.scissor().isEnabled()) { + setScissorFromClip(); + } + + setStencilFromClip(); + } + mRenderState.render(glop); + if (!mRenderState.stencil().isWriteEnabled()) { + // TODO: specify more clearly when a draw should dirty the layer. + // is writing to the stencil the only time we should ignore this? + dirtyLayer(glop.bounds.left, glop.bounds.top, glop.bounds.right, glop.bounds.bottom); + mDirty = true; + } +} + /////////////////////////////////////////////////////////////////////////////// // Drawing commands /////////////////////////////////////////////////////////////////////////////// @@ -1565,8 +1673,8 @@ void OpenGLRenderer::setupDraw(bool clearLayer) { if (clearLayer) clearLayerRegions(); // Make sure setScissor & setStencil happen at the beginning of // this method - if (mDirtyClip) { - if (mCaches.scissorEnabled) { + if (mState.getDirtyClip()) { + if (mRenderState.scissor().isEnabled()) { setScissorFromClip(); } @@ -1577,15 +1685,15 @@ void OpenGLRenderer::setupDraw(bool clearLayer) { mSetShaderColor = false; mColorSet = false; - mColorA = mColorR = mColorG = mColorB = 0.0f; + mColor.a = mColor.r = mColor.g = mColor.b = 0.0f; mTextureUnit = 0; mTrackDirtyRegions = true; // Enable debug highlight when what we're about to draw is tested against // the stencil buffer and if stencil highlight debugging is on - mDescription.hasDebugHighlight = !mCaches.debugOverdraw && - mCaches.debugStencilClip == Caches::kStencilShowHighlight && - mCaches.stencil.isTestEnabled(); + mDescription.hasDebugHighlight = !mCaches.debugOverdraw + && mCaches.debugStencilClip == Caches::kStencilShowHighlight + && mRenderState.stencil().isTestEnabled(); } void OpenGLRenderer::setupDrawWithTexture(bool isAlpha8) { @@ -1604,7 +1712,7 @@ void OpenGLRenderer::setupDrawWithExternalTexture() { } void OpenGLRenderer::setupDrawNoTexture() { - mCaches.disableTexCoordsVertexArray(); + mRenderState.meshState().disableTexCoordsVertexArray(); } void OpenGLRenderer::setupDrawVertexAlpha(bool useShadowAlphaInterp) { @@ -1613,21 +1721,21 @@ void OpenGLRenderer::setupDrawVertexAlpha(bool useShadowAlphaInterp) { } void OpenGLRenderer::setupDrawColor(int color, int alpha) { - mColorA = alpha / 255.0f; - mColorR = mColorA * ((color >> 16) & 0xFF) / 255.0f; - mColorG = mColorA * ((color >> 8) & 0xFF) / 255.0f; - mColorB = mColorA * ((color ) & 0xFF) / 255.0f; + mColor.a = alpha / 255.0f; + mColor.r = mColor.a * ((color >> 16) & 0xFF) / 255.0f; + mColor.g = mColor.a * ((color >> 8) & 0xFF) / 255.0f; + mColor.b = mColor.a * ((color ) & 0xFF) / 255.0f; mColorSet = true; - mSetShaderColor = mDescription.setColorModulate(mColorA); + mSetShaderColor = mDescription.setColorModulate(mColor.a); } void OpenGLRenderer::setupDrawAlpha8Color(int color, int alpha) { - mColorA = alpha / 255.0f; - mColorR = mColorA * ((color >> 16) & 0xFF) / 255.0f; - mColorG = mColorA * ((color >> 8) & 0xFF) / 255.0f; - mColorB = mColorA * ((color ) & 0xFF) / 255.0f; + mColor.a = alpha / 255.0f; + mColor.r = mColor.a * ((color >> 16) & 0xFF) / 255.0f; + mColor.g = mColor.a * ((color >> 8) & 0xFF) / 255.0f; + mColor.b = mColor.a * ((color ) & 0xFF) / 255.0f; mColorSet = true; - mSetShaderColor = mDescription.setAlpha8ColorModulate(mColorR, mColorG, mColorB, mColorA); + mSetShaderColor = mDescription.setAlpha8ColorModulate(mColor.r, mColor.g, mColor.b, mColor.a); } void OpenGLRenderer::setupDrawTextGamma(const SkPaint* paint) { @@ -1635,38 +1743,38 @@ void OpenGLRenderer::setupDrawTextGamma(const SkPaint* paint) { } void OpenGLRenderer::setupDrawColor(float r, float g, float b, float a) { - mColorA = a; - mColorR = r; - mColorG = g; - mColorB = b; + mColor.a = a; + mColor.r = r; + mColor.g = g; + mColor.b = b; mColorSet = true; mSetShaderColor = mDescription.setColorModulate(a); } void OpenGLRenderer::setupDrawShader(const SkShader* shader) { - if (shader != NULL) { - SkiaShader::describe(&mCaches, mDescription, mExtensions, *shader); + if (shader != nullptr) { + SkiaShader::describe(&mCaches, mDescription, mCaches.extensions(), *shader); } } void OpenGLRenderer::setupDrawColorFilter(const SkColorFilter* filter) { - if (filter == NULL) { + if (filter == nullptr) { return; } SkXfermode::Mode mode; - if (filter->asColorMode(NULL, &mode)) { + if (filter->asColorMode(nullptr, &mode)) { mDescription.colorOp = ProgramDescription::kColorBlend; mDescription.colorMode = mode; - } else if (filter->asColorMatrix(NULL)) { + } else if (filter->asColorMatrix(nullptr)) { mDescription.colorOp = ProgramDescription::kColorMatrix; } } void OpenGLRenderer::accountForClear(SkXfermode::Mode mode) { if (mColorSet && mode == SkXfermode::kClear_Mode) { - mColorA = 1.0f; - mColorR = mColorG = mColorB = 0.0f; + mColor.a = 1.0f; + mColor.r = mColor.g = mColor.b = 0.0f; mSetShaderColor = mDescription.modulate = true; } } @@ -1677,8 +1785,10 @@ void OpenGLRenderer::setupDrawBlending(const Layer* layer, bool swapSrcDst) { // argb=1,0,0,0 accountForClear(mode); // TODO: check shader blending, once we have shader drawing support for layers. - bool blend = layer->isBlend() || getLayerAlpha(layer) < 1.0f || - (mColorSet && mColorA < 1.0f) || isBlendedColorFilter(layer->getColorFilter()); + bool blend = layer->isBlend() + || getLayerAlpha(layer) < 1.0f + || (mColorSet && mColor.a < 1.0f) + || PaintUtils::isBlendedColorFilter(layer->getColorFilter()); chooseBlending(blend, mode, mDescription, swapSrcDst); } @@ -1687,27 +1797,27 @@ void OpenGLRenderer::setupDrawBlending(const SkPaint* paint, bool blend, bool sw // When the blending mode is kClear_Mode, we need to use a modulate color // argb=1,0,0,0 accountForClear(mode); - blend |= (mColorSet && mColorA < 1.0f) || - (getShader(paint) && !getShader(paint)->isOpaque()) || - isBlendedColorFilter(getColorFilter(paint)); + blend |= (mColorSet && mColor.a < 1.0f) + || (getShader(paint) && !getShader(paint)->isOpaque()) + || PaintUtils::isBlendedColorFilter(getColorFilter(paint)); chooseBlending(blend, mode, mDescription, swapSrcDst); } void OpenGLRenderer::setupDrawProgram() { - useProgram(mCaches.programCache.get(mDescription)); + mCaches.setProgram(mDescription); if (mDescription.hasRoundRectClip) { // TODO: avoid doing this repeatedly, stashing state pointer in program - const RoundRectClipState* state = mSnapshot->roundRectClipState; + const RoundRectClipState* state = writableSnapshot()->roundRectClipState; const Rect& innerRect = state->innerRect; - glUniform4f(mCaches.currentProgram->getUniform("roundRectInnerRectLTRB"), + glUniform4f(mCaches.program().getUniform("roundRectInnerRectLTRB"), innerRect.left, innerRect.top, innerRect.right, innerRect.bottom); - glUniformMatrix4fv(mCaches.currentProgram->getUniform("roundRectInvTransform"), + glUniformMatrix4fv(mCaches.program().getUniform("roundRectInvTransform"), 1, GL_FALSE, &state->matrix.data[0]); // add half pixel to round out integer rect space to cover pixel centers float roundedOutRadius = state->radius + 0.5f; - glUniform1f(mCaches.currentProgram->getUniform("roundRectRadius"), + glUniform1f(mCaches.program().getUniform("roundRectRadius"), roundedOutRadius); } } @@ -1725,7 +1835,9 @@ void OpenGLRenderer::setupDrawModelView(ModelViewMode mode, bool offset, bool dirty = right - left > 0.0f && bottom - top > 0.0f; const Matrix4& transformMatrix = ignoreTransform ? Matrix4::identity() : *currentTransform(); - mCaches.currentProgram->set(mSnapshot->getOrthoMatrix(), mModelViewMatrix, transformMatrix, offset); + + mCaches.program().set(currentSnapshot()->getOrthoMatrix(), + mModelViewMatrix, transformMatrix, offset); if (dirty && mTrackDirtyRegions) { if (!ignoreTransform) { dirtyLayer(left, top, right, bottom, *currentTransform()); @@ -1737,18 +1849,18 @@ void OpenGLRenderer::setupDrawModelView(ModelViewMode mode, bool offset, void OpenGLRenderer::setupDrawColorUniforms(bool hasShader) { if ((mColorSet && !hasShader) || (hasShader && mSetShaderColor)) { - mCaches.currentProgram->setColor(mColorR, mColorG, mColorB, mColorA); + mCaches.program().setColor(mColor); } } void OpenGLRenderer::setupDrawPureColorUniforms() { if (mSetShaderColor) { - mCaches.currentProgram->setColor(mColorR, mColorG, mColorB, mColorA); + mCaches.program().setColor(mColor); } } void OpenGLRenderer::setupDrawShaderUniforms(const SkShader* shader, bool ignoreTransform) { - if (shader == NULL) { + if (shader == nullptr) { return; } @@ -1762,11 +1874,12 @@ void OpenGLRenderer::setupDrawShaderUniforms(const SkShader* shader, bool ignore mModelViewMatrix.load(modelViewWithoutTransform); } - SkiaShader::setupProgram(&mCaches, mModelViewMatrix, &mTextureUnit, mExtensions, *shader); + SkiaShader::setupProgram(&mCaches, mModelViewMatrix, &mTextureUnit, + mCaches.extensions(), *shader); } void OpenGLRenderer::setupDrawColorFilterUniforms(const SkColorFilter* filter) { - if (NULL == filter) { + if (nullptr == filter) { return; } @@ -1778,7 +1891,7 @@ void OpenGLRenderer::setupDrawColorFilterUniforms(const SkColorFilter* filter) { const GLfloat r = a * SkColorGetR(color) / 255.0f; const GLfloat g = a * SkColorGetG(color) / 255.0f; const GLfloat b = a * SkColorGetB(color) / 255.0f; - glUniform4f(mCaches.currentProgram->getUniform("colorBlend"), r, g, b, a); + glUniform4f(mCaches.program().getUniform("colorBlend"), r, g, b, a); return; } @@ -1799,9 +1912,9 @@ void OpenGLRenderer::setupDrawColorFilterUniforms(const SkColorFilter* filter) { colorVector[2] = srcColorMatrix[14] / 255.0f; colorVector[3] = srcColorMatrix[19] / 255.0f; - glUniformMatrix4fv(mCaches.currentProgram->getUniform("colorMatrix"), 1, + glUniformMatrix4fv(mCaches.program().getUniform("colorMatrix"), 1, GL_FALSE, colorMatrix); - glUniform4fv(mCaches.currentProgram->getUniform("colorMatrixVector"), 1, colorVector); + glUniform4fv(mCaches.program().getUniform("colorMatrixVector"), 1, colorVector); return; } @@ -1809,25 +1922,25 @@ void OpenGLRenderer::setupDrawColorFilterUniforms(const SkColorFilter* filter) { } void OpenGLRenderer::setupDrawTextGammaUniforms() { - mCaches.fontRenderer->setupProgram(mDescription, mCaches.currentProgram); + mCaches.fontRenderer->setupProgram(mDescription, mCaches.program()); } void OpenGLRenderer::setupDrawSimpleMesh() { - bool force = mCaches.bindMeshBuffer(); - mCaches.bindPositionVertexPointer(force, 0); - mCaches.unbindIndicesBuffer(); + bool force = mRenderState.meshState().bindMeshBuffer(); + mRenderState.meshState().bindPositionVertexPointer(force, nullptr); + mRenderState.meshState().unbindIndicesBuffer(); } void OpenGLRenderer::setupDrawTexture(GLuint texture) { - if (texture) bindTexture(texture); + if (texture) mCaches.textureState().bindTexture(texture); mTextureUnit++; - mCaches.enableTexCoordsVertexArray(); + mRenderState.meshState().enableTexCoordsVertexArray(); } void OpenGLRenderer::setupDrawExternalTexture(GLuint texture) { - bindExternalTexture(texture); + mCaches.textureState().bindTexture(GL_TEXTURE_EXTERNAL_OES, texture); mTextureUnit++; - mCaches.enableTexCoordsVertexArray(); + mRenderState.meshState().enableTexCoordsVertexArray(); } void OpenGLRenderer::setupDrawTextureTransform() { @@ -1835,7 +1948,7 @@ void OpenGLRenderer::setupDrawTextureTransform() { } void OpenGLRenderer::setupDrawTextureTransformUniforms(mat4& transform) { - glUniformMatrix4fv(mCaches.currentProgram->getUniform("mainTextureTransform"), 1, + glUniformMatrix4fv(mCaches.program().getUniform("mainTextureTransform"), 1, GL_FALSE, &transform.data[0]); } @@ -1843,35 +1956,35 @@ void OpenGLRenderer::setupDrawMesh(const GLvoid* vertices, const GLvoid* texCoords, GLuint vbo) { bool force = false; if (!vertices || vbo) { - force = mCaches.bindMeshBuffer(vbo == 0 ? mCaches.meshBuffer : vbo); + force = mRenderState.meshState().bindMeshBuffer(vbo); } else { - force = mCaches.unbindMeshBuffer(); + force = mRenderState.meshState().unbindMeshBuffer(); } - mCaches.bindPositionVertexPointer(force, vertices); - if (mCaches.currentProgram->texCoords >= 0) { - mCaches.bindTexCoordsVertexPointer(force, texCoords); + mRenderState.meshState().bindPositionVertexPointer(force, vertices); + if (mCaches.program().texCoords >= 0) { + mRenderState.meshState().bindTexCoordsVertexPointer(force, texCoords); } - mCaches.unbindIndicesBuffer(); + mRenderState.meshState().unbindIndicesBuffer(); } void OpenGLRenderer::setupDrawMesh(const GLvoid* vertices, const GLvoid* texCoords, const GLvoid* colors) { - bool force = mCaches.unbindMeshBuffer(); + bool force = mRenderState.meshState().unbindMeshBuffer(); GLsizei stride = sizeof(ColorTextureVertex); - mCaches.bindPositionVertexPointer(force, vertices, stride); - if (mCaches.currentProgram->texCoords >= 0) { - mCaches.bindTexCoordsVertexPointer(force, texCoords, stride); + mRenderState.meshState().bindPositionVertexPointer(force, vertices, stride); + if (mCaches.program().texCoords >= 0) { + mRenderState.meshState().bindTexCoordsVertexPointer(force, texCoords, stride); } - int slot = mCaches.currentProgram->getAttrib("colors"); + int slot = mCaches.program().getAttrib("colors"); if (slot >= 0) { glEnableVertexAttribArray(slot); glVertexAttribPointer(slot, 4, GL_FLOAT, GL_FALSE, stride, colors); } - mCaches.unbindIndicesBuffer(); + mRenderState.meshState().unbindIndicesBuffer(); } void OpenGLRenderer::setupDrawMeshIndices(const GLvoid* vertices, @@ -1879,84 +1992,83 @@ void OpenGLRenderer::setupDrawMeshIndices(const GLvoid* vertices, bool force = false; // If vbo is != 0 we want to treat the vertices parameter as an offset inside // a VBO. However, if vertices is set to NULL and vbo == 0 then we want to - // use the default VBO found in Caches + // use the default VBO found in RenderState if (!vertices || vbo) { - force = mCaches.bindMeshBuffer(vbo == 0 ? mCaches.meshBuffer : vbo); + force = mRenderState.meshState().bindMeshBuffer(vbo); } else { - force = mCaches.unbindMeshBuffer(); + force = mRenderState.meshState().unbindMeshBuffer(); } - mCaches.bindQuadIndicesBuffer(); + mRenderState.meshState().bindQuadIndicesBuffer(); - mCaches.bindPositionVertexPointer(force, vertices); - if (mCaches.currentProgram->texCoords >= 0) { - mCaches.bindTexCoordsVertexPointer(force, texCoords); + mRenderState.meshState().bindPositionVertexPointer(force, vertices); + if (mCaches.program().texCoords >= 0) { + mRenderState.meshState().bindTexCoordsVertexPointer(force, texCoords); } } void OpenGLRenderer::setupDrawIndexedVertices(GLvoid* vertices) { - bool force = mCaches.unbindMeshBuffer(); - mCaches.bindQuadIndicesBuffer(); - mCaches.bindPositionVertexPointer(force, vertices, gVertexStride); + bool force = mRenderState.meshState().unbindMeshBuffer(); + mRenderState.meshState().bindQuadIndicesBuffer(); + mRenderState.meshState().bindPositionVertexPointer(force, vertices, kVertexStride); } /////////////////////////////////////////////////////////////////////////////// // Drawing /////////////////////////////////////////////////////////////////////////////// -status_t OpenGLRenderer::drawRenderNode(RenderNode* renderNode, Rect& dirty, int32_t replayFlags) { - status_t status; +void OpenGLRenderer::drawRenderNode(RenderNode* renderNode, Rect& dirty, int32_t replayFlags) { // All the usual checks and setup operations (quickReject, setupDraw, etc.) // will be performed by the display list itself if (renderNode && renderNode->isRenderable()) { // compute 3d ordering renderNode->computeOrdering(); if (CC_UNLIKELY(mCaches.drawDeferDisabled)) { - status = startFrame(); + startFrame(); ReplayStateStruct replayStruct(*this, dirty, replayFlags); renderNode->replay(replayStruct, 0); - return status | replayStruct.mDrawGlStatus; + return; } // Don't avoid overdraw when visualizing, since that makes it harder to // debug where it's coming from, and when the problem occurs. bool avoidOverdraw = !mCaches.debugOverdraw; - DeferredDisplayList deferredList(*currentClipRect(), avoidOverdraw); + DeferredDisplayList deferredList(mState.currentClipRect(), avoidOverdraw); DeferStateStruct deferStruct(deferredList, *this, replayFlags); renderNode->defer(deferStruct, 0); flushLayers(); - status = startFrame(); + startFrame(); - return deferredList.flush(*this, dirty) | status; + deferredList.flush(*this, dirty); + } else { + // Even if there is no drawing command(Ex: invisible), + // it still needs startFrame to clear buffer and start tiling. + startFrame(); } - - // Even if there is no drawing command(Ex: invisible), - // it still needs startFrame to clear buffer and start tiling. - return startFrame(); } -void OpenGLRenderer::drawAlphaBitmap(Texture* texture, float left, float top, const SkPaint* paint) { - float x = left; - float y = top; +void OpenGLRenderer::drawAlphaBitmap(Texture* texture, const SkPaint* paint) { + float x = 0; + float y = 0; texture->setWrap(GL_CLAMP_TO_EDGE, true); bool ignoreTransform = false; if (currentTransform()->isPureTranslate()) { - x = (int) floorf(left + currentTransform()->getTranslateX() + 0.5f); - y = (int) floorf(top + currentTransform()->getTranslateY() + 0.5f); + x = floorf(currentTransform()->getTranslateX() + 0.5f); + y = floorf(currentTransform()->getTranslateY() + 0.5f); ignoreTransform = true; texture->setFilter(GL_NEAREST, true); } else { - texture->setFilter(getFilter(paint), true); + texture->setFilter(PaintUtils::getFilter(paint), true); } // No need to check for a UV mapper on the texture object, only ARGB_8888 // bitmaps get packed in the atlas drawAlpha8TextureMesh(x, y, x + texture->width, y + texture->height, texture->id, - paint, (GLvoid*) NULL, (GLvoid*) gMeshTextureOffset, - GL_TRIANGLE_STRIP, gMeshCount, ignoreTransform); + paint, (GLvoid*) nullptr, (GLvoid*) kMeshTextureOffset, + GL_TRIANGLE_STRIP, kUnitQuadCount, ignoreTransform); } /** @@ -1964,20 +2076,40 @@ void OpenGLRenderer::drawAlphaBitmap(Texture* texture, float left, float top, co * will not set the scissor enable or dirty the current layer, if any. * The caller is responsible for properly dirtying the current layer. */ -status_t OpenGLRenderer::drawBitmaps(const SkBitmap* bitmap, AssetAtlas::Entry* entry, +void OpenGLRenderer::drawBitmaps(const SkBitmap* bitmap, AssetAtlas::Entry* entry, int bitmapCount, TextureVertex* vertices, bool pureTranslate, const Rect& bounds, const SkPaint* paint) { - mCaches.activeTexture(0); Texture* texture = entry ? entry->texture : mCaches.textureCache.get(bitmap); - if (!texture) return DrawGlInfo::kStatusDone; + if (!texture) return; const AutoTexture autoCleanup(texture); + if (USE_GLOPS) { + // TODO: remove layer dirty in multi-draw callers + // TODO: snap doesn't need to touch transform, only texture filter. + bool snap = pureTranslate; + const float x = floorf(bounds.left + 0.5f); + const float y = floorf(bounds.top + 0.5f); + int textureFillFlags = static_cast<int>((bitmap->colorType() == kAlpha_8_SkColorType) + ? TextureFillFlags::kIsAlphaMaskTexture : TextureFillFlags::kNone); + Glop glop; + GlopBuilder(mRenderState, mCaches, &glop) + .setMeshTexturedMesh(vertices, bitmapCount * 6) + .setFillTexturePaint(*texture, textureFillFlags, paint, currentSnapshot()->alpha) + .setTransform(currentSnapshot()->getOrthoMatrix(), Matrix4::identity(), false) + .setModelViewOffsetRectOptionalSnap(snap, x, y, Rect(0, 0, bounds.getWidth(), bounds.getHeight())) + .setRoundRectClipState(currentSnapshot()->roundRectClipState) + .build(); + renderGlop(glop); + return; + } + + mCaches.textureState().activateTexture(0); texture->setWrap(GL_CLAMP_TO_EDGE, true); - texture->setFilter(pureTranslate ? GL_NEAREST : getFilter(paint), true); + texture->setFilter(pureTranslate ? GL_NEAREST : PaintUtils::getFilter(paint), true); - const float x = (int) floorf(bounds.left + 0.5f); - const float y = (int) floorf(bounds.top + 0.5f); + const float x = floorf(bounds.left + 0.5f); + const float y = floorf(bounds.top + 0.5f); if (CC_UNLIKELY(bitmap->colorType() == kAlpha_8_SkColorType)) { drawAlpha8TextureMesh(x, y, x + bounds.getWidth(), y + bounds.getHeight(), texture->id, paint, &vertices[0].x, &vertices[0].u, @@ -1990,76 +2122,67 @@ status_t OpenGLRenderer::drawBitmaps(const SkBitmap* bitmap, AssetAtlas::Entry* kModelViewMode_Translate, false); } - return DrawGlInfo::kStatusDrew; + mDirty = true; } -status_t OpenGLRenderer::drawBitmap(const SkBitmap* bitmap, const SkPaint* paint) { +void OpenGLRenderer::drawBitmap(const SkBitmap* bitmap, const SkPaint* paint) { if (quickRejectSetupScissor(0, 0, bitmap->width(), bitmap->height())) { - return DrawGlInfo::kStatusDone; + return; } - mCaches.activeTexture(0); + mCaches.textureState().activateTexture(0); Texture* texture = getTexture(bitmap); - if (!texture) return DrawGlInfo::kStatusDone; + if (!texture) return; const AutoTexture autoCleanup(texture); - if (CC_UNLIKELY(bitmap->colorType() == kAlpha_8_SkColorType)) { - drawAlphaBitmap(texture, 0, 0, paint); - } else { - drawTextureRect(0, 0, bitmap->width(), bitmap->height(), texture, paint); - } - - return DrawGlInfo::kStatusDrew; -} - -status_t OpenGLRenderer::drawBitmapData(const SkBitmap* bitmap, const SkPaint* paint) { - if (quickRejectSetupScissor(0, 0, bitmap->width(), bitmap->height())) { - return DrawGlInfo::kStatusDone; + if (USE_GLOPS) { + int textureFillFlags = static_cast<int>((bitmap->colorType() == kAlpha_8_SkColorType) + ? TextureFillFlags::kIsAlphaMaskTexture : TextureFillFlags::kNone); + Glop glop; + GlopBuilder(mRenderState, mCaches, &glop) + .setMeshTexturedUnitQuad(texture->uvMapper) + .setFillTexturePaint(*texture, textureFillFlags, paint, currentSnapshot()->alpha) + .setTransform(currentSnapshot()->getOrthoMatrix(), *currentTransform(), false) + .setModelViewMapUnitToRectSnap(Rect(0, 0, texture->width, texture->height)) + .setRoundRectClipState(currentSnapshot()->roundRectClipState) + .build(); + renderGlop(glop); + return; } - mCaches.activeTexture(0); - Texture* texture = mCaches.textureCache.getTransient(bitmap); - const AutoTexture autoCleanup(texture); - if (CC_UNLIKELY(bitmap->colorType() == kAlpha_8_SkColorType)) { - drawAlphaBitmap(texture, 0, 0, paint); + drawAlphaBitmap(texture, paint); } else { - drawTextureRect(0, 0, bitmap->width(), bitmap->height(), texture, paint); + drawTextureRect(texture, paint); } - return DrawGlInfo::kStatusDrew; + mDirty = true; } -status_t OpenGLRenderer::drawBitmapMesh(const SkBitmap* bitmap, int meshWidth, int meshHeight, +void OpenGLRenderer::drawBitmapMesh(const SkBitmap* bitmap, int meshWidth, int meshHeight, const float* vertices, const int* colors, const SkPaint* paint) { - if (!vertices || currentSnapshot()->isIgnored()) { - return DrawGlInfo::kStatusDone; + if (!vertices || mState.currentlyIgnored()) { + return; } - // TODO: use quickReject on bounds from vertices - mCaches.enableScissor(); - float left = FLT_MAX; float top = FLT_MAX; float right = FLT_MIN; float bottom = FLT_MIN; - const uint32_t count = meshWidth * meshHeight * 6; + const uint32_t elementCount = meshWidth * meshHeight * 6; - Vector<ColorTextureVertex> mesh; // TODO: use C++11 unique_ptr - mesh.setCapacity(count); - ColorTextureVertex* vertex = mesh.editArray(); + std::unique_ptr<ColorTextureVertex[]> mesh(new ColorTextureVertex[elementCount]); + ColorTextureVertex* vertex = &mesh[0]; - bool cleanupColors = false; + std::unique_ptr<int[]> tempColors; if (!colors) { uint32_t colorsCount = (meshWidth + 1) * (meshHeight + 1); - int* newColors = new int[colorsCount]; - memset(newColors, 0xff, colorsCount * sizeof(int)); - colors = newColors; - cleanupColors = true; + tempColors.reset(new int[colorsCount]); + memset(tempColors.get(), 0xff, colorsCount * sizeof(int)); + colors = tempColors.get(); } - mCaches.activeTexture(0); Texture* texture = mRenderState.assetAtlas().getEntryTexture(bitmap); const UvMapper& mapper(getMapper(texture)); @@ -2099,32 +2222,46 @@ status_t OpenGLRenderer::drawBitmapMesh(const SkBitmap* bitmap, int meshWidth, i } if (quickRejectSetupScissor(left, top, right, bottom)) { - if (cleanupColors) delete[] colors; - return DrawGlInfo::kStatusDone; + return; } if (!texture) { texture = mCaches.textureCache.get(bitmap); if (!texture) { - if (cleanupColors) delete[] colors; - return DrawGlInfo::kStatusDone; + return; } } const AutoTexture autoCleanup(texture); + if (USE_GLOPS) { + /* + * TODO: handle alpha_8 textures correctly by applying paint color, but *not* + * shader in that case to mimic the behavior in SkiaCanvas::drawBitmapMesh. + */ + Glop glop; + GlopBuilder(mRenderState, mCaches, &glop) + .setMeshColoredTexturedMesh(mesh.get(), elementCount) + .setFillTexturePaint(*texture, static_cast<int>(TextureFillFlags::kNone), paint, currentSnapshot()->alpha) + .setTransform(currentSnapshot()->getOrthoMatrix(), *currentTransform(), false) + .setModelViewOffsetRect(0, 0, Rect(left, top, right, bottom)) + .setRoundRectClipState(currentSnapshot()->roundRectClipState) + .build(); + renderGlop(glop); + return; + } + + mCaches.textureState().activateTexture(0); texture->setWrap(GL_CLAMP_TO_EDGE, true); - texture->setFilter(getFilter(paint), true); + texture->setFilter(PaintUtils::getFilter(paint), true); int alpha; SkXfermode::Mode mode; getAlphaAndMode(paint, &alpha, &mode); - float a = alpha / 255.0f; - if (hasLayer()) { - dirtyLayer(left, top, right, bottom, *currentTransform()); - } + dirtyLayer(left, top, right, bottom, *currentTransform()); + float a = alpha / 255.0f; setupDraw(); setupDrawWithTextureAndColor(); setupDrawColor(a, a, a, a); @@ -2132,177 +2269,177 @@ status_t OpenGLRenderer::drawBitmapMesh(const SkBitmap* bitmap, int meshWidth, i setupDrawBlending(paint, true); setupDrawProgram(); setupDrawDirtyRegionsDisabled(); - setupDrawModelView(kModelViewMode_TranslateAndScale, false, 0.0f, 0.0f, 1.0f, 1.0f); + setupDrawModelView(kModelViewMode_Translate, false, 0, 0, 0, 0); setupDrawTexture(texture->id); setupDrawPureColorUniforms(); setupDrawColorFilterUniforms(getColorFilter(paint)); setupDrawMesh(&mesh[0].x, &mesh[0].u, &mesh[0].r); - glDrawArrays(GL_TRIANGLES, 0, count); + glDrawArrays(GL_TRIANGLES, 0, elementCount); - int slot = mCaches.currentProgram->getAttrib("colors"); + int slot = mCaches.program().getAttrib("colors"); if (slot >= 0) { glDisableVertexAttribArray(slot); } - if (cleanupColors) delete[] colors; - - return DrawGlInfo::kStatusDrew; + mDirty = true; } -status_t OpenGLRenderer::drawBitmap(const SkBitmap* bitmap, - float srcLeft, float srcTop, float srcRight, float srcBottom, - float dstLeft, float dstTop, float dstRight, float dstBottom, - const SkPaint* paint) { - if (quickRejectSetupScissor(dstLeft, dstTop, dstRight, dstBottom)) { - return DrawGlInfo::kStatusDone; +void OpenGLRenderer::drawBitmap(const SkBitmap* bitmap, Rect src, Rect dst, const SkPaint* paint) { + if (quickRejectSetupScissor(dst)) { + return; } - mCaches.activeTexture(0); Texture* texture = getTexture(bitmap); - if (!texture) return DrawGlInfo::kStatusDone; + if (!texture) return; const AutoTexture autoCleanup(texture); + if (USE_GLOPS) { + Rect uv(fmax(0.0f, src.left / texture->width), + fmax(0.0f, src.top / texture->height), + fmin(1.0f, src.right / texture->width), + fmin(1.0f, src.bottom / texture->height)); + + int textureFillFlags = static_cast<int>((bitmap->colorType() == kAlpha_8_SkColorType) + ? TextureFillFlags::kIsAlphaMaskTexture : TextureFillFlags::kNone); + Glop glop; + GlopBuilder(mRenderState, mCaches, &glop) + .setMeshTexturedUvQuad(texture->uvMapper, uv) + .setFillTexturePaint(*texture, textureFillFlags, paint, currentSnapshot()->alpha) + .setTransform(currentSnapshot()->getOrthoMatrix(), *currentTransform(), false) + .setModelViewMapUnitToRectSnap(dst) + .setRoundRectClipState(currentSnapshot()->roundRectClipState) + .build(); + renderGlop(glop); + return; + } + + mCaches.textureState().activateTexture(0); + const float width = texture->width; const float height = texture->height; - float u1 = fmax(0.0f, srcLeft / width); - float v1 = fmax(0.0f, srcTop / height); - float u2 = fmin(1.0f, srcRight / width); - float v2 = fmin(1.0f, srcBottom / height); + float u1 = fmax(0.0f, src.left / width); + float v1 = fmax(0.0f, src.top / height); + float u2 = fmin(1.0f, src.right / width); + float v2 = fmin(1.0f, src.bottom / height); getMapper(texture).map(u1, v1, u2, v2); - mCaches.unbindMeshBuffer(); + mRenderState.meshState().unbindMeshBuffer(); resetDrawTextureTexCoords(u1, v1, u2, v2); texture->setWrap(GL_CLAMP_TO_EDGE, true); - float scaleX = (dstRight - dstLeft) / (srcRight - srcLeft); - float scaleY = (dstBottom - dstTop) / (srcBottom - srcTop); + float scaleX = (dst.right - dst.left) / (src.right - src.left); + float scaleY = (dst.bottom - dst.top) / (src.bottom - src.top); bool scaled = scaleX != 1.0f || scaleY != 1.0f; - // Apply a scale transform on the canvas only when a shader is in use - // Skia handles the ratio between the dst and src rects as a scale factor - // when a shader is set - bool useScaleTransform = getShader(paint) && scaled; bool ignoreTransform = false; - if (CC_LIKELY(currentTransform()->isPureTranslate() && !useScaleTransform)) { - float x = (int) floorf(dstLeft + currentTransform()->getTranslateX() + 0.5f); - float y = (int) floorf(dstTop + currentTransform()->getTranslateY() + 0.5f); + if (CC_LIKELY(currentTransform()->isPureTranslate())) { + float x = floorf(dst.left + currentTransform()->getTranslateX() + 0.5f); + float y = floorf(dst.top + currentTransform()->getTranslateY() + 0.5f); - dstRight = x + (dstRight - dstLeft); - dstBottom = y + (dstBottom - dstTop); + dst.right = x + (dst.right - dst.left); + dst.bottom = y + (dst.bottom - dst.top); - dstLeft = x; - dstTop = y; + dst.left = x; + dst.top = y; - texture->setFilter(scaled ? getFilter(paint) : GL_NEAREST, true); + texture->setFilter(scaled ? PaintUtils::getFilter(paint) : GL_NEAREST, true); ignoreTransform = true; } else { - texture->setFilter(getFilter(paint), true); - } - - if (CC_UNLIKELY(useScaleTransform)) { - save(SkCanvas::kMatrix_SaveFlag); - translate(dstLeft, dstTop); - scale(scaleX, scaleY); - - dstLeft = 0.0f; - dstTop = 0.0f; - - dstRight = srcRight - srcLeft; - dstBottom = srcBottom - srcTop; + texture->setFilter(PaintUtils::getFilter(paint), true); } if (CC_UNLIKELY(bitmap->colorType() == kAlpha_8_SkColorType)) { - drawAlpha8TextureMesh(dstLeft, dstTop, dstRight, dstBottom, + drawAlpha8TextureMesh(dst.left, dst.top, dst.right, dst.bottom, texture->id, paint, &mMeshVertices[0].x, &mMeshVertices[0].u, - GL_TRIANGLE_STRIP, gMeshCount, ignoreTransform); + GL_TRIANGLE_STRIP, kUnitQuadCount, ignoreTransform); } else { - drawTextureMesh(dstLeft, dstTop, dstRight, dstBottom, + drawTextureMesh(dst.left, dst.top, dst.right, dst.bottom, texture->id, paint, texture->blend, &mMeshVertices[0].x, &mMeshVertices[0].u, - GL_TRIANGLE_STRIP, gMeshCount, false, ignoreTransform); - } - - if (CC_UNLIKELY(useScaleTransform)) { - restore(); + GL_TRIANGLE_STRIP, kUnitQuadCount, false, ignoreTransform); } resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f); - return DrawGlInfo::kStatusDrew; + mDirty = true; } -status_t OpenGLRenderer::drawPatch(const SkBitmap* bitmap, const Res_png_9patch* patch, - float left, float top, float right, float bottom, const SkPaint* paint) { - if (quickRejectSetupScissor(left, top, right, bottom)) { - return DrawGlInfo::kStatusDone; +void OpenGLRenderer::drawPatch(const SkBitmap* bitmap, const Patch* mesh, + AssetAtlas::Entry* entry, float left, float top, float right, float bottom, + const SkPaint* paint) { + if (!mesh || !mesh->verticesCount || quickRejectSetupScissor(left, top, right, bottom)) { + return; } - AssetAtlas::Entry* entry = mRenderState.assetAtlas().getEntry(bitmap); - const Patch* mesh = mCaches.patchCache.get(entry, bitmap->width(), bitmap->height(), - right - left, bottom - top, patch); + Texture* texture = entry ? entry->texture : mCaches.textureCache.get(bitmap); + if (!texture) return; - return drawPatch(bitmap, mesh, entry, left, top, right, bottom, paint); -} + if (USE_GLOPS) { + // 9 patches are built for stretching - always filter + int textureFillFlags = static_cast<int>(TextureFillFlags::kForceFilter); + if (bitmap->colorType() == kAlpha_8_SkColorType) { + textureFillFlags |= TextureFillFlags::kIsAlphaMaskTexture; + } + Glop glop; + GlopBuilder(mRenderState, mCaches, &glop) + .setMeshPatchQuads(*mesh) + .setFillTexturePaint(*texture, textureFillFlags, paint, currentSnapshot()->alpha) + .setTransform(currentSnapshot()->getOrthoMatrix(), *currentTransform(), false) + .setModelViewOffsetRectSnap(left, top, Rect(0, 0, right - left, bottom - top)) // TODO: get minimal bounds from patch + .setRoundRectClipState(currentSnapshot()->roundRectClipState) + .build(); + renderGlop(glop); + return; + } -status_t OpenGLRenderer::drawPatch(const SkBitmap* bitmap, const Patch* mesh, - AssetAtlas::Entry* entry, float left, float top, float right, float bottom, - const SkPaint* paint) { - if (quickRejectSetupScissor(left, top, right, bottom)) { - return DrawGlInfo::kStatusDone; - } - - if (CC_LIKELY(mesh && mesh->verticesCount > 0)) { - mCaches.activeTexture(0); - Texture* texture = entry ? entry->texture : mCaches.textureCache.get(bitmap); - if (!texture) return DrawGlInfo::kStatusDone; - const AutoTexture autoCleanup(texture); - - texture->setWrap(GL_CLAMP_TO_EDGE, true); - texture->setFilter(GL_LINEAR, true); - - const bool pureTranslate = currentTransform()->isPureTranslate(); - // Mark the current layer dirty where we are going to draw the patch - if (hasLayer() && mesh->hasEmptyQuads) { - const float offsetX = left + currentTransform()->getTranslateX(); - const float offsetY = top + currentTransform()->getTranslateY(); - const size_t count = mesh->quads.size(); - for (size_t i = 0; i < count; i++) { - const Rect& bounds = mesh->quads.itemAt(i); - if (CC_LIKELY(pureTranslate)) { - const float x = (int) floorf(bounds.left + offsetX + 0.5f); - const float y = (int) floorf(bounds.top + offsetY + 0.5f); - dirtyLayer(x, y, x + bounds.getWidth(), y + bounds.getHeight()); - } else { - dirtyLayer(left + bounds.left, top + bounds.top, - left + bounds.right, top + bounds.bottom, *currentTransform()); - } + mCaches.textureState().activateTexture(0); + const AutoTexture autoCleanup(texture); + + texture->setWrap(GL_CLAMP_TO_EDGE, true); + texture->setFilter(GL_LINEAR, true); + + const bool pureTranslate = currentTransform()->isPureTranslate(); + // Mark the current layer dirty where we are going to draw the patch + if (hasLayer() && mesh->hasEmptyQuads) { + const float offsetX = left + currentTransform()->getTranslateX(); + const float offsetY = top + currentTransform()->getTranslateY(); + const size_t count = mesh->quads.size(); + for (size_t i = 0; i < count; i++) { + const Rect& bounds = mesh->quads.itemAt(i); + if (CC_LIKELY(pureTranslate)) { + const float x = floorf(bounds.left + offsetX + 0.5f); + const float y = floorf(bounds.top + offsetY + 0.5f); + dirtyLayer(x, y, x + bounds.getWidth(), y + bounds.getHeight()); + } else { + dirtyLayer(left + bounds.left, top + bounds.top, + left + bounds.right, top + bounds.bottom, *currentTransform()); } } + } - bool ignoreTransform = false; - if (CC_LIKELY(pureTranslate)) { - const float x = (int) floorf(left + currentTransform()->getTranslateX() + 0.5f); - const float y = (int) floorf(top + currentTransform()->getTranslateY() + 0.5f); + bool ignoreTransform = false; + if (CC_LIKELY(pureTranslate)) { + const float x = floorf(left + currentTransform()->getTranslateX() + 0.5f); + const float y = floorf(top + currentTransform()->getTranslateY() + 0.5f); - right = x + right - left; - bottom = y + bottom - top; - left = x; - top = y; - ignoreTransform = true; - } - drawIndexedTextureMesh(left, top, right, bottom, texture->id, paint, - texture->blend, (GLvoid*) mesh->offset, (GLvoid*) mesh->textureOffset, - GL_TRIANGLES, mesh->indexCount, false, ignoreTransform, - mCaches.patchCache.getMeshBuffer(), kModelViewMode_Translate, !mesh->hasEmptyQuads); + right = x + right - left; + bottom = y + bottom - top; + left = x; + top = y; + ignoreTransform = true; } + drawIndexedTextureMesh(left, top, right, bottom, texture->id, paint, + texture->blend, (GLvoid*) mesh->positionOffset, (GLvoid*) mesh->textureOffset, + GL_TRIANGLES, mesh->indexCount, false, ignoreTransform, + mCaches.patchCache.getMeshBuffer(), kModelViewMode_Translate, !mesh->hasEmptyQuads); - return DrawGlInfo::kStatusDrew; + mDirty = true; } /** @@ -2310,42 +2447,77 @@ status_t OpenGLRenderer::drawPatch(const SkBitmap* bitmap, const Patch* mesh, * will not set the scissor enable or dirty the current layer, if any. * The caller is responsible for properly dirtying the current layer. */ -status_t OpenGLRenderer::drawPatches(const SkBitmap* bitmap, AssetAtlas::Entry* entry, - TextureVertex* vertices, uint32_t indexCount, const SkPaint* paint) { - mCaches.activeTexture(0); +void OpenGLRenderer::drawPatches(const SkBitmap* bitmap, AssetAtlas::Entry* entry, + TextureVertex* vertices, uint32_t elementCount, const SkPaint* paint) { + mCaches.textureState().activateTexture(0); Texture* texture = entry ? entry->texture : mCaches.textureCache.get(bitmap); - if (!texture) return DrawGlInfo::kStatusDone; + if (!texture) return; const AutoTexture autoCleanup(texture); + if (USE_GLOPS) { + // TODO: get correct bounds from caller + // 9 patches are built for stretching - always filter + int textureFillFlags = static_cast<int>(TextureFillFlags::kForceFilter); + if (bitmap->colorType() == kAlpha_8_SkColorType) { + textureFillFlags |= TextureFillFlags::kIsAlphaMaskTexture; + } + Glop glop; + GlopBuilder(mRenderState, mCaches, &glop) + .setMeshTexturedIndexedQuads(vertices, elementCount) + .setFillTexturePaint(*texture, textureFillFlags, paint, currentSnapshot()->alpha) + .setTransform(currentSnapshot()->getOrthoMatrix(), Matrix4::identity(), false) + .setModelViewOffsetRect(0, 0, Rect(0, 0, 0, 0)) + .setRoundRectClipState(currentSnapshot()->roundRectClipState) + .build(); + renderGlop(glop); + return; + } + texture->setWrap(GL_CLAMP_TO_EDGE, true); texture->setFilter(GL_LINEAR, true); drawIndexedTextureMesh(0.0f, 0.0f, 1.0f, 1.0f, texture->id, paint, texture->blend, &vertices[0].x, &vertices[0].u, - GL_TRIANGLES, indexCount, false, true, 0, kModelViewMode_Translate, false); + GL_TRIANGLES, elementCount, false, true, 0, kModelViewMode_Translate, false); - return DrawGlInfo::kStatusDrew; + mDirty = true; } -status_t OpenGLRenderer::drawVertexBuffer(float translateX, float translateY, +void OpenGLRenderer::drawVertexBuffer(float translateX, float translateY, const VertexBuffer& vertexBuffer, const SkPaint* paint, int displayFlags) { // not missing call to quickReject/dirtyLayer, always done at a higher level if (!vertexBuffer.getVertexCount()) { // no vertices to draw - return DrawGlInfo::kStatusDone; + return; } + if (USE_GLOPS) { + bool fudgeOffset = displayFlags & kVertexBuffer_Offset; + bool shadowInterp = displayFlags & kVertexBuffer_ShadowInterp; + Glop glop; + GlopBuilder(mRenderState, mCaches, &glop) + .setMeshVertexBuffer(vertexBuffer, shadowInterp) + .setFillPaint(*paint, currentSnapshot()->alpha) + .setTransform(currentSnapshot()->getOrthoMatrix(), *currentTransform(), fudgeOffset) + .setModelViewOffsetRect(translateX, translateY, vertexBuffer.getBounds()) + .setRoundRectClipState(currentSnapshot()->roundRectClipState) + .build(); + renderGlop(glop); + return; + } + + const VertexBuffer::MeshFeatureFlags meshFeatureFlags = vertexBuffer.getMeshFeatureFlags(); Rect bounds(vertexBuffer.getBounds()); bounds.translate(translateX, translateY); dirtyLayer(bounds.left, bounds.top, bounds.right, bounds.bottom, *currentTransform()); int color = paint->getColor(); - bool isAA = paint->isAntiAlias(); + bool isAA = meshFeatureFlags & VertexBuffer::kAlpha; setupDraw(); setupDrawNoTexture(); if (isAA) setupDrawVertexAlpha((displayFlags & kVertexBuffer_ShadowInterp)); - setupDrawColor(color, ((color >> 24) & 0xFF) * mSnapshot->alpha); + setupDrawColor(color, ((color >> 24) & 0xFF) * currentSnapshot()->alpha); setupDrawColorFilter(getColorFilter(paint)); setupDrawShader(getShader(paint)); setupDrawBlending(paint, isAA); @@ -2357,40 +2529,34 @@ status_t OpenGLRenderer::drawVertexBuffer(float translateX, float translateY, setupDrawShaderUniforms(getShader(paint)); const void* vertices = vertexBuffer.getBuffer(); - mCaches.unbindMeshBuffer(); - mCaches.bindPositionVertexPointer(true, vertices, isAA ? gAlphaVertexStride : gVertexStride); - mCaches.resetTexCoordsVertexPointer(); + mRenderState.meshState().unbindMeshBuffer(); + mRenderState.meshState().bindPositionVertexPointer(true, vertices, + isAA ? kAlphaVertexStride : kVertexStride); + mRenderState.meshState().resetTexCoordsVertexPointer(); int alphaSlot = -1; if (isAA) { - void* alphaCoords = ((GLbyte*) vertices) + gVertexAlphaOffset; - alphaSlot = mCaches.currentProgram->getAttrib("vtxAlpha"); + void* alphaCoords = ((GLbyte*) vertices) + kVertexAlphaOffset; + alphaSlot = mCaches.program().getAttrib("vtxAlpha"); // TODO: avoid enable/disable in back to back uses of the alpha attribute glEnableVertexAttribArray(alphaSlot); - glVertexAttribPointer(alphaSlot, 1, GL_FLOAT, GL_FALSE, gAlphaVertexStride, alphaCoords); + glVertexAttribPointer(alphaSlot, 1, GL_FLOAT, GL_FALSE, kAlphaVertexStride, alphaCoords); } - const VertexBuffer::Mode mode = vertexBuffer.getMode(); - if (mode == VertexBuffer::kStandard) { - mCaches.unbindIndicesBuffer(); + if (meshFeatureFlags & VertexBuffer::kIndices) { + mRenderState.meshState().unbindIndicesBuffer(); + glDrawElements(GL_TRIANGLE_STRIP, vertexBuffer.getIndexCount(), + GL_UNSIGNED_SHORT, vertexBuffer.getIndices()); + } else { + mRenderState.meshState().unbindIndicesBuffer(); glDrawArrays(GL_TRIANGLE_STRIP, 0, vertexBuffer.getVertexCount()); - } else if (mode == VertexBuffer::kOnePolyRingShadow) { - mCaches.bindShadowIndicesBuffer(); - glDrawElements(GL_TRIANGLE_STRIP, ONE_POLY_RING_SHADOW_INDEX_COUNT, GL_UNSIGNED_SHORT, 0); - } else if (mode == VertexBuffer::kTwoPolyRingShadow) { - mCaches.bindShadowIndicesBuffer(); - glDrawElements(GL_TRIANGLE_STRIP, TWO_POLY_RING_SHADOW_INDEX_COUNT, GL_UNSIGNED_SHORT, 0); - } else if (mode == VertexBuffer::kIndices) { - mCaches.unbindIndicesBuffer(); - glDrawElements(GL_TRIANGLE_STRIP, vertexBuffer.getIndexCount(), GL_UNSIGNED_SHORT, - vertexBuffer.getIndices()); } if (isAA) { glDisableVertexAttribArray(alphaSlot); } - return DrawGlInfo::kStatusDrew; + mDirty = true; } /** @@ -2402,11 +2568,11 @@ status_t OpenGLRenderer::drawVertexBuffer(float translateX, float translateY, * * Doesn't yet support joins, caps, or path effects. */ -status_t OpenGLRenderer::drawConvexPath(const SkPath& path, const SkPaint* paint) { +void OpenGLRenderer::drawConvexPath(const SkPath& path, const SkPaint* paint) { VertexBuffer vertexBuffer; // TODO: try clipping large paths to viewport PathTessellator::tessellatePath(path, paint, *currentTransform(), vertexBuffer); - return drawVertexBuffer(vertexBuffer, paint); + drawVertexBuffer(vertexBuffer, paint); } /** @@ -2420,8 +2586,8 @@ status_t OpenGLRenderer::drawConvexPath(const SkPath& path, const SkPaint* paint * TODO: try using a fixed input buffer for non-capped lines as in text rendering. this may reduce * memory transfer by removing need for degenerate vertices. */ -status_t OpenGLRenderer::drawLines(const float* points, int count, const SkPaint* paint) { - if (currentSnapshot()->isIgnored() || count < 4) return DrawGlInfo::kStatusDone; +void OpenGLRenderer::drawLines(const float* points, int count, const SkPaint* paint) { + if (mState.currentlyIgnored() || count < 4) return; count &= ~0x3; // round down to nearest four @@ -2430,15 +2596,15 @@ status_t OpenGLRenderer::drawLines(const float* points, int count, const SkPaint const Rect& bounds = buffer.getBounds(); if (quickRejectSetupScissor(bounds.left, bounds.top, bounds.right, bounds.bottom)) { - return DrawGlInfo::kStatusDone; + return; } int displayFlags = paint->isAntiAlias() ? 0 : kVertexBuffer_Offset; - return drawVertexBuffer(buffer, paint, displayFlags); + drawVertexBuffer(buffer, paint, displayFlags); } -status_t OpenGLRenderer::drawPoints(const float* points, int count, const SkPaint* paint) { - if (currentSnapshot()->isIgnored() || count < 2) return DrawGlInfo::kStatusDone; +void OpenGLRenderer::drawPoints(const float* points, int count, const SkPaint* paint) { + if (mState.currentlyIgnored() || count < 2) return; count &= ~0x1; // round down to nearest two @@ -2447,18 +2613,20 @@ status_t OpenGLRenderer::drawPoints(const float* points, int count, const SkPain const Rect& bounds = buffer.getBounds(); if (quickRejectSetupScissor(bounds.left, bounds.top, bounds.right, bounds.bottom)) { - return DrawGlInfo::kStatusDone; + return; } int displayFlags = paint->isAntiAlias() ? 0 : kVertexBuffer_Offset; - return drawVertexBuffer(buffer, paint, displayFlags); + drawVertexBuffer(buffer, paint, displayFlags); + + mDirty = true; } -status_t OpenGLRenderer::drawColor(int color, SkXfermode::Mode mode) { +void OpenGLRenderer::drawColor(int color, SkXfermode::Mode mode) { // No need to check against the clip, we fill the clip region - if (currentSnapshot()->isIgnored()) return DrawGlInfo::kStatusDone; + if (mState.currentlyIgnored()) return; - Rect clip(*currentClipRect()); + Rect clip(mState.currentClipRect()); clip.snapToPixelBoundaries(); SkPaint paint; @@ -2467,12 +2635,12 @@ status_t OpenGLRenderer::drawColor(int color, SkXfermode::Mode mode) { drawColorRect(clip.left, clip.top, clip.right, clip.bottom, &paint, true); - return DrawGlInfo::kStatusDrew; + mDirty = true; } -status_t OpenGLRenderer::drawShape(float left, float top, const PathTexture* texture, +void OpenGLRenderer::drawShape(float left, float top, PathTexture* texture, const SkPaint* paint) { - if (!texture) return DrawGlInfo::kStatusDone; + if (!texture) return; const AutoTexture autoCleanup(texture); const float x = left + texture->left - texture->offset; @@ -2480,89 +2648,89 @@ status_t OpenGLRenderer::drawShape(float left, float top, const PathTexture* tex drawPathTexture(texture, x, y, paint); - return DrawGlInfo::kStatusDrew; + mDirty = true; } -status_t OpenGLRenderer::drawRoundRect(float left, float top, float right, float bottom, +void OpenGLRenderer::drawRoundRect(float left, float top, float right, float bottom, float rx, float ry, const SkPaint* p) { - if (currentSnapshot()->isIgnored() + if (mState.currentlyIgnored() || quickRejectSetupScissor(left, top, right, bottom, p) - || paintWillNotDraw(*p)) { - return DrawGlInfo::kStatusDone; + || PaintUtils::paintWillNotDraw(*p)) { + return; } - if (p->getPathEffect() != 0) { - mCaches.activeTexture(0); - const PathTexture* texture = mCaches.pathCache.getRoundRect( + if (p->getPathEffect() != nullptr) { + mCaches.textureState().activateTexture(0); + PathTexture* texture = mCaches.pathCache.getRoundRect( right - left, bottom - top, rx, ry, p); - return drawShape(left, top, texture, p); + drawShape(left, top, texture, p); + } else { + const VertexBuffer* vertexBuffer = mCaches.tessellationCache.getRoundRect( + *currentTransform(), *p, right - left, bottom - top, rx, ry); + drawVertexBuffer(left, top, *vertexBuffer, p); } - - const VertexBuffer* vertexBuffer = mCaches.tessellationCache.getRoundRect( - *currentTransform(), *p, right - left, bottom - top, rx, ry); - return drawVertexBuffer(left, top, *vertexBuffer, p); } -status_t OpenGLRenderer::drawCircle(float x, float y, float radius, const SkPaint* p) { - if (currentSnapshot()->isIgnored() +void OpenGLRenderer::drawCircle(float x, float y, float radius, const SkPaint* p) { + if (mState.currentlyIgnored() || quickRejectSetupScissor(x - radius, y - radius, x + radius, y + radius, p) - || paintWillNotDraw(*p)) { - return DrawGlInfo::kStatusDone; - } - if (p->getPathEffect() != 0) { - mCaches.activeTexture(0); - const PathTexture* texture = mCaches.pathCache.getCircle(radius, p); - return drawShape(x - radius, y - radius, texture, p); + || PaintUtils::paintWillNotDraw(*p)) { + return; } - - SkPath path; - if (p->getStyle() == SkPaint::kStrokeAndFill_Style) { - path.addCircle(x, y, radius + p->getStrokeWidth() / 2); + if (p->getPathEffect() != nullptr) { + mCaches.textureState().activateTexture(0); + PathTexture* texture = mCaches.pathCache.getCircle(radius, p); + drawShape(x - radius, y - radius, texture, p); } else { - path.addCircle(x, y, radius); + SkPath path; + if (p->getStyle() == SkPaint::kStrokeAndFill_Style) { + path.addCircle(x, y, radius + p->getStrokeWidth() / 2); + } else { + path.addCircle(x, y, radius); + } + drawConvexPath(path, p); } - return drawConvexPath(path, p); } -status_t OpenGLRenderer::drawOval(float left, float top, float right, float bottom, +void OpenGLRenderer::drawOval(float left, float top, float right, float bottom, const SkPaint* p) { - if (currentSnapshot()->isIgnored() + if (mState.currentlyIgnored() || quickRejectSetupScissor(left, top, right, bottom, p) - || paintWillNotDraw(*p)) { - return DrawGlInfo::kStatusDone; - } - - if (p->getPathEffect() != 0) { - mCaches.activeTexture(0); - const PathTexture* texture = mCaches.pathCache.getOval(right - left, bottom - top, p); - return drawShape(left, top, texture, p); + || PaintUtils::paintWillNotDraw(*p)) { + return; } - SkPath path; - SkRect rect = SkRect::MakeLTRB(left, top, right, bottom); - if (p->getStyle() == SkPaint::kStrokeAndFill_Style) { - rect.outset(p->getStrokeWidth() / 2, p->getStrokeWidth() / 2); + if (p->getPathEffect() != nullptr) { + mCaches.textureState().activateTexture(0); + PathTexture* texture = mCaches.pathCache.getOval(right - left, bottom - top, p); + drawShape(left, top, texture, p); + } else { + SkPath path; + SkRect rect = SkRect::MakeLTRB(left, top, right, bottom); + if (p->getStyle() == SkPaint::kStrokeAndFill_Style) { + rect.outset(p->getStrokeWidth() / 2, p->getStrokeWidth() / 2); + } + path.addOval(rect); + drawConvexPath(path, p); } - path.addOval(rect); - return drawConvexPath(path, p); } -status_t OpenGLRenderer::drawArc(float left, float top, float right, float bottom, +void OpenGLRenderer::drawArc(float left, float top, float right, float bottom, float startAngle, float sweepAngle, bool useCenter, const SkPaint* p) { - if (currentSnapshot()->isIgnored() + if (mState.currentlyIgnored() || quickRejectSetupScissor(left, top, right, bottom, p) - || paintWillNotDraw(*p)) { - return DrawGlInfo::kStatusDone; + || PaintUtils::paintWillNotDraw(*p)) { + return; } // TODO: support fills (accounting for concavity if useCenter && sweepAngle > 180) - if (p->getStyle() != SkPaint::kStroke_Style || p->getPathEffect() != 0 || useCenter) { - mCaches.activeTexture(0); - const PathTexture* texture = mCaches.pathCache.getArc(right - left, bottom - top, + if (p->getStyle() != SkPaint::kStroke_Style || p->getPathEffect() != nullptr || useCenter) { + mCaches.textureState().activateTexture(0); + PathTexture* texture = mCaches.pathCache.getArc(right - left, bottom - top, startAngle, sweepAngle, useCenter, p); - return drawShape(left, top, texture, p); + drawShape(left, top, texture, p); + return; } - SkRect rect = SkRect::MakeLTRB(left, top, right, bottom); if (p->getStyle() == SkPaint::kStrokeAndFill_Style) { rect.outset(p->getStrokeWidth() / 2, p->getStrokeWidth() / 2); @@ -2576,53 +2744,54 @@ status_t OpenGLRenderer::drawArc(float left, float top, float right, float botto if (useCenter) { path.close(); } - return drawConvexPath(path, p); + drawConvexPath(path, p); } // See SkPaintDefaults.h #define SkPaintDefaults_MiterLimit SkIntToScalar(4) -status_t OpenGLRenderer::drawRect(float left, float top, float right, float bottom, +void OpenGLRenderer::drawRect(float left, float top, float right, float bottom, const SkPaint* p) { - if (currentSnapshot()->isIgnored() + if (mState.currentlyIgnored() || quickRejectSetupScissor(left, top, right, bottom, p) - || paintWillNotDraw(*p)) { - return DrawGlInfo::kStatusDone; + || PaintUtils::paintWillNotDraw(*p)) { + return; } if (p->getStyle() != SkPaint::kFill_Style) { // only fill style is supported by drawConvexPath, since others have to handle joins - if (p->getPathEffect() != 0 || p->getStrokeJoin() != SkPaint::kMiter_Join || + if (p->getPathEffect() != nullptr || p->getStrokeJoin() != SkPaint::kMiter_Join || p->getStrokeMiter() != SkPaintDefaults_MiterLimit) { - mCaches.activeTexture(0); - const PathTexture* texture = + mCaches.textureState().activateTexture(0); + PathTexture* texture = mCaches.pathCache.getRect(right - left, bottom - top, p); - return drawShape(left, top, texture, p); + drawShape(left, top, texture, p); + } else { + SkPath path; + SkRect rect = SkRect::MakeLTRB(left, top, right, bottom); + if (p->getStyle() == SkPaint::kStrokeAndFill_Style) { + rect.outset(p->getStrokeWidth() / 2, p->getStrokeWidth() / 2); + } + path.addRect(rect); + drawConvexPath(path, p); } + } else { + if (p->isAntiAlias() && !currentTransform()->isSimple()) { + SkPath path; + path.addRect(left, top, right, bottom); + drawConvexPath(path, p); + } else { + drawColorRect(left, top, right, bottom, p); - SkPath path; - SkRect rect = SkRect::MakeLTRB(left, top, right, bottom); - if (p->getStyle() == SkPaint::kStrokeAndFill_Style) { - rect.outset(p->getStrokeWidth() / 2, p->getStrokeWidth() / 2); + mDirty = true; } - path.addRect(rect); - return drawConvexPath(path, p); - } - - if (p->isAntiAlias() && !currentTransform()->isSimple()) { - SkPath path; - path.addRect(left, top, right, bottom); - return drawConvexPath(path, p); - } else { - drawColorRect(left, top, right, bottom, p); - return DrawGlInfo::kStatusDrew; } } void OpenGLRenderer::drawTextShadow(const SkPaint* paint, const char* text, int bytesCount, int count, const float* positions, FontRenderer& fontRenderer, int alpha, float x, float y) { - mCaches.activeTexture(0); + mCaches.textureState().activateTexture(0); TextShadow textShadow; if (!getTextShadow(paint, &textShadow)) { @@ -2632,17 +2801,30 @@ void OpenGLRenderer::drawTextShadow(const SkPaint* paint, const char* text, // NOTE: The drop shadow will not perform gamma correction // if shader-based correction is enabled mCaches.dropShadowCache.setFontRenderer(fontRenderer); - const ShadowTexture* shadow = mCaches.dropShadowCache.get( + ShadowTexture* texture = mCaches.dropShadowCache.get( paint, text, bytesCount, count, textShadow.radius, positions); // If the drop shadow exceeds the max texture size or couldn't be // allocated, skip drawing - if (!shadow) return; - const AutoTexture autoCleanup(shadow); + if (!texture) return; + const AutoTexture autoCleanup(texture); - const float sx = x - shadow->left + textShadow.dx; - const float sy = y - shadow->top + textShadow.dy; + const float sx = x - texture->left + textShadow.dx; + const float sy = y - texture->top + textShadow.dy; + + if (USE_GLOPS) { + Glop glop; + GlopBuilder(mRenderState, mCaches, &glop) + .setMeshTexturedUnitQuad(nullptr) + .setFillShadowTexturePaint(*texture, textShadow.color, *paint, currentSnapshot()->alpha) + .setTransform(currentSnapshot()->getOrthoMatrix(), *currentTransform(), false) + .setModelViewMapUnitToRect(Rect(sx, sy, sx + texture->width, sy + texture->height)) + .setRoundRectClipState(currentSnapshot()->roundRectClipState) + .build(); + renderGlop(glop); + return; + } - const int shadowAlpha = ((textShadow.color >> 24) & 0xFF) * mSnapshot->alpha; + const int shadowAlpha = ((textShadow.color >> 24) & 0xFF) * currentSnapshot()->alpha; if (getShader(paint)) { textShadow.color = SK_ColorWHITE; } @@ -2655,40 +2837,41 @@ void OpenGLRenderer::drawTextShadow(const SkPaint* paint, const char* text, setupDrawBlending(paint, true); setupDrawProgram(); setupDrawModelView(kModelViewMode_TranslateAndScale, false, - sx, sy, sx + shadow->width, sy + shadow->height); - setupDrawTexture(shadow->id); + sx, sy, sx + texture->width, sy + texture->height); + setupDrawTexture(texture->id); setupDrawPureColorUniforms(); setupDrawColorFilterUniforms(getColorFilter(paint)); setupDrawShaderUniforms(getShader(paint)); - setupDrawMesh(NULL, (GLvoid*) gMeshTextureOffset); + setupDrawMesh(nullptr, (GLvoid*) kMeshTextureOffset); - glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount); + glDrawArrays(GL_TRIANGLE_STRIP, 0, kUnitQuadCount); } bool OpenGLRenderer::canSkipText(const SkPaint* paint) const { - float alpha = (hasTextShadow(paint) ? 1.0f : paint->getAlpha()) * mSnapshot->alpha; - return alpha == 0.0f && getXfermode(paint->getXfermode()) == SkXfermode::kSrcOver_Mode; + float alpha = (hasTextShadow(paint) ? 1.0f : paint->getAlpha()) * currentSnapshot()->alpha; + return MathUtils::isZero(alpha) + && PaintUtils::getXfermode(paint->getXfermode()) == SkXfermode::kSrcOver_Mode; } -status_t OpenGLRenderer::drawPosText(const char* text, int bytesCount, int count, +void OpenGLRenderer::drawPosText(const char* text, int bytesCount, int count, const float* positions, const SkPaint* paint) { - if (text == NULL || count == 0 || currentSnapshot()->isIgnored() || canSkipText(paint)) { - return DrawGlInfo::kStatusDone; + if (text == nullptr || count == 0 || mState.currentlyIgnored() || canSkipText(paint)) { + return; } // NOTE: Skia does not support perspective transform on drawPosText yet if (!currentTransform()->isSimple()) { - return DrawGlInfo::kStatusDone; + return; } - mCaches.enableScissor(); + mRenderState.scissor().setEnabled(true); float x = 0.0f; float y = 0.0f; const bool pureTranslate = currentTransform()->isPureTranslate(); if (pureTranslate) { - x = (int) floorf(x + currentTransform()->getTranslateX() + 0.5f); - y = (int) floorf(y + currentTransform()->getTranslateY() + 0.5f); + x = floorf(x + currentTransform()->getTranslateX() + 0.5f); + y = floorf(y + currentTransform()->getTranslateY() + 0.5f); } FontRenderer& fontRenderer = mCaches.fontRenderer->getFontRenderer(paint); @@ -2710,23 +2893,16 @@ status_t OpenGLRenderer::drawPosText(const char* text, int bytesCount, int count } fontRenderer.setTextureFiltering(linearFilter); - const Rect* clip = pureTranslate ? mSnapshot->clipRect : &mSnapshot->getLocalClip(); + const Rect& clip(pureTranslate ? writableSnapshot()->getClipRect() : writableSnapshot()->getLocalClip()); Rect bounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f); - const bool hasActiveLayer = hasLayer(); - TextSetupFunctor functor(this, x, y, pureTranslate, alpha, mode, paint); - if (fontRenderer.renderPosText(paint, clip, text, 0, bytesCount, count, x, y, - positions, hasActiveLayer ? &bounds : NULL, &functor)) { - if (hasActiveLayer) { - if (!pureTranslate) { - currentTransform()->mapRect(bounds); - } - dirtyLayerUnchecked(bounds, getRegion()); - } + if (fontRenderer.renderPosText(paint, &clip, text, 0, bytesCount, count, x, y, + positions, hasLayer() ? &bounds : nullptr, &functor)) { + dirtyLayer(bounds.left, bounds.top, bounds.right, bounds.bottom, *currentTransform()); + mDirty = true; } - return DrawGlInfo::kStatusDrew; } bool OpenGLRenderer::findBestFontTransform(const mat4& transform, SkMatrix* outMatrix) const { @@ -2750,16 +2926,77 @@ bool OpenGLRenderer::findBestFontTransform(const mat4& transform, SkMatrix* outM return true; } -status_t OpenGLRenderer::drawText(const char* text, int bytesCount, int count, float x, float y, +int OpenGLRenderer::getSaveCount() const { + return mState.getSaveCount(); +} + +int OpenGLRenderer::save(int flags) { + return mState.save(flags); +} + +void OpenGLRenderer::restore() { + mState.restore(); +} + +void OpenGLRenderer::restoreToCount(int saveCount) { + mState.restoreToCount(saveCount); +} + +void OpenGLRenderer::translate(float dx, float dy, float dz) { + mState.translate(dx, dy, dz); +} + +void OpenGLRenderer::rotate(float degrees) { + mState.rotate(degrees); +} + +void OpenGLRenderer::scale(float sx, float sy) { + mState.scale(sx, sy); +} + +void OpenGLRenderer::skew(float sx, float sy) { + mState.skew(sx, sy); +} + +void OpenGLRenderer::setMatrix(const Matrix4& matrix) { + mState.setMatrix(matrix); +} + +void OpenGLRenderer::concatMatrix(const Matrix4& matrix) { + mState.concatMatrix(matrix); +} + +bool OpenGLRenderer::clipRect(float left, float top, float right, float bottom, SkRegion::Op op) { + return mState.clipRect(left, top, right, bottom, op); +} + +bool OpenGLRenderer::clipPath(const SkPath* path, SkRegion::Op op) { + return mState.clipPath(path, op); +} + +bool OpenGLRenderer::clipRegion(const SkRegion* region, SkRegion::Op op) { + return mState.clipRegion(region, op); +} + +void OpenGLRenderer::setClippingOutline(LinearAllocator& allocator, const Outline* outline) { + mState.setClippingOutline(allocator, outline); +} + +void OpenGLRenderer::setClippingRoundRect(LinearAllocator& allocator, + const Rect& rect, float radius, bool highPriority) { + mState.setClippingRoundRect(allocator, rect, radius, highPriority); +} + +void OpenGLRenderer::drawText(const char* text, int bytesCount, int count, float x, float y, const float* positions, const SkPaint* paint, float totalAdvance, const Rect& bounds, DrawOpMode drawOpMode) { - if (drawOpMode == kDrawOpMode_Immediate) { + if (drawOpMode == DrawOpMode::kImmediate) { // The checks for corner-case ignorable text and quick rejection is only done for immediate // drawing as ops from DeferredDisplayList are already filtered for these - if (text == NULL || count == 0 || currentSnapshot()->isIgnored() || canSkipText(paint) || + if (text == nullptr || count == 0 || mState.currentlyIgnored() || canSkipText(paint) || quickRejectSetupScissor(bounds)) { - return DrawGlInfo::kStatusDone; + return; } } @@ -2770,8 +3007,8 @@ status_t OpenGLRenderer::drawText(const char* text, int bytesCount, int count, f const bool pureTranslate = transform.isPureTranslate(); if (CC_LIKELY(pureTranslate)) { - x = (int) floorf(x + transform.getTranslateX() + 0.5f); - y = (int) floorf(y + transform.getTranslateY() + 0.5f); + x = floorf(x + transform.getTranslateX() + 0.5f); + y = floorf(y + transform.getTranslateY() + 0.5f); } int alpha; @@ -2807,25 +3044,25 @@ status_t OpenGLRenderer::drawText(const char* text, int bytesCount, int count, f fontRenderer.setTextureFiltering(linearFilter); // TODO: Implement better clipping for scaled/rotated text - const Rect* clip = !pureTranslate ? NULL : currentClipRect(); + const Rect* clip = !pureTranslate ? nullptr : &mState.currentClipRect(); Rect layerBounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f); bool status; TextSetupFunctor functor(this, x, y, pureTranslate, alpha, mode, paint); // don't call issuedrawcommand, do it at end of batch - bool forceFinish = (drawOpMode != kDrawOpMode_Defer); + bool forceFinish = (drawOpMode != DrawOpMode::kDefer); if (CC_UNLIKELY(paint->getTextAlign() != SkPaint::kLeft_Align)) { SkPaint paintCopy(*paint); paintCopy.setTextAlign(SkPaint::kLeft_Align); status = fontRenderer.renderPosText(&paintCopy, clip, text, 0, bytesCount, count, x, y, - positions, hasActiveLayer ? &layerBounds : NULL, &functor, forceFinish); + positions, hasActiveLayer ? &layerBounds : nullptr, &functor, forceFinish); } else { status = fontRenderer.renderPosText(paint, clip, text, 0, bytesCount, count, x, y, - positions, hasActiveLayer ? &layerBounds : NULL, &functor, forceFinish); + positions, hasActiveLayer ? &layerBounds : nullptr, &functor, forceFinish); } - if ((status || drawOpMode != kDrawOpMode_Immediate) && hasActiveLayer) { + if ((status || drawOpMode != DrawOpMode::kImmediate) && hasActiveLayer) { if (!pureTranslate) { transform.mapRect(layerBounds); } @@ -2834,17 +3071,17 @@ status_t OpenGLRenderer::drawText(const char* text, int bytesCount, int count, f drawTextDecorations(totalAdvance, oldX, oldY, paint); - return DrawGlInfo::kStatusDrew; + mDirty = true; } -status_t OpenGLRenderer::drawTextOnPath(const char* text, int bytesCount, int count, +void OpenGLRenderer::drawTextOnPath(const char* text, int bytesCount, int count, const SkPath* path, float hOffset, float vOffset, const SkPaint* paint) { - if (text == NULL || count == 0 || currentSnapshot()->isIgnored() || canSkipText(paint)) { - return DrawGlInfo::kStatusDone; + if (text == nullptr || count == 0 || mState.currentlyIgnored() || canSkipText(paint)) { + return; } // TODO: avoid scissor by calculating maximum bounds using path bounds + font metrics - mCaches.enableScissor(); + mRenderState.scissor().setEnabled(true); FontRenderer& fontRenderer = mCaches.fontRenderer->getFontRenderer(paint); fontRenderer.setFont(paint, SkMatrix::I()); @@ -2855,45 +3092,38 @@ status_t OpenGLRenderer::drawTextOnPath(const char* text, int bytesCount, int co getAlphaAndMode(paint, &alpha, &mode); TextSetupFunctor functor(this, 0.0f, 0.0f, false, alpha, mode, paint); - const Rect* clip = &mSnapshot->getLocalClip(); + const Rect* clip = &writableSnapshot()->getLocalClip(); Rect bounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f); - const bool hasActiveLayer = hasLayer(); - if (fontRenderer.renderTextOnPath(paint, clip, text, 0, bytesCount, count, path, - hOffset, vOffset, hasActiveLayer ? &bounds : NULL, &functor)) { - if (hasActiveLayer) { - currentTransform()->mapRect(bounds); - dirtyLayerUnchecked(bounds, getRegion()); - } + hOffset, vOffset, hasLayer() ? &bounds : nullptr, &functor)) { + dirtyLayer(bounds.left, bounds.top, bounds.right, bounds.bottom, *currentTransform()); + mDirty = true; } - - return DrawGlInfo::kStatusDrew; } -status_t OpenGLRenderer::drawPath(const SkPath* path, const SkPaint* paint) { - if (currentSnapshot()->isIgnored()) return DrawGlInfo::kStatusDone; +void OpenGLRenderer::drawPath(const SkPath* path, const SkPaint* paint) { + if (mState.currentlyIgnored()) return; - mCaches.activeTexture(0); + mCaches.textureState().activateTexture(0); - const PathTexture* texture = mCaches.pathCache.get(path, paint); - if (!texture) return DrawGlInfo::kStatusDone; + PathTexture* texture = mCaches.pathCache.get(path, paint); + if (!texture) return; const AutoTexture autoCleanup(texture); const float x = texture->left - texture->offset; const float y = texture->top - texture->offset; drawPathTexture(texture, x, y, paint); - - return DrawGlInfo::kStatusDrew; + mDirty = true; } -status_t OpenGLRenderer::drawLayer(Layer* layer, float x, float y) { +void OpenGLRenderer::drawLayer(Layer* layer, float x, float y) { if (!layer) { - return DrawGlInfo::kStatusDone; + return; } - mat4* transform = NULL; + mat4* transform = nullptr; if (layer->isTextureLayer()) { transform = &layer->getTransform(); if (!transform->isIdentity()) { @@ -2903,14 +3133,15 @@ status_t OpenGLRenderer::drawLayer(Layer* layer, float x, float y) { } bool clipRequired = false; - const bool rejected = calculateQuickRejectForScissor(x, y, - x + layer->layer.getWidth(), y + layer->layer.getHeight(), &clipRequired, NULL, false); + const bool rejected = mState.calculateQuickRejectForScissor( + x, y, x + layer->layer.getWidth(), y + layer->layer.getHeight(), + &clipRequired, nullptr, false); if (rejected) { if (transform && !transform->isIdentity()) { restore(); } - return DrawGlInfo::kStatusDone; + return; } EVENT_LOGD("drawLayer," RECT_STRING ", clipRequired %d", x, y, @@ -2918,54 +3149,64 @@ status_t OpenGLRenderer::drawLayer(Layer* layer, float x, float y) { updateLayer(layer, true); - mCaches.setScissorEnabled(mScissorOptimizationDisabled || clipRequired); - mCaches.activeTexture(0); + mRenderState.scissor().setEnabled(mScissorOptimizationDisabled || clipRequired); + mCaches.textureState().activateTexture(0); if (CC_LIKELY(!layer->region.isEmpty())) { if (layer->region.isRect()) { DRAW_DOUBLE_STENCIL_IF(!layer->hasDrawnSinceUpdate, composeLayerRect(layer, layer->regionRect)); } else if (layer->mesh) { - - const float a = getLayerAlpha(layer); - setupDraw(); - setupDrawWithTexture(); - setupDrawColor(a, a, a, a); - setupDrawColorFilter(layer->getColorFilter()); - setupDrawBlending(layer); - setupDrawProgram(); - setupDrawPureColorUniforms(); - setupDrawColorFilterUniforms(layer->getColorFilter()); - setupDrawTexture(layer->getTexture()); - if (CC_LIKELY(currentTransform()->isPureTranslate())) { - int tx = (int) floorf(x + currentTransform()->getTranslateX() + 0.5f); - int ty = (int) floorf(y + currentTransform()->getTranslateY() + 0.5f); - - layer->setFilter(GL_NEAREST); - setupDrawModelView(kModelViewMode_Translate, false, tx, ty, - tx + layer->layer.getWidth(), ty + layer->layer.getHeight(), true); + if (USE_GLOPS) { + Glop glop; + GlopBuilder(mRenderState, mCaches, &glop) + .setMeshTexturedIndexedQuads(layer->mesh, layer->meshElementCount) + .setFillLayer(layer->getTexture(), layer->getColorFilter(), getLayerAlpha(layer), layer->getMode(), Blend::ModeOrderSwap::NoSwap) + .setTransform(currentSnapshot()->getOrthoMatrix(), *currentTransform(), false) + .setModelViewOffsetRectSnap(x, y, Rect(0, 0, layer->layer.getWidth(), layer->layer.getHeight())) + .setRoundRectClipState(currentSnapshot()->roundRectClipState) + .build(); + DRAW_DOUBLE_STENCIL_IF(!layer->hasDrawnSinceUpdate, renderGlop(glop)); } else { - layer->setFilter(GL_LINEAR); - setupDrawModelView(kModelViewMode_Translate, false, x, y, - x + layer->layer.getWidth(), y + layer->layer.getHeight()); - } + const float a = getLayerAlpha(layer); + setupDraw(); + setupDrawWithTexture(); + setupDrawColor(a, a, a, a); + setupDrawColorFilter(layer->getColorFilter()); + setupDrawBlending(layer); + setupDrawProgram(); + setupDrawPureColorUniforms(); + setupDrawColorFilterUniforms(layer->getColorFilter()); + setupDrawTexture(layer->getTextureId()); + if (CC_LIKELY(currentTransform()->isPureTranslate())) { + int tx = (int) floorf(x + currentTransform()->getTranslateX() + 0.5f); + int ty = (int) floorf(y + currentTransform()->getTranslateY() + 0.5f); + + layer->setFilter(GL_NEAREST); + setupDrawModelView(kModelViewMode_Translate, false, tx, ty, + tx + layer->layer.getWidth(), ty + layer->layer.getHeight(), true); + } else { + layer->setFilter(GL_LINEAR); + setupDrawModelView(kModelViewMode_Translate, false, x, y, + x + layer->layer.getWidth(), y + layer->layer.getHeight()); + } - TextureVertex* mesh = &layer->mesh[0]; - GLsizei elementsCount = layer->meshElementCount; + TextureVertex* mesh = &layer->mesh[0]; + GLsizei elementsCount = layer->meshElementCount; - while (elementsCount > 0) { - GLsizei drawCount = min(elementsCount, (GLsizei) gMaxNumberOfQuads * 6); + while (elementsCount > 0) { + GLsizei drawCount = MathUtils::min(elementsCount, (GLsizei) kMaxNumberOfQuads * 6); - setupDrawMeshIndices(&mesh[0].x, &mesh[0].u); - DRAW_DOUBLE_STENCIL_IF(!layer->hasDrawnSinceUpdate, - glDrawElements(GL_TRIANGLES, drawCount, GL_UNSIGNED_SHORT, NULL)); + setupDrawMeshIndices(&mesh[0].x, &mesh[0].u); + DRAW_DOUBLE_STENCIL_IF(!layer->hasDrawnSinceUpdate, + glDrawElements(GL_TRIANGLES, drawCount, GL_UNSIGNED_SHORT, nullptr)); - elementsCount -= drawCount; - // Though there are 4 vertices in a quad, we use 6 indices per - // quad to draw with GL_TRIANGLES - mesh += (drawCount / 6) * 4; + elementsCount -= drawCount; + // Though there are 4 vertices in a quad, we use 6 indices per + // quad to draw with GL_TRIANGLES + mesh += (drawCount / 6) * 4; + } } - #if DEBUG_LAYERS_AS_REGIONS drawRegionRectsDebug(layer->region); #endif @@ -2985,53 +3226,16 @@ status_t OpenGLRenderer::drawLayer(Layer* layer, float x, float y) { restore(); } - return DrawGlInfo::kStatusDrew; + mDirty = true; } /////////////////////////////////////////////////////////////////////////////// // Draw filters /////////////////////////////////////////////////////////////////////////////// - -void OpenGLRenderer::resetPaintFilter() { - // when clearing the PaintFilter, the masks should also be cleared for simple DrawModifier - // comparison, see MergingDrawBatch::canMergeWith - mDrawModifiers.mHasDrawFilter = false; - mDrawModifiers.mPaintFilterClearBits = 0; - mDrawModifiers.mPaintFilterSetBits = 0; -} - -void OpenGLRenderer::setupPaintFilter(int clearBits, int setBits) { - // TODO: don't bother with boolean, it's redundant with clear/set bits - mDrawModifiers.mHasDrawFilter = true; - mDrawModifiers.mPaintFilterClearBits = clearBits & SkPaint::kAllFlags; - mDrawModifiers.mPaintFilterSetBits = setBits & SkPaint::kAllFlags; -} - -const SkPaint* OpenGLRenderer::filterPaint(const SkPaint* paint) { - // TODO: use CompatFlagsDrawFilter here, and combine logic with android/graphics/DrawFilter.cpp - // to avoid clobbering 0x02 paint flag - - // Equivalent to the Java Paint's FILTER_BITMAP_FLAG. - static const uint32_t sFilterBitmapFlag = 0x02; - - if (CC_LIKELY(!mDrawModifiers.mHasDrawFilter || !paint)) { - return paint; - } - - const uint32_t clearBits = mDrawModifiers.mPaintFilterClearBits; - const uint32_t setBits = mDrawModifiers.mPaintFilterSetBits; - - const uint32_t flags = (paint->getFlags() & ~clearBits) | setBits; - mFilteredPaint = *paint; - mFilteredPaint.setFlags(flags); - - // check if paint filter trying to override bitmap filter - if ((clearBits | setBits) & sFilterBitmapFlag) { - mFilteredPaint.setFilterLevel(flags & sFilterBitmapFlag - ? SkPaint::kLow_FilterLevel : SkPaint::kNone_FilterLevel); - } - - return &mFilteredPaint; +void OpenGLRenderer::setDrawFilter(SkDrawFilter* filter) { + // We should never get here since we apply the draw filter when stashing + // the paints in the DisplayList. + LOG_ALWAYS_FATAL("OpenGLRenderer does not directly support DrawFilters"); } /////////////////////////////////////////////////////////////////////////////// @@ -3046,12 +3250,26 @@ Texture* OpenGLRenderer::getTexture(const SkBitmap* bitmap) { return texture; } -void OpenGLRenderer::drawPathTexture(const PathTexture* texture, - float x, float y, const SkPaint* paint) { +void OpenGLRenderer::drawPathTexture(PathTexture* texture, float x, float y, + const SkPaint* paint) { if (quickRejectSetupScissor(x, y, x + texture->width, y + texture->height)) { return; } + if (USE_GLOPS) { + Glop glop; + GlopBuilder(mRenderState, mCaches, &glop) + .setMeshTexturedUnitQuad(nullptr) + .setFillPathTexturePaint(*texture, *paint, currentSnapshot()->alpha) + .setTransform(currentSnapshot()->getOrthoMatrix(), *currentTransform(), false) + .setModelViewMapUnitToRect(Rect(x, y, x + texture->width, y + texture->height)) + .setRoundRectClipState(currentSnapshot()->roundRectClipState) + .build(); + renderGlop(glop); + return; + } + + int alpha; SkXfermode::Mode mode; getAlphaAndMode(paint, &alpha, &mode); @@ -3069,9 +3287,9 @@ void OpenGLRenderer::drawPathTexture(const PathTexture* texture, setupDrawPureColorUniforms(); setupDrawColorFilterUniforms(getColorFilter(paint)); setupDrawShaderUniforms(getShader(paint)); - setupDrawMesh(NULL, (GLvoid*) gMeshTextureOffset); + setupDrawMesh(nullptr, (GLvoid*) kMeshTextureOffset); - glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount); + glDrawArrays(GL_TRIANGLE_STRIP, 0, kUnitQuadCount); } // Same values used by Skia @@ -3124,20 +3342,20 @@ void OpenGLRenderer::drawTextDecorations(float underlineWidth, float x, float y, } } -status_t OpenGLRenderer::drawRects(const float* rects, int count, const SkPaint* paint) { - if (currentSnapshot()->isIgnored()) { - return DrawGlInfo::kStatusDone; +void OpenGLRenderer::drawRects(const float* rects, int count, const SkPaint* paint) { + if (mState.currentlyIgnored()) { + return; } - return drawColorRects(rects, count, paint, false, true, true); + drawColorRects(rects, count, paint, false, true, true); } -status_t OpenGLRenderer::drawShadow(float casterAlpha, +void OpenGLRenderer::drawShadow(float casterAlpha, const VertexBuffer* ambientShadowVertexBuffer, const VertexBuffer* spotShadowVertexBuffer) { - if (currentSnapshot()->isIgnored()) return DrawGlInfo::kStatusDone; + if (mState.currentlyIgnored()) return; // TODO: use quickRejectWithScissor. For now, always force enable scissor. - mCaches.enableScissor(); + mRenderState.scissor().setEnabled(true); SkPaint paint; paint.setAntiAlias(true); // want to use AlphaVertex @@ -3161,19 +3379,13 @@ status_t OpenGLRenderer::drawShadow(float casterAlpha, drawVertexBuffer(*spotShadowVertexBuffer, &paint, kVertexBuffer_ShadowInterp); } - return DrawGlInfo::kStatusDrew; + mDirty=true; } -status_t OpenGLRenderer::drawColorRects(const float* rects, int count, const SkPaint* paint, +void OpenGLRenderer::drawColorRects(const float* rects, int count, const SkPaint* paint, bool ignoreTransform, bool dirty, bool clip) { if (count == 0) { - return DrawGlInfo::kStatusDone; - } - - int color = paint->getColor(); - // If a shader is set, preserve only the alpha - if (getShader(paint)) { - color |= 0x00ffffff; + return; } float left = FLT_MAX; @@ -3202,7 +3414,27 @@ status_t OpenGLRenderer::drawColorRects(const float* rects, int count, const SkP } if (clip && quickRejectSetupScissor(left, top, right, bottom)) { - return DrawGlInfo::kStatusDone; + return; + } + + if (USE_GLOPS) { + const Matrix4& transform = ignoreTransform ? Matrix4::identity() : *currentTransform(); + Glop glop; + GlopBuilder(mRenderState, mCaches, &glop) + .setMeshIndexedQuads(&mesh[0], count / 4) + .setFillPaint(*paint, currentSnapshot()->alpha) + .setTransform(currentSnapshot()->getOrthoMatrix(), transform, false) + .setModelViewOffsetRect(0, 0, Rect(left, top, right, bottom)) + .setRoundRectClipState(currentSnapshot()->roundRectClipState) + .build(); + renderGlop(glop); + return; + } + + int color = paint->getColor(); + // If a shader is set, preserve only the alpha + if (getShader(paint)) { + color |= 0x00ffffff; } setupDraw(); @@ -3225,11 +3457,26 @@ status_t OpenGLRenderer::drawColorRects(const float* rects, int count, const SkP issueIndexedQuadDraw(&mesh[0], count / 4); - return DrawGlInfo::kStatusDrew; + mDirty = true; } void OpenGLRenderer::drawColorRect(float left, float top, float right, float bottom, const SkPaint* paint, bool ignoreTransform) { + + if (USE_GLOPS) { + const Matrix4& transform = ignoreTransform ? Matrix4::identity() : *currentTransform(); + Glop glop; + GlopBuilder(mRenderState, mCaches, &glop) + .setMeshUnitQuad() + .setFillPaint(*paint, currentSnapshot()->alpha) + .setTransform(currentSnapshot()->getOrthoMatrix(), transform, false) + .setModelViewMapUnitToRect(Rect(left, top, right, bottom)) + .setRoundRectClipState(currentSnapshot()->roundRectClipState) + .build(); + renderGlop(glop); + return; + } + int color = paint->getColor(); // If a shader is set, preserve only the alpha if (getShader(paint)) { @@ -3250,15 +3497,14 @@ void OpenGLRenderer::drawColorRect(float left, float top, float right, float bot setupDrawColorFilterUniforms(getColorFilter(paint)); setupDrawSimpleMesh(); - glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount); + glDrawArrays(GL_TRIANGLE_STRIP, 0, kUnitQuadCount); } -void OpenGLRenderer::drawTextureRect(float left, float top, float right, float bottom, - Texture* texture, const SkPaint* paint) { +void OpenGLRenderer::drawTextureRect(Texture* texture, const SkPaint* paint) { texture->setWrap(GL_CLAMP_TO_EDGE, true); - GLvoid* vertices = (GLvoid*) NULL; - GLvoid* texCoords = (GLvoid*) gMeshTextureOffset; + GLvoid* vertices = (GLvoid*) nullptr; + GLvoid* texCoords = (GLvoid*) kMeshTextureOffset; if (texture->uvMapper) { vertices = &mMeshVertices[0].x; @@ -3271,17 +3517,17 @@ void OpenGLRenderer::drawTextureRect(float left, float top, float right, float b } if (CC_LIKELY(currentTransform()->isPureTranslate())) { - const float x = (int) floorf(left + currentTransform()->getTranslateX() + 0.5f); - const float y = (int) floorf(top + currentTransform()->getTranslateY() + 0.5f); + const float x = floorf(currentTransform()->getTranslateX() + 0.5f); + const float y = floorf(currentTransform()->getTranslateY() + 0.5f); texture->setFilter(GL_NEAREST, true); drawTextureMesh(x, y, x + texture->width, y + texture->height, texture->id, paint, texture->blend, vertices, texCoords, - GL_TRIANGLE_STRIP, gMeshCount, false, true); + GL_TRIANGLE_STRIP, kUnitQuadCount, false, true); } else { - texture->setFilter(getFilter(paint), true); - drawTextureMesh(left, top, right, bottom, texture->id, paint, - texture->blend, vertices, texCoords, GL_TRIANGLE_STRIP, gMeshCount); + texture->setFilter(PaintUtils::getFilter(paint), true); + drawTextureMesh(0, 0, texture->width, texture->height, texture->id, paint, + texture->blend, vertices, texCoords, GL_TRIANGLE_STRIP, kUnitQuadCount); } if (texture->uvMapper) { @@ -3340,7 +3586,7 @@ void OpenGLRenderer::drawIndexedTextureMesh(float left, float top, float right, setupDrawColorFilterUniforms(getColorFilter(paint)); setupDrawMeshIndices(vertices, texCoords, vbo); - glDrawElements(drawMode, elementsCount, GL_UNSIGNED_SHORT, NULL); + glDrawElements(drawMode, elementsCount, GL_UNSIGNED_SHORT, nullptr); } void OpenGLRenderer::drawAlpha8TextureMesh(float left, float top, float right, float bottom, @@ -3348,14 +3594,14 @@ void OpenGLRenderer::drawAlpha8TextureMesh(float left, float top, float right, f GLvoid* vertices, GLvoid* texCoords, GLenum drawMode, GLsizei elementsCount, bool ignoreTransform, ModelViewMode modelViewMode, bool dirty) { - int color = paint != NULL ? paint->getColor() : 0; + int color = paint != nullptr ? paint->getColor() : 0; int alpha; SkXfermode::Mode mode; getAlphaAndMode(paint, &alpha, &mode); setupDraw(); setupDrawWithTexture(true); - if (paint != NULL) { + if (paint != nullptr) { setupDrawAlpha8Color(color, alpha); } setupDrawColorFilter(getColorFilter(paint)); @@ -3376,7 +3622,7 @@ void OpenGLRenderer::drawAlpha8TextureMesh(float left, float top, float right, f void OpenGLRenderer::chooseBlending(bool blend, SkXfermode::Mode mode, ProgramDescription& description, bool swapSrcDst) { - if (mSnapshot->roundRectClipState != NULL /*&& !mSkipOutlineClip*/) { + if (currentSnapshot()->roundRectClipState != nullptr /*&& !mSkipOutlineClip*/) { blend = true; mDescription.hasRoundRectClip = true; } @@ -3391,47 +3637,21 @@ void OpenGLRenderer::chooseBlending(bool blend, SkXfermode::Mode mode, // If the blend mode cannot be implemented using shaders, fall // back to the default SrcOver blend mode instead if (CC_UNLIKELY(mode > SkXfermode::kScreen_Mode)) { - if (CC_UNLIKELY(mExtensions.hasFramebufferFetch())) { + if (CC_UNLIKELY(mCaches.extensions().hasFramebufferFetch())) { description.framebufferMode = mode; description.swapSrcDst = swapSrcDst; - if (mCaches.blend) { - glDisable(GL_BLEND); - mCaches.blend = false; - } - + mRenderState.blend().disable(); return; } else { mode = SkXfermode::kSrcOver_Mode; } } - - if (!mCaches.blend) { - glEnable(GL_BLEND); - } - - GLenum sourceMode = swapSrcDst ? gBlendsSwap[mode].src : gBlends[mode].src; - GLenum destMode = swapSrcDst ? gBlendsSwap[mode].dst : gBlends[mode].dst; - - if (sourceMode != mCaches.lastSrcMode || destMode != mCaches.lastDstMode) { - glBlendFunc(sourceMode, destMode); - mCaches.lastSrcMode = sourceMode; - mCaches.lastDstMode = destMode; - } - } else if (mCaches.blend) { - glDisable(GL_BLEND); - } - mCaches.blend = blend; -} - -bool OpenGLRenderer::useProgram(Program* program) { - if (!program->isInUse()) { - if (mCaches.currentProgram != NULL) mCaches.currentProgram->remove(); - program->use(); - mCaches.currentProgram = program; - return false; + mRenderState.blend().enable(mode, + swapSrcDst ? Blend::ModeOrderSwap::Swap : Blend::ModeOrderSwap::NoSwap); + } else { + mRenderState.blend().disable(); } - return true; } void OpenGLRenderer::resetDrawTextureTexCoords(float u1, float v1, float u2, float v2) { @@ -3442,7 +3662,8 @@ void OpenGLRenderer::resetDrawTextureTexCoords(float u1, float v1, float u2, flo TextureVertex::setUV(v++, u2, v2); } -void OpenGLRenderer::getAlphaAndMode(const SkPaint* paint, int* alpha, SkXfermode::Mode* mode) const { +void OpenGLRenderer::getAlphaAndMode(const SkPaint* paint, int* alpha, + SkXfermode::Mode* mode) const { getAlphaAndModeDirect(paint, alpha, mode); if (mDrawModifiers.mOverrideLayerAlpha < 1.0f) { // if drawing a layer, ignore the paint's alpha |
