summaryrefslogtreecommitdiffstats
path: root/libs/hwui/OpenGLRenderer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libs/hwui/OpenGLRenderer.cpp')
-rw-r--r--[-rwxr-xr-x]libs/hwui/OpenGLRenderer.cpp2001
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