summaryrefslogtreecommitdiff
path: root/libs/hwui/OpenGLRenderer.cpp
diff options
context:
space:
mode:
author Romain Guy <romainguy@google.com> 2013-03-26 15:05:58 -0700
committer Romain Guy <romainguy@google.com> 2013-03-26 15:25:07 -0700
commit96885eb480c5e0526fe2f77d30f6e551f3f3ceab (patch)
tree17bee5ff04c63bf1415696b02374c60e584a0542 /libs/hwui/OpenGLRenderer.cpp
parent7c566bf3e4a10d74588b3e92ea3f6af310930f37 (diff)
Avoid multiple font cache texture uploads
Bug #8378964 This change defers drawing into layers until after the renderer for FBO0 is ready to draw. At that point, all the precaching is done which means all glyphs can be uploaded at once in the font caches. Change-Id: Ie1f7a7ff30f76f06fb3dbc72c7d05e66207d1ecb
Diffstat (limited to 'libs/hwui/OpenGLRenderer.cpp')
-rw-r--r--libs/hwui/OpenGLRenderer.cpp121
1 files changed, 98 insertions, 23 deletions
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 2cf7183360d1..1c36a23fb86c 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -120,6 +120,7 @@ OpenGLRenderer::OpenGLRenderer():
memcpy(mMeshVertices, gMeshVertices, sizeof(gMeshVertices));
mFirstSnapshot = new Snapshot;
+ mFrameStarted = false;
mScissorOptimizationDisabled = false;
}
@@ -179,14 +180,11 @@ void OpenGLRenderer::initViewport(int width, int height) {
mFirstSnapshot->viewport.set(0, 0, width, height);
}
-status_t OpenGLRenderer::prepare(bool opaque) {
- return prepareDirty(0.0f, 0.0f, mWidth, mHeight, opaque);
-}
-
-status_t OpenGLRenderer::prepareDirty(float left, float top,
+void OpenGLRenderer::setupFrameState(float left, float top,
float right, float bottom, bool opaque) {
mCaches.clearGarbage();
+ mOpaque = opaque;
mSnapshot = new Snapshot(mFirstSnapshot,
SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
mSnapshot->fbo = getTargetFbo();
@@ -194,13 +192,17 @@ status_t OpenGLRenderer::prepareDirty(float left, float top,
mSnapshot->setClip(left, top, right, bottom);
mTilingClip.set(left, top, right, bottom);
- mDirtyClip = true;
+}
- updateLayers();
+status_t OpenGLRenderer::startFrame() {
+ if (mFrameStarted) return DrawGlInfo::kStatusDone;
+ mFrameStarted = true;
- discardFramebuffer(left, top, right, bottom);
+ mDirtyClip = true;
+
+ discardFramebuffer(mTilingClip.left, mTilingClip.top, mTilingClip.right, mTilingClip.bottom);
- syncState();
+ glViewport(0, 0, mWidth, mHeight);
// Functors break the tiling extension in pretty spectacular ways
// This ensures we don't use tiling when a functor is going to be
@@ -211,7 +213,30 @@ status_t OpenGLRenderer::prepareDirty(float left, float top,
debugOverdraw(true, true);
- return clear(left, top, right, bottom, opaque);
+ return clear(mTilingClip.left, mTilingClip.top,
+ 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) {
+ setupFrameState(left, top, right, bottom, opaque);
+
+ // Layer renderers will start the frame immediately
+ // 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) {
+ syncState();
+ updateLayers();
+ } else {
+ return startFrame();
+ }
+
+ return DrawGlInfo::kStatusDone;
}
void OpenGLRenderer::discardFramebuffer(float left, float top, float right, float bottom) {
@@ -241,8 +266,6 @@ status_t OpenGLRenderer::clear(float left, float top, float right, float bottom,
}
void OpenGLRenderer::syncState() {
- glViewport(0, 0, mWidth, mHeight);
-
if (mCaches.blend) {
glEnable(GL_BLEND);
} else {
@@ -312,6 +335,8 @@ void OpenGLRenderer::finish() {
}
#endif
}
+
+ mFrameStarted = false;
}
void OpenGLRenderer::interrupt() {
@@ -503,8 +528,8 @@ void OpenGLRenderer::renderOverdraw() {
///////////////////////////////////////////////////////////////////////////////
bool OpenGLRenderer::updateLayer(Layer* layer, bool inFrame) {
- if (layer->deferredUpdateScheduled && layer->renderer && layer->displayList) {
- OpenGLRenderer* renderer = layer->renderer;
+ if (layer->deferredUpdateScheduled && layer->renderer &&
+ layer->displayList && layer->displayList->isRenderable()) {
Rect& dirty = layer->dirtyRect;
if (inFrame) {
@@ -512,19 +537,29 @@ bool OpenGLRenderer::updateLayer(Layer* layer, bool inFrame) {
debugOverdraw(false, false);
}
- 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();
+ if (CC_UNLIKELY(inFrame || mCaches.drawDeferDisabled)) {
+ OpenGLRenderer* renderer = layer->renderer;
+ 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();
+ } else {
+ layer->defer();
+ }
if (inFrame) {
resumeAfterLayer();
startTiling(mSnapshot);
}
- dirty.setEmpty();
+ if (CC_UNLIKELY(inFrame || mCaches.drawDeferDisabled)) {
+ dirty.setEmpty();
+ layer->renderer = NULL;
+ }
+
layer->deferredUpdateScheduled = false;
- layer->renderer = NULL;
layer->displayList = NULL;
layer->debugDrawUpdate = mCaches.debugLayersUpdates;
@@ -535,19 +570,54 @@ bool OpenGLRenderer::updateLayer(Layer* layer, bool inFrame) {
}
void OpenGLRenderer::updateLayers() {
+ // If draw deferring is enabled this method will simply defer
+ // the display list of each individual layer. The layers remain
+ // in the layer updates list which will be cleared by flushLayers().
int count = mLayerUpdates.size();
if (count > 0) {
- startMark("Layer Updates");
+ if (CC_UNLIKELY(mCaches.drawDeferDisabled)) {
+ startMark("Layer Updates");
+ } else {
+ startMark("Defer Layer Updates");
+ }
// Note: it is very important to update the layers in reverse order
for (int i = count - 1; i >= 0; i--) {
Layer* layer = mLayerUpdates.itemAt(i);
updateLayer(layer, false);
- mCaches.resourceCache.decrementRefcount(layer);
+ if (CC_UNLIKELY(mCaches.drawDeferDisabled)) {
+ mCaches.resourceCache.decrementRefcount(layer);
+ }
}
- mLayerUpdates.clear();
+ if (CC_UNLIKELY(mCaches.drawDeferDisabled)) {
+ mLayerUpdates.clear();
+ glBindFramebuffer(GL_FRAMEBUFFER, getTargetFbo());
+ }
+ endMark();
+ }
+}
+
+void OpenGLRenderer::flushLayers() {
+ int count = mLayerUpdates.size();
+ if (count > 0) {
+ startMark("Apply Layer Updates");
+ char layerName[12];
+
+ // Note: it is very important to update the layers in reverse order
+ for (int i = count - 1; i >= 0; i--) {
+ sprintf(layerName, "Layer #%d", i);
+ startMark(layerName); {
+ Layer* layer = mLayerUpdates.itemAt(i);
+ layer->flush();
+ mCaches.resourceCache.decrementRefcount(layer);
+ }
+ endMark();
+ }
+
+ mLayerUpdates.clear();
glBindFramebuffer(GL_FRAMEBUFFER, getTargetFbo());
+
endMark();
}
}
@@ -1832,6 +1902,7 @@ status_t OpenGLRenderer::drawDisplayList(DisplayList* displayList, Rect& dirty,
// will be performed by the display list itself
if (displayList && displayList->isRenderable()) {
if (CC_UNLIKELY(mCaches.drawDeferDisabled)) {
+ startFrame();
ReplayStateStruct replayStruct(*this, dirty, replayFlags);
displayList->replay(replayStruct, 0);
return replayStruct.mDrawGlStatus;
@@ -1840,6 +1911,10 @@ status_t OpenGLRenderer::drawDisplayList(DisplayList* displayList, Rect& dirty,
DeferredDisplayList deferredList;
DeferStateStruct deferStruct(deferredList, *this, replayFlags);
displayList->defer(deferStruct, 0);
+
+ flushLayers();
+ startFrame();
+
return deferredList.flush(*this, dirty);
}