diff options
| -rw-r--r-- | libs/hwui/Android.mk | 1 | ||||
| -rw-r--r-- | libs/hwui/DisplayListRenderer.cpp | 29 | ||||
| -rw-r--r-- | libs/hwui/DisplayListRenderer.h | 69 | ||||
| -rw-r--r-- | libs/hwui/FontRenderer.h | 2 | ||||
| -rw-r--r-- | libs/hwui/LayerRenderer.cpp | 2 | ||||
| -rw-r--r-- | libs/hwui/LayerRenderer.h | 2 | ||||
| -rw-r--r-- | libs/hwui/OpenGLRenderer.cpp | 285 | ||||
| -rw-r--r-- | libs/hwui/OpenGLRenderer.h | 78 | ||||
| -rw-r--r-- | libs/hwui/Renderer.h | 21 | ||||
| -rw-r--r-- | libs/hwui/StatefulBaseRenderer.cpp | 206 | ||||
| -rw-r--r-- | libs/hwui/StatefulBaseRenderer.h | 137 | 
11 files changed, 492 insertions, 340 deletions
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk index 962d72675e17..9d3123214fba 100644 --- a/libs/hwui/Android.mk +++ b/libs/hwui/Android.mk @@ -42,6 +42,7 @@ ifeq ($(USE_OPENGL_RENDERER),true)  		SkiaColorFilter.cpp \  		SkiaShader.cpp \  		Snapshot.cpp \ +		StatefulBaseRenderer.cpp \  		Stencil.cpp \  		Texture.cpp \  		TextureCache.cpp \ diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp index 31a7db6461c6..9c5db6e3800d 100644 --- a/libs/hwui/DisplayListRenderer.cpp +++ b/libs/hwui/DisplayListRenderer.cpp @@ -120,19 +120,14 @@ void DisplayListRenderer::setViewport(int width, int height) {      // TODO: DisplayListRenderer shouldn't have a projection matrix, as it should never be used      mViewProjMatrix.loadOrtho(0, width, height, 0, -1, 1); -    mWidth = width; -    mHeight = height; +    initializeViewport(width, height);  }  status_t DisplayListRenderer::prepareDirty(float left, float top,          float right, float bottom, bool opaque) { -    mSnapshot = new Snapshot(mFirstSnapshot, -            SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag); -    mSaveCount = 1; +    initializeSaveStack(0, 0, getWidth(), getHeight()); -    mSnapshot->setClip(0.0f, 0.0f, mWidth, mHeight);      mDirtyClip = opaque; -      mRestoreSaveCount = -1;      return DrawGlInfo::kStatusDone; // No invalidate needed at record-time @@ -158,7 +153,7 @@ status_t DisplayListRenderer::callDrawGLFunction(Functor *functor, Rect& dirty)  int DisplayListRenderer::save(int flags) {      addStateOp(new (alloc()) SaveOp(flags)); -    return OpenGLRenderer::save(flags); +    return StatefulBaseRenderer::save(flags);  }  void DisplayListRenderer::restore() { @@ -169,19 +164,19 @@ void DisplayListRenderer::restore() {      mRestoreSaveCount--;      insertTranslate(); -    OpenGLRenderer::restore(); +    StatefulBaseRenderer::restore();  }  void DisplayListRenderer::restoreToCount(int saveCount) {      mRestoreSaveCount = saveCount;      insertTranslate(); -    OpenGLRenderer::restoreToCount(saveCount); +    StatefulBaseRenderer::restoreToCount(saveCount);  }  int DisplayListRenderer::saveLayer(float left, float top, float right, float bottom,          int alpha, SkXfermode::Mode mode, int flags) {      addStateOp(new (alloc()) SaveLayerOp(left, top, right, bottom, alpha, mode, flags)); -    return OpenGLRenderer::save(flags); +    return StatefulBaseRenderer::save(flags);  }  void DisplayListRenderer::translate(float dx, float dy, float dz) { @@ -190,34 +185,34 @@ void DisplayListRenderer::translate(float dx, float dy, float dz) {      mTranslateX += dx;      mTranslateY += dy;      insertRestoreToCount(); -    OpenGLRenderer::translate(dx, dy, dz); +    StatefulBaseRenderer::translate(dx, dy, dz);  }  void DisplayListRenderer::rotate(float degrees) {      addStateOp(new (alloc()) RotateOp(degrees)); -    OpenGLRenderer::rotate(degrees); +    StatefulBaseRenderer::rotate(degrees);  }  void DisplayListRenderer::scale(float sx, float sy) {      addStateOp(new (alloc()) ScaleOp(sx, sy)); -    OpenGLRenderer::scale(sx, sy); +    StatefulBaseRenderer::scale(sx, sy);  }  void DisplayListRenderer::skew(float sx, float sy) {      addStateOp(new (alloc()) SkewOp(sx, sy)); -    OpenGLRenderer::skew(sx, sy); +    StatefulBaseRenderer::skew(sx, sy);  }  void DisplayListRenderer::setMatrix(SkMatrix* matrix) {      matrix = refMatrix(matrix);      addStateOp(new (alloc()) SetMatrixOp(matrix)); -    OpenGLRenderer::setMatrix(matrix); +    StatefulBaseRenderer::setMatrix(matrix);  }  void DisplayListRenderer::concatMatrix(SkMatrix* matrix) {      matrix = refMatrix(matrix);      addStateOp(new (alloc()) ConcatMatrixOp(matrix)); -    OpenGLRenderer::concatMatrix(matrix); +    StatefulBaseRenderer::concatMatrix(matrix);  }  bool DisplayListRenderer::clipRect(float left, float top, float right, float bottom, diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h index b6244e43fe4b..b5d9924c8601 100644 --- a/libs/hwui/DisplayListRenderer.h +++ b/libs/hwui/DisplayListRenderer.h @@ -65,22 +65,26 @@ public:      virtual bool isRecording() { return true; } +// ---------------------------------------------------------------------------- +// Frame state operations +// ----------------------------------------------------------------------------      virtual void setViewport(int width, int height);      virtual status_t prepareDirty(float left, float top, float right, float bottom, bool opaque);      virtual void finish(); - -    virtual status_t callDrawGLFunction(Functor *functor, Rect& dirty); -      virtual void interrupt();      virtual void resume(); +// ---------------------------------------------------------------------------- +// Canvas state operations +// ---------------------------------------------------------------------------- +    // Save (layer)      virtual int save(int flags);      virtual void restore();      virtual void restoreToCount(int saveCount); -      virtual int saveLayer(float left, float top, float right, float bottom,              int alpha, SkXfermode::Mode mode, int flags); +    // Matrix      virtual void translate(float dx, float dy, float dz);      virtual void rotate(float degrees);      virtual void scale(float sx, float sy); @@ -89,12 +93,30 @@ public:      virtual void setMatrix(SkMatrix* matrix);      virtual void concatMatrix(SkMatrix* matrix); +    // Clip      virtual bool clipRect(float left, float top, float right, float bottom, SkRegion::Op op);      virtual bool clipPath(SkPath* path, SkRegion::Op op);      virtual bool clipRegion(SkRegion* region, SkRegion::Op op); -    virtual status_t drawDisplayList(DisplayList* displayList, Rect& dirty, int32_t flags); -    virtual status_t drawLayer(Layer* layer, float x, float y); +    // Misc - should be implemented with SkPaint inspection +    virtual void resetShader(); +    virtual void setupShader(SkiaShader* shader); + +    virtual void resetColorFilter(); +    virtual void setupColorFilter(SkiaColorFilter* filter); + +    virtual void resetShadow(); +    virtual void setupShadow(float radius, float dx, float dy, int color); + +    virtual void resetPaintFilter(); +    virtual void setupPaintFilter(int clearBits, int setBits); + +// ---------------------------------------------------------------------------- +// Canvas draw operations +// ---------------------------------------------------------------------------- +    virtual status_t drawColor(int color, SkXfermode::Mode mode); + +    // Bitmap-based      virtual status_t drawBitmap(SkBitmap* bitmap, float left, float top, SkPaint* paint);      virtual status_t drawBitmap(SkBitmap* bitmap, SkMatrix* matrix, SkPaint* paint);      virtual status_t drawBitmap(SkBitmap* bitmap, float srcLeft, float srcTop, @@ -105,8 +127,10 @@ public:              float* vertices, int* colors, SkPaint* paint);      virtual status_t drawPatch(SkBitmap* bitmap, Res_png_9patch* patch,              float left, float top, float right, float bottom, SkPaint* paint); -    virtual status_t drawColor(int color, SkXfermode::Mode mode); + +    // Shapes      virtual status_t drawRect(float left, float top, float right, float bottom, SkPaint* paint); +    virtual status_t drawRects(const float* rects, int count, SkPaint* paint);      virtual status_t drawRoundRect(float left, float top, float right, float bottom,              float rx, float ry, SkPaint* paint);      virtual status_t drawCircle(float x, float y, float radius, SkPaint* paint); @@ -116,28 +140,29 @@ public:      virtual status_t drawPath(SkPath* path, SkPaint* paint);      virtual status_t drawLines(float* points, int count, SkPaint* paint);      virtual status_t drawPoints(float* points, int count, SkPaint* paint); + +    // Text +    virtual status_t drawText(const char* text, int bytesCount, int count, float x, float y, +            const float* positions, SkPaint* paint, float totalAdvance, const Rect& bounds, +            DrawOpMode drawOpMode = kDrawOpMode_Immediate);      virtual status_t drawTextOnPath(const char* text, int bytesCount, int count, SkPath* path,              float hOffset, float vOffset, SkPaint* paint);      virtual status_t drawPosText(const char* text, int bytesCount, int count,              const float* positions, SkPaint* paint); -    virtual status_t drawText(const char* text, int bytesCount, int count, float x, float y, -            const float* positions, SkPaint* paint, float totalAdvance, const Rect& bounds, -            DrawOpMode drawOpMode); - -    virtual status_t drawRects(const float* rects, int count, SkPaint* paint); -    virtual void resetShader(); -    virtual void setupShader(SkiaShader* shader); - -    virtual void resetColorFilter(); -    virtual void setupColorFilter(SkiaColorFilter* filter); - -    virtual void resetShadow(); -    virtual void setupShadow(float radius, float dx, float dy, int color); +// ---------------------------------------------------------------------------- +// Canvas draw operations - special +// ---------------------------------------------------------------------------- +    virtual status_t drawLayer(Layer* layer, float x, float y); +    virtual status_t drawDisplayList(DisplayList* displayList, Rect& dirty, +            int32_t replayFlags); -    virtual void resetPaintFilter(); -    virtual void setupPaintFilter(int clearBits, int setBits); +    // TODO: rename for consistency +    virtual status_t callDrawGLFunction(Functor* functor, Rect& dirty); +// ---------------------------------------------------------------------------- +// DisplayList / resource management +// ----------------------------------------------------------------------------      ANDROID_API void reset();      sp<DisplayListData> getDisplayListData() const { diff --git a/libs/hwui/FontRenderer.h b/libs/hwui/FontRenderer.h index aa7e776c44ad..db4e02093678 100644 --- a/libs/hwui/FontRenderer.h +++ b/libs/hwui/FontRenderer.h @@ -44,8 +44,6 @@ namespace RSC {  }  #endif -class Functor; -  namespace android {  namespace uirenderer { diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp index f8076cc414d0..35fd46ee7662 100644 --- a/libs/hwui/LayerRenderer.cpp +++ b/libs/hwui/LayerRenderer.cpp @@ -92,7 +92,7 @@ void LayerRenderer::finish() {      // who will invoke OpenGLRenderer::resume()  } -GLint LayerRenderer::getTargetFbo() const { +GLuint LayerRenderer::getTargetFbo() const {      return mLayer->getFbo();  } diff --git a/libs/hwui/LayerRenderer.h b/libs/hwui/LayerRenderer.h index 5f867317ecf6..f24c8d4a1f83 100644 --- a/libs/hwui/LayerRenderer.h +++ b/libs/hwui/LayerRenderer.h @@ -67,7 +67,7 @@ protected:      virtual void ensureStencilBuffer();      virtual bool hasLayer() const;      virtual Region* getRegion() const; -    virtual GLint getTargetFbo() const; +    virtual GLuint getTargetFbo() const;      virtual bool suppressErrorChecks() const;  private: diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp index c30d86fbd773..a3a443200c41 100644 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -129,7 +129,6 @@ OpenGLRenderer::OpenGLRenderer():      memcpy(mMeshVertices, gMeshVertices, sizeof(gMeshVertices)); -    mFirstSnapshot = new Snapshot;      mFrameStarted = false;      mCountOverdraw = false; @@ -182,24 +181,15 @@ void OpenGLRenderer::initViewport(int width, int height) {          mViewProjMatrix.loadOrtho(0, width, height, 0, -1, 1);      } -    mWidth = width; -    mHeight = height; - -    mFirstSnapshot->height = height; -    mFirstSnapshot->viewport.set(0, 0, width, height); +    initializeViewport(width, height);  }  void OpenGLRenderer::setupFrameState(float left, float top,          float right, float bottom, bool opaque) {      mCaches.clearGarbage(); +    initializeSaveStack(left, top, right, bottom);      mOpaque = opaque; -    mSnapshot = new Snapshot(mFirstSnapshot, -            SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag); -    mSnapshot->fbo = getTargetFbo(); -    mSaveCount = 1; - -    mSnapshot->setClip(left, top, right, bottom);      mTilingClip.set(left, top, right, bottom);  } @@ -211,14 +201,14 @@ status_t OpenGLRenderer::startFrame() {      discardFramebuffer(mTilingClip.left, mTilingClip.top, mTilingClip.right, mTilingClip.bottom); -    glViewport(0, 0, mWidth, mHeight); +    glViewport(0, 0, getWidth(), getHeight());      // Functors break the tiling extension in pretty spectacular ways      // This ensures we don't use tiling when a functor is going to be      // invoked during the frame      mSuppressTiling = mCaches.hasRegisteredFunctors(); -    startTiling(mSnapshot, true); +    startTiling(*mSnapshot, true);      debugOverdraw(true, true); @@ -226,10 +216,6 @@ status_t OpenGLRenderer::startFrame() {              mTilingClip.right, mTilingClip.bottom, mOpaque);  } -status_t OpenGLRenderer::prepare(bool opaque) { -    return prepareDirty(0.0f, 0.0f, mWidth, mHeight, opaque); -} -  status_t OpenGLRenderer::prepareDirty(float left, float top,          float right, float bottom, bool opaque) { @@ -239,7 +225,7 @@ status_t OpenGLRenderer::prepareDirty(float left, float top,      // The framebuffer renderer will first defer the display list      // for each layer and wait until the first drawing command      // to start the frame -    if (mSnapshot->fbo == 0) { +    if (currentSnapshot().fbo == 0) {          syncState();          updateLayers();      } else { @@ -254,7 +240,7 @@ void OpenGLRenderer::discardFramebuffer(float left, float top, float right, floa      // 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 >= mWidth && bottom >= mHeight) { +            left <= 0.0f && top <= 0.0f && right >= getWidth() && bottom >= getHeight()) {          const bool isFbo = getTargetFbo() == 0;          const GLenum attachments[] = {                  isFbo ? (const GLenum) GL_COLOR_EXT : (const GLenum) GL_COLOR_ATTACHMENT0, @@ -266,7 +252,7 @@ void OpenGLRenderer::discardFramebuffer(float left, float top, float right, floa  status_t OpenGLRenderer::clear(float left, float top, float right, float bottom, bool opaque) {      if (!opaque || mCountOverdraw) {          mCaches.enableScissor(); -        mCaches.setScissor(left, mSnapshot->height - bottom, right - left, bottom - top); +        mCaches.setScissor(left, currentSnapshot().height - bottom, right - left, bottom - top);          glClear(GL_COLOR_BUFFER_BIT);          return DrawGlInfo::kStatusDrew;      } @@ -283,14 +269,14 @@ void OpenGLRenderer::syncState() {      }  } -void OpenGLRenderer::startTiling(const sp<Snapshot>& s, bool opaque) { +void OpenGLRenderer::startTiling(const Snapshot& s, bool opaque) {      if (!mSuppressTiling) { -        Rect* clip = &mTilingClip; -        if (s->flags & Snapshot::kFlagFboTarget) { -            clip = &(s->layer->clipRect); +        const Rect* clip = &mTilingClip; +        if (s.flags & Snapshot::kFlagFboTarget) { +            clip = &(s.layer->clipRect);          } -        startTiling(*clip, s->height, opaque); +        startTiling(*clip, s.height, opaque);      }  } @@ -369,9 +355,9 @@ void OpenGLRenderer::interrupt() {  }  void OpenGLRenderer::resume() { -    sp<Snapshot> snapshot = (mSnapshot != NULL) ? mSnapshot : mFirstSnapshot; -    glViewport(0, 0, snapshot->viewport.getWidth(), snapshot->viewport.getHeight()); -    glBindFramebuffer(GL_FRAMEBUFFER, snapshot->fbo); +    const Snapshot& snapshot = currentSnapshot(); +    glViewport(0, 0, snapshot.viewport.getWidth(), snapshot.viewport.getHeight()); +    glBindFramebuffer(GL_FRAMEBUFFER, snapshot.fbo);      debugOverdraw(true, false);      glClearColor(0.0f, 0.0f, 0.0f, 0.0f); @@ -391,9 +377,9 @@ void OpenGLRenderer::resume() {  }  void OpenGLRenderer::resumeAfterLayer() { -    sp<Snapshot> snapshot = (mSnapshot != NULL) ? mSnapshot : mFirstSnapshot; -    glViewport(0, 0, snapshot->viewport.getWidth(), snapshot->viewport.getHeight()); -    glBindFramebuffer(GL_FRAMEBUFFER, snapshot->fbo); +    const Snapshot& snapshot = currentSnapshot(); +    glViewport(0, 0, snapshot.viewport.getWidth(), snapshot.viewport.getHeight()); +    glBindFramebuffer(GL_FRAMEBUFFER, snapshot.fbo);      debugOverdraw(true, false);      mCaches.resetScissor(); @@ -447,12 +433,12 @@ status_t OpenGLRenderer::invokeFunctors(Rect& dirty) {  }  status_t OpenGLRenderer::callDrawGLFunction(Functor* functor, Rect& dirty) { -    if (mSnapshot->isIgnored()) return DrawGlInfo::kStatusDone; +    if (currentSnapshot().isIgnored()) return DrawGlInfo::kStatusDone;      detachFunctor(functor); -    Rect clip(*mSnapshot->clipRect); +    Rect clip(currentClipRect());      clip.snapToPixelBoundaries();      // Since we don't know what the functor will draw, let's dirty @@ -556,9 +542,9 @@ void OpenGLRenderer::renderOverdraw() {  }  void OpenGLRenderer::countOverdraw() { -    size_t count = mWidth * mHeight; +    size_t count = getWidth() * getHeight();      uint32_t* buffer = new uint32_t[count]; -    glReadPixels(0, 0, mWidth, mHeight, GL_RGBA, GL_UNSIGNED_BYTE, &buffer[0]); +    glReadPixels(0, 0, getWidth(), getHeight(), GL_RGBA, GL_UNSIGNED_BYTE, &buffer[0]);      size_t total = 0;      for (size_t i = 0; i < count; i++) { @@ -594,7 +580,7 @@ bool OpenGLRenderer::updateLayer(Layer* layer, bool inFrame) {          if (inFrame) {              resumeAfterLayer(); -            startTiling(mSnapshot); +            startTiling(*mSnapshot);          }          layer->debugDrawUpdate = mCaches.debugLayersUpdates; @@ -715,50 +701,17 @@ void OpenGLRenderer::flushLayerUpdates() {  // State management  /////////////////////////////////////////////////////////////////////////////// -int OpenGLRenderer::getSaveCount() const { -    return mSaveCount; -} - -int OpenGLRenderer::save(int flags) { -    return saveSnapshot(flags); -} - -void OpenGLRenderer::restore() { -    if (mSaveCount > 1) { -        restoreSnapshot(); -    } -} - -void OpenGLRenderer::restoreToCount(int saveCount) { -    if (saveCount < 1) saveCount = 1; - -    while (mSaveCount > saveCount) { -        restoreSnapshot(); -    } -} - -int OpenGLRenderer::saveSnapshot(int flags) { -    mSnapshot = new Snapshot(mSnapshot, flags); -    return mSaveCount++; -} - -bool OpenGLRenderer::restoreSnapshot() { -    bool restoreClip = mSnapshot->flags & Snapshot::kFlagClipSet; -    bool restoreLayer = mSnapshot->flags & Snapshot::kFlagIsLayer; -    bool restoreOrtho = mSnapshot->flags & Snapshot::kFlagDirtyOrtho; - -    sp<Snapshot> current = mSnapshot; -    sp<Snapshot> previous = mSnapshot->previous; +void OpenGLRenderer::onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) { +    bool restoreOrtho = removed.flags & Snapshot::kFlagDirtyOrtho; +    bool restoreClip = removed.flags & Snapshot::kFlagClipSet; +    bool restoreLayer = removed.flags & Snapshot::kFlagIsLayer;      if (restoreOrtho) { -        Rect& r = previous->viewport; +        const Rect& r = restored.viewport;          glViewport(r.left, r.top, r.right, r.bottom); -        mViewProjMatrix.load(current->orthoMatrix); +        mViewProjMatrix.load(removed.orthoMatrix); // todo: should ortho be stored in 'restored'?      } -    mSaveCount--; -    mSnapshot = previous; -      if (restoreClip) {          dirtyClip();      } @@ -766,11 +719,9 @@ bool OpenGLRenderer::restoreSnapshot() {      if (restoreLayer) {          endMark(); // Savelayer          startMark("ComposeLayer"); -        composeLayer(current, previous); +        composeLayer(removed, restored);          endMark();      } - -    return restoreClip;  }  /////////////////////////////////////////////////////////////////////////////// @@ -781,7 +732,7 @@ int OpenGLRenderer::saveLayer(float left, float top, float right, float bottom,          int alpha, SkXfermode::Mode mode, int flags) {      const int count = saveSnapshot(flags); -    if (!mSnapshot->isIgnored()) { +    if (!currentSnapshot().isIgnored()) {          createLayer(left, top, right, bottom, alpha, mode, flags);      } @@ -794,14 +745,14 @@ 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(*mSnapshot->clipRect)) { +    if (bounds.intersect(currentClipRect())) {          // We cannot work with sub-pixels in this case          bounds.snapToPixelBoundaries();          // When the layer is not an FBO, we may use glCopyTexImage so we          // need to make sure the layer does not extend outside the bounds          // of the framebuffer -        if (!bounds.intersect(mSnapshot->previous->viewport)) { +        if (!bounds.intersect(currentSnapshot().previous->viewport)) {              bounds.setEmpty();          } else if (fboLayer) {              clip.set(bounds); @@ -836,7 +787,7 @@ int OpenGLRenderer::saveLayerDeferred(float left, float top, float right, float          int alpha, SkXfermode::Mode mode, int flags) {      const int count = saveSnapshot(flags); -    if (!mSnapshot->isIgnored() && (flags & SkCanvas::kClipToLayer_SaveFlag)) { +    if (!currentSnapshot().isIgnored() && (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) @@ -846,7 +797,7 @@ int OpenGLRenderer::saveLayerDeferred(float left, float top, float right, float          calculateLayerBoundsAndClip(bounds, clip, true);          updateSnapshotIgnoreForLayer(bounds, clip, true, alpha); -        if (!mSnapshot->isIgnored()) { +        if (!currentSnapshot().isIgnored()) {              mSnapshot->resetTransform(-bounds.left, -bounds.top, 0.0f);              mSnapshot->resetClip(clip.left, clip.top, clip.right, clip.bottom);              mSnapshot->viewport.set(0.0f, 0.0f, bounds.getWidth(), bounds.getHeight()); @@ -922,7 +873,7 @@ bool OpenGLRenderer::createLayer(float left, float top, float right, float botto      updateSnapshotIgnoreForLayer(bounds, clip, fboLayer, alpha);      // Bail out if we won't draw in this snapshot -    if (mSnapshot->isIgnored()) { +    if (currentSnapshot().isIgnored()) {          return false;      } @@ -1001,7 +952,7 @@ bool OpenGLRenderer::createFboLayer(Layer* layer, Rect& bounds, Rect& clip) {      glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,              layer->getTexture(), 0); -    startTiling(mSnapshot, true); +    startTiling(*mSnapshot, true);      // Clear the FBO, expand the clear region by 1 to get nice bilinear filtering      mCaches.enableScissor(); @@ -1023,15 +974,15 @@ bool OpenGLRenderer::createFboLayer(Layer* layer, Rect& bounds, Rect& clip) {  /**   * Read the documentation of createLayer() before doing anything in this method.   */ -void OpenGLRenderer::composeLayer(sp<Snapshot> current, sp<Snapshot> previous) { -    if (!current->layer) { +void OpenGLRenderer::composeLayer(const Snapshot& removed, const Snapshot& restored) { +    if (!removed.layer) {          ALOGE("Attempting to compose a layer that does not exist");          return;      } -    Layer* layer = current->layer; +    Layer* layer = removed.layer;      const Rect& rect = layer->layer; -    const bool fboLayer = current->flags & Snapshot::kFlagIsFboLayer; +    const bool fboLayer = removed.flags & Snapshot::kFlagIsFboLayer;      bool clipRequired = false;      calculateQuickRejectForScissor(rect.left, rect.top, rect.right, rect.bottom, @@ -1047,10 +998,10 @@ void OpenGLRenderer::composeLayer(sp<Snapshot> current, sp<Snapshot> previous) {          layer->removeFbo(false);          // Unbind current FBO and restore previous one -        glBindFramebuffer(GL_FRAMEBUFFER, previous->fbo); +        glBindFramebuffer(GL_FRAMEBUFFER, restored.fbo);          debugOverdraw(true, false); -        startTiling(previous); +        startTiling(restored);      }      if (!fboLayer && layer->getAlpha() < 255) { @@ -1067,7 +1018,7 @@ void OpenGLRenderer::composeLayer(sp<Snapshot> current, sp<Snapshot> previous) {      // When the layer is stored in an FBO, we can save a bit of fillrate by      // drawing only the dirty region      if (fboLayer) { -        dirtyLayer(rect.left, rect.top, rect.right, rect.bottom, *previous->transform); +        dirtyLayer(rect.left, rect.top, rect.right, rect.bottom, *restored.transform);          if (layer->getColorFilter()) {              setupColorFilter(layer->getColorFilter());          } @@ -1347,7 +1298,7 @@ void OpenGLRenderer::dirtyLayer(const float left, const float top,  }  void OpenGLRenderer::dirtyLayerUnchecked(Rect& bounds, Region* region) { -    if (bounds.intersect(*mSnapshot->clipRect)) { +    if (bounds.intersect(currentClipRect())) {          bounds.snapToPixelBoundaries();          android::Rect dirty(bounds.left, bounds.top, bounds.right, bounds.bottom);          if (!dirty.isEmpty()) { @@ -1375,7 +1326,7 @@ void OpenGLRenderer::clearLayerRegions() {      const size_t count = mLayers.size();      if (count == 0) return; -    if (!mSnapshot->isIgnored()) { +    if (!currentSnapshot().isIgnored()) {          // Doing several glScissor/glClear here can negatively impact          // GPUs with a tiler architecture, instead we draw quads with          // the Clear blending mode @@ -1427,8 +1378,8 @@ void OpenGLRenderer::clearLayerRegions() {  ///////////////////////////////////////////////////////////////////////////////  bool OpenGLRenderer::storeDisplayState(DeferredDisplayState& state, int stateDeferFlags) { -    const Rect& currentClip = *(mSnapshot->clipRect); -    const mat4& currentMatrix = *(mSnapshot->transform); +    const Rect& currentClip = currentClipRect(); +    const mat4& currentMatrix = currentTransform();      if (stateDeferFlags & kStateDeferFlag_Draw) {          // state has bounds initialized in local coordinates @@ -1471,14 +1422,14 @@ bool OpenGLRenderer::storeDisplayState(DeferredDisplayState& state, int stateDef      // (Note: saveLayer/restore use colorFilter and alpha, so we just save restore everything)      state.mMatrix.load(currentMatrix);      state.mDrawModifiers = mDrawModifiers; -    state.mAlpha = mSnapshot->alpha; +    state.mAlpha = currentSnapshot().alpha;      return false;  }  void OpenGLRenderer::restoreDisplayState(const DeferredDisplayState& state, bool skipClipRestore) { -    currentTransform().load(state.mMatrix); -    mDrawModifiers = state.mDrawModifiers; +    setMatrix(state.mMatrix);      mSnapshot->alpha = state.mAlpha; +    mDrawModifiers = state.mDrawModifiers;      if (state.mClipValid && !skipClipRestore) {          mSnapshot->setClip(state.mClip.left, state.mClip.top, @@ -1498,62 +1449,21 @@ void OpenGLRenderer::setupMergedMultiDraw(const Rect* clipRect) {      if (clipRect != NULL) {          mSnapshot->setClip(clipRect->left, clipRect->top, clipRect->right, clipRect->bottom);      } else { -        mSnapshot->setClip(0, 0, mWidth, mHeight); +        mSnapshot->setClip(0, 0, getWidth(), getHeight());      }      dirtyClip();      mCaches.setScissorEnabled(clipRect != NULL || mScissorOptimizationDisabled);  }  /////////////////////////////////////////////////////////////////////////////// -// Transforms -/////////////////////////////////////////////////////////////////////////////// - -void OpenGLRenderer::translate(float dx, float dy, float dz) { -    currentTransform().translate(dx, dy, dz); -} - -void OpenGLRenderer::rotate(float degrees) { -    currentTransform().rotate(degrees, 0.0f, 0.0f, 1.0f); -} - -void OpenGLRenderer::scale(float sx, float sy) { -    currentTransform().scale(sx, sy, 1.0f); -} - -void OpenGLRenderer::skew(float sx, float sy) { -    currentTransform().skew(sx, sy); -} - -void OpenGLRenderer::setMatrix(SkMatrix* matrix) { -    if (matrix) { -        currentTransform().load(*matrix); -    } else { -        currentTransform().loadIdentity(); -    } -} - -bool OpenGLRenderer::hasRectToRectTransform() { -    return CC_LIKELY(currentTransform().rectToRect()); -} - -void OpenGLRenderer::getMatrix(SkMatrix* matrix) const { -    currentTransform().copyTo(*matrix); -} - -void OpenGLRenderer::concatMatrix(SkMatrix* matrix) { -    mat4 transform(*matrix); -    currentTransform().multiply(transform); -} - -///////////////////////////////////////////////////////////////////////////////  // Clipping  ///////////////////////////////////////////////////////////////////////////////  void OpenGLRenderer::setScissorFromClip() { -    Rect clip(*mSnapshot->clipRect); +    Rect clip(currentClipRect());      clip.snapToPixelBoundaries(); -    if (mCaches.setScissor(clip.left, mSnapshot->height - clip.bottom, +    if (mCaches.setScissor(clip.left, currentSnapshot().height - clip.bottom,              clip.getWidth(), clip.getHeight())) {          mDirtyClip = false;      } @@ -1564,7 +1474,7 @@ void OpenGLRenderer::ensureStencilBuffer() {      // cannot attach a stencil buffer to fbo0 dynamically. Let's      // just hope we have one when hasLayer() returns false.      if (hasLayer()) { -        attachStencilBufferToLayer(mSnapshot->layer); +        attachStencilBufferToLayer(currentSnapshot().layer);      }  } @@ -1586,7 +1496,7 @@ void OpenGLRenderer::attachStencilBufferToLayer(Layer* layer) {  void OpenGLRenderer::setStencilFromClip() {      if (!mCaches.debugOverdraw) { -        if (!mSnapshot->clipRegion->isEmpty()) { +        if (!currentSnapshot().clipRegion->isEmpty()) {              // 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; @@ -1611,14 +1521,16 @@ void OpenGLRenderer::setStencilFromClip() {              // 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(*mSnapshot->clipRegion, 0xff000000, SkXfermode::kSrc_Mode, false); +            drawRegionRects(*(currentSnapshot().clipRegion), +                    0xff000000, SkXfermode::kSrc_Mode, false);              mCaches.stencil.enableTest();              // Draw the region used to generate the stencil if the appropriate debug              // mode is enabled              if (mCaches.debugStencilClip == Caches::kStencilShowRegion) { -                drawRegionRects(*mSnapshot->clipRegion, 0x7f0000ff, SkXfermode::kSrcOver_Mode); +                drawRegionRects(*(currentSnapshot().clipRegion), +                        0x7f0000ff, SkXfermode::kSrcOver_Mode);              }          } else {              mCaches.stencil.disable(); @@ -1626,69 +1538,6 @@ void OpenGLRenderer::setStencilFromClip() {      }  } -const Rect& OpenGLRenderer::getClipBounds() const { -    return mSnapshot->getLocalClip(); -} - -/** - * Calculates whether content drawn within the passed bounds would be outside of, or intersect with - * the clipRect. Does not modify the scissor. - * - * @param clipRequired if not null, will be set to true if element intersects clip - *         (and wasn't rejected) - * - * @param snapOut if set, the geometry will be treated as having an AA ramp. - *         See Rect::snapGeometryToPixelBoundaries() - */ -bool OpenGLRenderer::calculateQuickRejectForScissor(float left, float top, -        float right, float bottom, bool* clipRequired, bool snapOut) const { -    if (mSnapshot->isIgnored() || bottom <= top || right <= left) { -        return true; -    } - -    Rect r(left, top, right, bottom); -    currentTransform().mapRect(r); -    r.snapGeometryToPixelBoundaries(snapOut); - -    Rect clipRect(*mSnapshot->clipRect); -    clipRect.snapToPixelBoundaries(); - -    if (!clipRect.intersects(r)) return true; - -    // clip is required if geometry intersects clip rect -    if (clipRequired) *clipRequired = !clipRect.contains(r); -    return false; -} - -/** - * Returns false if drawing won't be clipped out. - * - * Makes the decision conservatively, by rounding out the mapped rect before comparing with the - * clipRect. To be used when perfect, pixel accuracy is not possible (esp. with tessellation) but - * rejection is still desired. - * - * This function, unlike quickRejectSetupScissor, should be used where precise geometry information - * isn't known (esp. when geometry adjusts based on scale). Generally, this will be first pass - * rejection where precise rejection isn't important, or precise information isn't available. - */ -bool OpenGLRenderer::quickRejectConservative(float left, float top, -        float right, float bottom) const { -    if (mSnapshot->isIgnored() || bottom <= top || right <= left) { -        return true; -    } - -    Rect r(left, top, right, bottom); -    currentTransform().mapRect(r); -    r.roundOut(); // rounded out to be conservative - -    Rect clipRect(*mSnapshot->clipRect); -    clipRect.snapToPixelBoundaries(); - -    if (!clipRect.intersects(r)) return true; - -    return false; -} -  /**   * Returns false and sets scissor enable based upon bounds if drawing won't be clipped out.   * @@ -1721,8 +1570,8 @@ bool OpenGLRenderer::quickRejectSetupScissor(float left, float top, float right,  void OpenGLRenderer::debugClip() {  #if DEBUG_CLIP_REGIONS -    if (!isRecording() && !mSnapshot->clipRegion->isEmpty()) { -        drawRegionRects(*mSnapshot->clipRegion, 0x7f00ff00, SkXfermode::kSrcOver_Mode); +    if (!isRecording() && !currentSnapshot().clipRegion->isEmpty()) { +        drawRegionRects(*(currentSnapshot().clipRegion), 0x7f00ff00, SkXfermode::kSrcOver_Mode);      }  #endif  } @@ -1754,7 +1603,7 @@ bool OpenGLRenderer::clipPath(SkPath* path, SkRegion::Op op) {          clip.setRegion(*mSnapshot->previous->clipRegion);      } else {          if (mSnapshot->previous == mFirstSnapshot) { -            clip.setRect(0, 0, mWidth, mHeight); +            clip.setRect(0, 0, getWidth(), getHeight());          } else {              Rect* bounds = mSnapshot->previous->clipRect;              clip.setRect(bounds->left, bounds->top, bounds->right, bounds->bottom); @@ -1779,10 +1628,6 @@ bool OpenGLRenderer::clipRegion(SkRegion* region, SkRegion::Op op) {      return !mSnapshot->clipRect->isEmpty();  } -Rect* OpenGLRenderer::getClipRect() { -    return mSnapshot->clipRect; -} -  ///////////////////////////////////////////////////////////////////////////////  // Drawing commands  /////////////////////////////////////////////////////////////////////////////// @@ -2067,7 +1912,7 @@ status_t OpenGLRenderer::drawDisplayList(DisplayList* displayList, Rect& dirty,      if (mCaches.propertyDirtyViewport) {          // force recalc of view/proj matrices -        setViewport(mWidth, mHeight); +        setViewport(getWidth(), getHeight());          mCaches.propertyDirtyViewport = false;      } @@ -3107,7 +2952,7 @@ status_t OpenGLRenderer::drawLayer(Layer* layer, float x, float y) {          transform = &layer->getTransform();          if (!transform->isIdentity()) {              save(0); -            currentTransform().multiply(*transform); +            concatMatrix(*transform);          }      } diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h index 2d6a7e995995..1325bf700b3f 100644 --- a/libs/hwui/OpenGLRenderer.h +++ b/libs/hwui/OpenGLRenderer.h @@ -42,6 +42,7 @@  #include "Program.h"  #include "Rect.h"  #include "Renderer.h" +#include "StatefulBaseRenderer.h"  #include "SkiaColorFilter.h"  #include "Snapshot.h"  #include "UvMapper.h" @@ -120,10 +121,9 @@ enum ModelViewMode {  // Renderer  ///////////////////////////////////////////////////////////////////////////////  /** - * OpenGL renderer used to draw accelerated 2D graphics. The API is a - * simplified version of Skia's Canvas API. + * OpenGL Renderer implementation.   */ -class OpenGLRenderer : public Renderer { +class OpenGLRenderer : public StatefulBaseRenderer {  public:      ANDROID_API OpenGLRenderer();      virtual ~OpenGLRenderer(); @@ -131,10 +131,7 @@ public:      ANDROID_API void initProperties();      virtual void setViewport(int width, int height); - -    virtual status_t prepare(bool opaque);      virtual status_t prepareDirty(float left, float top, float right, float bottom, bool opaque); -      virtual void finish();      virtual void interrupt();      virtual void resume(); @@ -157,11 +154,6 @@ public:      ANDROID_API void clearLayerUpdates();      ANDROID_API void flushLayerUpdates(); -    ANDROID_API int getSaveCount() const; -    virtual int save(int flags); -    virtual void restore(); -    virtual void restoreToCount(int saveCount); -      ANDROID_API int saveLayer(float left, float top, float right, float bottom,              SkPaint* paint, int flags) {          SkXfermode::Mode mode = SkXfermode::kSrcOver_Mode; @@ -178,28 +170,9 @@ public:      int saveLayerDeferred(float left, float top, float right, float bottom,              int alpha, SkXfermode::Mode mode, int flags); -    virtual void translate(float dx, float dy, float dz = 0); -    virtual void rotate(float degrees); -    virtual void scale(float sx, float sy); -    virtual void skew(float sx, float sy); - -    bool hasRectToRectTransform(); -    ANDROID_API void getMatrix(SkMatrix* matrix) const; -    virtual void setMatrix(SkMatrix* matrix); -    virtual void concatMatrix(SkMatrix* matrix); -    virtual void concatMatrix(Matrix4& matrix) { -        currentTransform().multiply(matrix); -    } - -    ANDROID_API const Rect& getClipBounds() const; - -    ANDROID_API bool quickRejectConservative(float left, float top, -            float right, float bottom) const; -      virtual bool clipRect(float left, float top, float right, float bottom, SkRegion::Op op);      virtual bool clipPath(SkPath* path, SkRegion::Op op);      virtual bool clipRegion(SkRegion* region, SkRegion::Op op); -    virtual Rect* getClipRect();      virtual status_t drawDisplayList(DisplayList* displayList, Rect& dirty, int32_t replayFlags);      virtual status_t drawLayer(Layer* layer, float x, float y); @@ -273,7 +246,7 @@ public:      void setDrawModifiers(const DrawModifiers& drawModifiers) { mDrawModifiers = drawModifiers; }      ANDROID_API bool isCurrentTransformSimple() { -        return mSnapshot->transform->isSimple(); +        return currentTransform().isSimple();      }      Caches& getCaches() { @@ -400,9 +373,6 @@ protected:       */      void attachStencilBufferToLayer(Layer* layer); -    bool calculateQuickRejectForScissor(float left, float top, float right, float bottom, -            bool* clipRequired, bool snapOut) const; -      bool quickRejectSetupScissor(float left, float top, float right, float bottom,              SkPaint* paint = NULL);      bool quickRejectSetupScissor(const Rect& bounds, SkPaint* paint = NULL) { @@ -419,16 +389,13 @@ protected:       * @param curent The current snapshot containing the layer to compose       * @param previous The previous snapshot to compose the current layer with       */ -    virtual void composeLayer(sp<Snapshot> current, sp<Snapshot> previous); +    virtual void composeLayer(const Snapshot& current, const Snapshot& previous);      /**       * Marks the specified region as dirty at the specified bounds.       */      void dirtyLayerUnchecked(Rect& bounds, Region* region); -    /** -     * Returns the current snapshot. -     */      sp<Snapshot> getSnapshot() const {          return mSnapshot;      } @@ -450,7 +417,7 @@ protected:      /**       * Returns the name of the FBO this renderer is rendering into.       */ -    virtual GLint getTargetFbo() const { +    virtual GLuint getTargetFbo() const {          return 0;      } @@ -520,7 +487,7 @@ private:       * This method needs to be invoked every time getTargetFbo() is       * bound again.       */ -    void startTiling(const sp<Snapshot>& snapshot, bool opaque = false); +    void startTiling(const Snapshot& snapshot, bool opaque = false);      /**       * Tells the GPU what part of the screen is about to be redrawn. @@ -535,23 +502,7 @@ private:       */      void endTiling(); -    /** -     * Saves the current state of the renderer as a new snapshot. -     * The new snapshot is saved in mSnapshot and the previous snapshot -     * is linked from mSnapshot->previous. -     * -     * @param flags The save flags; see SkCanvas for more information -     * -     * @return The new save count. This value can be passed to #restoreToCount() -     */ -    int saveSnapshot(int flags); - -    /** -     * Restores the current snapshot; mSnapshot becomes mSnapshot->previous. -     * -     * @return True if the clip was modified. -     */ -    bool restoreSnapshot(); +    void onSnapshotRestored(const Snapshot& removed, const Snapshot& restored);      /**       * Sets the clipping rectangle using glScissor. The clip is defined by @@ -979,10 +930,6 @@ private:          mDirtyClip = true;      } -    inline mat4& currentTransform() const { -        return *mSnapshot->transform; -    } -      inline const UvMapper& getMapper(const Texture* texture) {          return texture && texture->uvMapper ? *texture->uvMapper : mUvMapper;      } @@ -994,9 +941,6 @@ private:       */      Texture* getTexture(SkBitmap* bitmap); -    // Dimensions of the drawing surface -    int mWidth, mHeight; -      // Matrix used for view/projection in shaders      mat4 mViewProjMatrix; @@ -1016,12 +960,6 @@ private:       */      mat4 mModelView; -    // Number of saved states -    int mSaveCount; -    // Base state -    sp<Snapshot> mFirstSnapshot; -    // Current state -    sp<Snapshot> mSnapshot;      // State used to define the clipping region      Rect mTilingClip;      // Is the target render surface opaque diff --git a/libs/hwui/Renderer.h b/libs/hwui/Renderer.h index ac216fe4e6e8..faf663a60390 100644 --- a/libs/hwui/Renderer.h +++ b/libs/hwui/Renderer.h @@ -17,10 +17,18 @@  #ifndef ANDROID_HWUI_RENDERER_H  #define ANDROID_HWUI_RENDERER_H +#include <SkRegion.h> + +#include <utils/String8.h> +  #include "AssetAtlas.h"  #include "SkPaint.h"  namespace android { + +class Functor; +class Res_png_9patch; +  namespace uirenderer {  class DisplayList; @@ -152,12 +160,8 @@ public:  // ----------------------------------------------------------------------------  // Canvas state operations  // ---------------------------------------------------------------------------- -    // getters +    // Save (layer)      virtual int getSaveCount() const = 0; -    virtual void getMatrix(SkMatrix* outMatrix) const = 0; -    virtual const Rect& getClipBounds() const = 0; - -    // save (layer)      virtual int save(int flags) = 0;      virtual void restore() = 0;      virtual void restoreToCount(int saveCount) = 0; @@ -180,6 +184,7 @@ public:              int alpha, SkXfermode::Mode mode, int flags) = 0;      // Matrix +    virtual void getMatrix(SkMatrix* outMatrix) const = 0;      virtual void translate(float dx, float dy, float dz = 0.0f) = 0;      virtual void rotate(float degrees) = 0;      virtual void scale(float sx, float sy) = 0; @@ -187,9 +192,11 @@ public:      virtual void setMatrix(SkMatrix* matrix) = 0;      virtual void concatMatrix(SkMatrix* matrix) = 0; -    virtual void concatMatrix(Matrix4& matrix) = 0; -    // Clip +    // clip +    virtual const Rect& getClipBounds() const = 0; +    virtual bool quickRejectConservative(float left, float top, +            float right, float bottom) const = 0;      virtual bool clipRect(float left, float top, float right, float bottom, SkRegion::Op op) = 0;      virtual bool clipPath(SkPath* path, SkRegion::Op op) = 0;      virtual bool clipRegion(SkRegion* region, SkRegion::Op op) = 0; diff --git a/libs/hwui/StatefulBaseRenderer.cpp b/libs/hwui/StatefulBaseRenderer.cpp new file mode 100644 index 000000000000..cc8b14fafb92 --- /dev/null +++ b/libs/hwui/StatefulBaseRenderer.cpp @@ -0,0 +1,206 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <SkCanvas.h> + +#include "StatefulBaseRenderer.h" + +namespace android { +namespace uirenderer { + +StatefulBaseRenderer::StatefulBaseRenderer() : +        mSaveCount(1), mFirstSnapshot(new Snapshot), mSnapshot(mFirstSnapshot) { +} + +void StatefulBaseRenderer::initializeSaveStack(float clipLeft, float clipTop, +        float clipRight, float clipBottom) { +    mSnapshot = new Snapshot(mFirstSnapshot, +            SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag); +    mSnapshot->setClip(clipLeft, clipTop, clipRight, clipBottom); +    mSnapshot->fbo = getTargetFbo(); +    mSaveCount = 1; +} + +void StatefulBaseRenderer::initializeViewport(int width, int height) { +    mWidth = width; +    mHeight = height; + +    mFirstSnapshot->height = height; +    mFirstSnapshot->viewport.set(0, 0, width, height); +} + +/////////////////////////////////////////////////////////////////////////////// +// Save (layer) +/////////////////////////////////////////////////////////////////////////////// + +/** + * Non-virtual implementation of save, guaranteed to save without side-effects + * + * The approach here and in restoreSnapshot(), allows subclasses to directly manipulate the save + * stack, and ensures restoreToCount() doesn't call back into subclass overrides. + */ +int StatefulBaseRenderer::saveSnapshot(int flags) { +    mSnapshot = new Snapshot(mSnapshot, flags); +    return mSaveCount++; +} + +int StatefulBaseRenderer::save(int flags) { +    return saveSnapshot(flags); +} + +/** + * Non-virtual implementation of restore, guaranteed to restore without side-effects. + */ +void StatefulBaseRenderer::restoreSnapshot() { +    sp<Snapshot> toRemove = mSnapshot; +    sp<Snapshot> toRestore = mSnapshot->previous; + +    mSaveCount--; +    mSnapshot = toRestore; + +    // subclass handles restore implementation +    onSnapshotRestored(*toRemove, *toRestore); +} + +void StatefulBaseRenderer::restore() { +    if (mSaveCount > 1) { +        restoreSnapshot(); +    } +} + +void StatefulBaseRenderer::restoreToCount(int saveCount) { +    if (saveCount < 1) saveCount = 1; + +    while (mSaveCount > saveCount) { +        restoreSnapshot(); +    } +} + +/////////////////////////////////////////////////////////////////////////////// +// Matrix +/////////////////////////////////////////////////////////////////////////////// + +void StatefulBaseRenderer::getMatrix(SkMatrix* matrix) const { +    mSnapshot->transform->copyTo(*matrix); +} + +void StatefulBaseRenderer::translate(float dx, float dy, float dz) { +    mSnapshot->transform->translate(dx, dy, dz); +} + +void StatefulBaseRenderer::rotate(float degrees) { +    mSnapshot->transform->rotate(degrees, 0.0f, 0.0f, 1.0f); +} + +void StatefulBaseRenderer::scale(float sx, float sy) { +    mSnapshot->transform->scale(sx, sy, 1.0f); +} + +void StatefulBaseRenderer::skew(float sx, float sy) { +    mSnapshot->transform->skew(sx, sy); +} + +void StatefulBaseRenderer::setMatrix(SkMatrix* matrix) { +    if (matrix) { +        mSnapshot->transform->load(*matrix); +    } else { +        mSnapshot->transform->loadIdentity(); +    } +} + +void StatefulBaseRenderer::setMatrix(const Matrix4& matrix) { +    mSnapshot->transform->load(matrix); +} + +void StatefulBaseRenderer::concatMatrix(SkMatrix* matrix) { +    mat4 transform(*matrix); +    mSnapshot->transform->multiply(transform); +} + +void StatefulBaseRenderer::concatMatrix(const Matrix4& matrix) { +    mSnapshot->transform->multiply(matrix); +} + +/////////////////////////////////////////////////////////////////////////////// +// Clip +/////////////////////////////////////////////////////////////////////////////// + + +/////////////////////////////////////////////////////////////////////////////// +// Quick Rejection +/////////////////////////////////////////////////////////////////////////////// + +/** + * Calculates whether content drawn within the passed bounds would be outside of, or intersect with + * the clipRect. Does not modify the scissor. + * + * @param clipRequired if not null, will be set to true if element intersects clip + *         (and wasn't rejected) + * + * @param snapOut if set, the geometry will be treated as having an AA ramp. + *         See Rect::snapGeometryToPixelBoundaries() + */ +bool StatefulBaseRenderer::calculateQuickRejectForScissor(float left, float top, +        float right, float bottom, bool* clipRequired, bool snapOut) const { +    if (mSnapshot->isIgnored() || bottom <= top || right <= left) { +        return true; +    } + +    Rect r(left, top, right, bottom); +    currentTransform().mapRect(r); +    r.snapGeometryToPixelBoundaries(snapOut); + +    Rect clipRect(currentClipRect()); +    clipRect.snapToPixelBoundaries(); + +    if (!clipRect.intersects(r)) return true; + +    // clip is required if geometry intersects clip rect +    if (clipRequired) *clipRequired = !clipRect.contains(r); +    return false; +} + +/** + * Returns false if drawing won't be clipped out. + * + * Makes the decision conservatively, by rounding out the mapped rect before comparing with the + * clipRect. To be used when perfect, pixel accuracy is not possible (esp. with tessellation) but + * rejection is still desired. + * + * This function, unlike quickRejectSetupScissor, should be used where precise geometry information + * isn't known (esp. when geometry adjusts based on scale). Generally, this will be first pass + * rejection where precise rejection isn't important, or precise information isn't available. + */ +bool StatefulBaseRenderer::quickRejectConservative(float left, float top, +        float right, float bottom) const { +    if (mSnapshot->isIgnored() || bottom <= top || right <= left) { +        return true; +    } + +    Rect r(left, top, right, bottom); +    currentTransform().mapRect(r); +    r.roundOut(); // rounded out to be conservative + +    Rect clipRect(currentClipRect()); +    clipRect.snapToPixelBoundaries(); + +    if (!clipRect.intersects(r)) return true; + +    return false; +} + +}; // namespace uirenderer +}; // namespace android diff --git a/libs/hwui/StatefulBaseRenderer.h b/libs/hwui/StatefulBaseRenderer.h new file mode 100644 index 000000000000..2bd196e36e26 --- /dev/null +++ b/libs/hwui/StatefulBaseRenderer.h @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_HWUI_STATEFUL_BASE_RENDERER_H +#define ANDROID_HWUI_STATEFUL_BASE_RENDERER_H + +#include <utils/RefBase.h> + +#include "Renderer.h" +#include "Snapshot.h" + +namespace android { +namespace uirenderer { + +/** + * Implementation for Renderer state methods + * + * Eventually, this class should have abstract protected methods + * for allowing subclasses to hook into save/saveLayer and restore + */ +class StatefulBaseRenderer : public Renderer { +public: +    StatefulBaseRenderer(); + +    virtual status_t prepare(bool opaque) { +        return prepareDirty(0.0f, 0.0f, mWidth, mHeight, opaque); +    } +    void initializeViewport(int width, int height); +    void initializeSaveStack(float clipLeft, float clipTop, float clipRight, float clipBottom); + +    // getters +    bool hasRectToRectTransform() const { +        return CC_LIKELY(currentTransform().rectToRect()); +    } + +    // Save (layer) +    virtual int getSaveCount() const { return mSaveCount; } +    virtual int save(int flags); +    virtual void restore(); +    virtual void restoreToCount(int saveCount); +    //virtual int saveLayer(float left, float top, float right, float bottom, +    //        int alpha, SkXfermode::Mode mode, int flags); + +    // Matrix +    virtual void getMatrix(SkMatrix* outMatrix) const; +    virtual void translate(float dx, float dy, float dz = 0.0f); +    virtual void rotate(float degrees); +    virtual void scale(float sx, float sy); +    virtual void skew(float sx, float sy); + +    virtual void setMatrix(SkMatrix* matrix); +    void setMatrix(const Matrix4& matrix); // internal only convenience method +    virtual void concatMatrix(SkMatrix* matrix); +    void concatMatrix(const Matrix4& matrix); // internal only convenience method + +    // Clip +    const Rect& getClipBounds() const { return mSnapshot->getLocalClip(); } +    virtual bool quickRejectConservative(float left, float top, float right, float bottom) const; + +    // TODO: implement these with hooks to enable scissor/stencil usage in OpenGLRenderer +    // virtual bool clipRect(float left, float top, float right, float bottom, SkRegion::Op op); +    // virtual bool clipPath(SkPath* path, SkRegion::Op op); +    // virtual bool clipRegion(SkRegion* region, SkRegion::Op op); + +protected: +    int getWidth() { return mWidth; } +    int getHeight() { return mHeight; } + +    // Save +    int saveSnapshot(int flags); +    void restoreSnapshot(); + +    // allows subclasses to control what value is stored in snapshot's fbo field in +    // initializeSaveStack +    virtual GLuint getTargetFbo() const { +        return -1; +    } + +    // Clip +    bool calculateQuickRejectForScissor(float left, float top, float right, float bottom, +            bool* clipRequired, bool snapOut) const; + +    /** +     * Called just after a restore has occurred. The 'removed' snapshot popped from the stack, +     * 'restored' snapshot has become the top/current. +     * +     * Subclasses can override this method to handle layer restoration +     */ +    virtual void onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) {}; + +    inline const Rect& currentClipRect() const { +        return *(mSnapshot->clipRect); +    } + +    inline const mat4& currentTransform() const { +        return *(mSnapshot->transform); +    } + +    inline const Snapshot& currentSnapshot() const { +        return mSnapshot != NULL ? *mSnapshot : *mFirstSnapshot; +    } + +    // TODO: below should be private so that snapshot stack manipulation +    // goes though (mostly) public methods + +    // Number of saved states +    int mSaveCount; + +    // Base state +    sp<Snapshot> mFirstSnapshot; + +    // Current state +    sp<Snapshot> mSnapshot; + +private: +    // Dimensions of the drawing surface +    int mWidth, mHeight; + +}; // class StatefulBaseRenderer + +}; // namespace uirenderer +}; // namespace android + +#endif // ANDROID_HWUI_STATEFUL_BASE_RENDERER_H  |