From 2b7028eabac80cec170572bc0e945a1d4224e595 Mon Sep 17 00:00:00 2001 From: Romain Guy Date: Wed, 19 Sep 2012 17:25:38 -0700 Subject: [PATCH] Add support for QCOM_tiled_rendering Bug #7186819 This optional OpenGL extension can be used by tiled renderers to optimize copies from main memory to tiles memory. Change-Id: Id4a5d64e61ad17f50e773e8104b9bf584bb65077 --- core/java/android/view/HardwareRenderer.java | 9 ++-- libs/hwui/Caches.cpp | 4 +- libs/hwui/OpenGLRenderer.cpp | 50 +++++++++++++------ libs/hwui/OpenGLRenderer.h | 18 +++++++ .../res/layout/text_fade.xml | 1 + .../android/test/hwui/TextFadeActivity.java | 5 ++ .../android/test/hwui/ViewLayersActivity.java | 3 ++ 7 files changed, 71 insertions(+), 19 deletions(-) diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java index 446a51ed5545a..ef5dc561a7d47 100644 --- a/core/java/android/view/HardwareRenderer.java +++ b/core/java/android/view/HardwareRenderer.java @@ -1136,9 +1136,8 @@ public abstract class HardwareRenderer { } } - int status = onPreDraw(dirty); - int saveCount = canvas.save(); - callbacks.onHardwarePreDraw(canvas); + int saveCount = 0; + int status = DisplayList.STATUS_DONE; try { view.mRecreateDisplayList = (view.mPrivateFlags & View.PFLAG_INVALIDATED) @@ -1164,6 +1163,10 @@ public abstract class HardwareRenderer { Trace.traceEnd(Trace.TRACE_TAG_VIEW); } + status = onPreDraw(dirty); + saveCount = canvas.save(); + callbacks.onHardwarePreDraw(canvas); + if (mProfileEnabled) { long now = System.nanoTime(); float total = (now - getDisplayListStartTime) * 0.000001f; diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp index edb4c10cdcc3d..b149bb9083d54 100644 --- a/libs/hwui/Caches.cpp +++ b/libs/hwui/Caches.cpp @@ -429,13 +429,13 @@ void Caches::resetScissor() { void Caches::startTiling(GLuint x, GLuint y, GLuint width, GLuint height, bool opaque) { if (extensions.hasTiledRendering()) { - + glStartTilingQCOM(x, y, width, height, GL_COLOR_BUFFER_BIT0_QCOM); } } void Caches::endTiling() { if (extensions.hasTiledRendering()) { - + glEndTilingQCOM(GL_COLOR_BUFFER_BIT0_QCOM); } } diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp index 11eb7a1a9c2a1..9b9ca12e954a6 100644 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -175,7 +175,7 @@ int OpenGLRenderer::prepareDirty(float left, float top, float right, float botto mSaveCount = 1; mSnapshot->setClip(left, top, right, bottom); - mDirtyClip = opaque; + mDirtyClip = mOpaqueFrame = opaque; // 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 @@ -188,6 +188,9 @@ int OpenGLRenderer::prepareDirty(float left, float top, float right, float botto syncState(); + mTilingSnapshot = mSnapshot; + startTiling(); + if (!opaque) { mCaches.enableScissor(); mCaches.setScissor(left, mSnapshot->height - bottom, right - left, bottom - top); @@ -210,7 +213,30 @@ void OpenGLRenderer::syncState() { } } +void OpenGLRenderer::startTiling() { + startTiling(mTilingSnapshot); +} + +void OpenGLRenderer::startTiling(const sp& s) { + bool opaque = mOpaqueFrame; + Rect* clip = mTilingSnapshot->clipRect; + + if (s->flags & Snapshot::kFlagIsFboLayer) { + opaque = !s->layer->isBlend(); + clip = s->clipRect; + } + + mCaches.startTiling(clip->left, s->height - clip->bottom, + clip->right - clip->left, clip->bottom - clip->top, opaque); +} + +void OpenGLRenderer::endTiling() { + mCaches.endTiling(); +} + void OpenGLRenderer::finish() { + endTiling(); + #if DEBUG_OPENGL GLenum status = GL_NO_ERROR; while ((status = glGetError()) != GL_NO_ERROR) { @@ -637,6 +663,7 @@ bool OpenGLRenderer::createFboLayer(Layer* layer, Rect& bounds, Rect& clip, GLui mSnapshot->flags |= Snapshot::kFlagDirtyOrtho; mSnapshot->orthoMatrix.load(mOrthoMatrix); + endTiling(); // Bind texture to FBO glBindFramebuffer(GL_FRAMEBUFFER, layer->getFbo()); layer->bindTexture(); @@ -650,18 +677,7 @@ bool OpenGLRenderer::createFboLayer(Layer* layer, Rect& bounds, Rect& clip, GLui glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, layer->getTexture(), 0); -#if DEBUG_LAYERS_AS_REGIONS - GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); - if (status != GL_FRAMEBUFFER_COMPLETE) { - ALOGE("Framebuffer incomplete (GL error code 0x%x)", status); - - glBindFramebuffer(GL_FRAMEBUFFER, previousFbo); - - Caches::getInstance().resourceCache.decrementRefcount(layer); - - return false; - } -#endif + startTiling(mSnapshot); // Clear the FBO, expand the clear region by 1 to get nice bilinear filtering mCaches.enableScissor(); @@ -690,11 +706,14 @@ void OpenGLRenderer::composeLayer(sp current, sp previous) { const bool fboLayer = current->flags & Snapshot::kFlagIsFboLayer; if (fboLayer) { + endTiling(); + // Detach the texture from the FBO glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); - // Unbind current FBO and restore previous one glBindFramebuffer(GL_FRAMEBUFFER, previous->fbo); + + startTiling(previous); } Layer* layer = current->layer; @@ -2621,12 +2640,15 @@ status_t OpenGLRenderer::drawLayer(Layer* layer, float x, float y, SkPaint* pain OpenGLRenderer* renderer = layer->renderer; Rect& dirty = layer->dirtyRect; + endTiling(); + renderer->setViewport(layer->layer.getWidth(), layer->layer.getHeight()); renderer->prepareDirty(dirty.left, dirty.top, dirty.right, dirty.bottom, !layer->isBlend()); renderer->drawDisplayList(layer->displayList, dirty, DisplayList::kReplayFlag_ClipChildren); renderer->finish(); resumeAfterLayer(); + startTiling(mSnapshot); dirty.setEmpty(); layer->deferredUpdateScheduled = false; diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h index 8dcd33f19eb7a..10ba86e6ca77e 100644 --- a/libs/hwui/OpenGLRenderer.h +++ b/libs/hwui/OpenGLRenderer.h @@ -346,6 +346,20 @@ private: */ void syncState(); + /** + * Tells the GPU what part of the screen is about to be redrawn. + * This method needs to be invoked every time getTargetFbo() is + * bound again. + */ + void startTiling(); + void startTiling(const sp& snapshot); + + /** + * Tells the GPU that we are done drawing the frame or that we + * are switching to another render target. + */ + void endTiling(); + /** * Saves the current state of the renderer as a new snapshot. * The new snapshot is saved in mSnapshot and the previous snapshot @@ -735,6 +749,8 @@ private: sp mFirstSnapshot; // Current state sp mSnapshot; + // State used to define the clipping region + sp mTilingSnapshot; // Shaders SkiaShader* mShader; @@ -784,6 +800,8 @@ private: GLuint mTextureUnit; // Track dirty regions, true by default bool mTrackDirtyRegions; + // Indicate whether we are drawing an opaque frame + bool mOpaqueFrame; friend class DisplayListRenderer; diff --git a/tests/HwAccelerationTest/res/layout/text_fade.xml b/tests/HwAccelerationTest/res/layout/text_fade.xml index 8da22047aea68..08a70b3a3e716 100644 --- a/tests/HwAccelerationTest/res/layout/text_fade.xml +++ b/tests/HwAccelerationTest/res/layout/text_fade.xml @@ -32,6 +32,7 @@ android:ellipsize="marquee" android:fadingEdgeLength="16sp" android:fadingEdge="horizontal" + android:requiresFadingEdge="horizontal" android:text="This is a really really really really really really long string" android:textSize="16sp" /> diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/TextFadeActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/TextFadeActivity.java index c8bbc7d427680..d307ef871b973 100644 --- a/tests/HwAccelerationTest/src/com/android/test/hwui/TextFadeActivity.java +++ b/tests/HwAccelerationTest/src/com/android/test/hwui/TextFadeActivity.java @@ -21,7 +21,9 @@ import android.content.Context; import android.graphics.Canvas; import android.graphics.Paint; import android.os.Bundle; +import android.text.TextUtils; import android.view.View; +import android.widget.TextView; @SuppressWarnings({"UnusedDeclaration"}) public class TextFadeActivity extends Activity { @@ -30,5 +32,8 @@ public class TextFadeActivity extends Activity { super.onCreate(savedInstanceState); setContentView(R.layout.text_fade); + + findViewById(R.id.contact_tile_name).setHorizontalFadingEdgeEnabled(true); + ((TextView) findViewById(R.id.contact_tile_name)).setEllipsize(TextUtils.TruncateAt.MARQUEE); } } diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/ViewLayersActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/ViewLayersActivity.java index 359447d069959..0ddd7fd692a0f 100644 --- a/tests/HwAccelerationTest/src/com/android/test/hwui/ViewLayersActivity.java +++ b/tests/HwAccelerationTest/src/com/android/test/hwui/ViewLayersActivity.java @@ -81,11 +81,14 @@ public class ViewLayersActivity extends Activity { leftList.setAlpha(0.5f); middleList.setLayerType(View.LAYER_TYPE_HARDWARE, p3); middleList.setAlpha(0.5f); + middleList.setVerticalFadingEdgeEnabled(true); rightList.setLayerType(View.LAYER_TYPE_SOFTWARE, p2); moveRight.start(); moveLeft.start(); rotate.start(); + + ((View) leftList.getParent()).setAlpha(0.5f); } }, 2000); }