Merge "Avoid multiple font cache texture uploads Bug #8378964" into jb-mr2-dev

This commit is contained in:
Romain Guy
2013-03-27 00:21:05 +00:00
committed by Android (Google) Code Review
7 changed files with 181 additions and 31 deletions

View File

@@ -428,6 +428,8 @@ public abstract class HardwareRenderer {
interface HardwareDrawCallbacks {
/**
* Invoked before a view is drawn by a hardware renderer.
* This method can be used to apply transformations to the
* canvas but no drawing command should be issued.
*
* @param canvas The Canvas used to render the view.
*/
@@ -435,6 +437,7 @@ public abstract class HardwareRenderer {
/**
* Invoked after a view is drawn by a hardware renderer.
* It is safe to invoke drawing commands from this method.
*
* @param canvas The Canvas used to render the view.
*/

View File

@@ -52,6 +52,8 @@ public:
kOpBatch_Count, // Add other batch ids before this
};
void clear();
bool isEmpty() { return mBatches.isEmpty(); }
/**
@@ -78,8 +80,6 @@ private:
*/
void resetBatchingState();
void clear();
void storeStateOpBarrier(OpenGLRenderer& renderer, StateOp* op);
void storeRestoreToCountBarrier(int newSaveCount);

View File

@@ -18,6 +18,8 @@
#include <utils/Log.h>
#include "DisplayList.h"
#include "DeferredDisplayList.h"
#include "Layer.h"
#include "LayerRenderer.h"
#include "OpenGLRenderer.h"
@@ -43,15 +45,18 @@ Layer::Layer(const uint32_t layerWidth, const uint32_t layerHeight) {
fbo = 0;
stencil = NULL;
debugDrawUpdate = false;
deferredList = NULL;
Caches::getInstance().resourceCache.incrementRefcount(this);
}
Layer::~Layer() {
if (mesh) delete mesh;
if (meshIndices) delete meshIndices;
if (colorFilter) Caches::getInstance().resourceCache.decrementRefcount(colorFilter);
removeFbo();
deleteTexture();
delete[] mesh;
delete[] meshIndices;
delete deferredList;
}
uint32_t Layer::computeIdealWidth(uint32_t layerWidth) {
@@ -133,5 +138,43 @@ void Layer::setColorFilter(SkiaColorFilter* filter) {
}
}
void Layer::defer() {
if (!deferredList) {
deferredList = new DeferredDisplayList;
}
DeferStateStruct deferredState(*deferredList, *renderer,
DisplayList::kReplayFlag_ClipChildren);
const float width = layer.getWidth();
const float height = layer.getHeight();
if (dirtyRect.isEmpty() || (dirtyRect.left <= 0 && dirtyRect.top <= 0 &&
dirtyRect.right >= width && dirtyRect.bottom >= height)) {
dirtyRect.set(0, 0, width, height);
}
renderer->initViewport(width, height);
renderer->setupFrameState(dirtyRect.left, dirtyRect.top,
dirtyRect.right, dirtyRect.bottom, !isBlend());
displayList->defer(deferredState, 0);
}
void Layer::flush() {
if (deferredList && !deferredList->isEmpty()) {
renderer->setViewport(layer.getWidth(), layer.getHeight());
renderer->prepareDirty(dirtyRect.left, dirtyRect.top, dirtyRect.right, dirtyRect.bottom,
!isBlend());
deferredList->flush(*renderer, dirtyRect);
renderer->finish();
renderer = NULL;
dirtyRect.setEmpty();
deferredList->clear();
}
}
}; // namespace uirenderer
}; // namespace android

View File

@@ -42,6 +42,8 @@ namespace uirenderer {
// Forward declarations
class OpenGLRenderer;
class DisplayList;
class DeferredDisplayList;
class DeferStateStruct;
/**
* A layer has dimensions and is backed by an OpenGL texture or FBO.
@@ -271,6 +273,9 @@ struct Layer {
return transform;
}
void defer();
void flush();
/**
* Bounds of the layer.
*/
@@ -379,6 +384,12 @@ private:
*/
mat4 transform;
/**
* Used to defer display lists when the layer is updated with a
* display list.
*/
DeferredDisplayList* deferredList;
}; // struct Layer
}; // namespace uirenderer

View File

@@ -129,8 +129,8 @@ Region* LayerRenderer::getRegion() const {
void LayerRenderer::generateMesh() {
if (mLayer->region.isRect() || mLayer->region.isEmpty()) {
if (mLayer->mesh) {
delete mLayer->mesh;
delete mLayer->meshIndices;
delete[] mLayer->mesh;
delete[] mLayer->meshIndices;
mLayer->mesh = NULL;
mLayer->meshIndices = NULL;
@@ -153,8 +153,8 @@ void LayerRenderer::generateMesh() {
GLsizei elementCount = count * 6;
if (mLayer->mesh && mLayer->meshElementCount < elementCount) {
delete mLayer->mesh;
delete mLayer->meshIndices;
delete[] mLayer->mesh;
delete[] mLayer->meshIndices;
mLayer->mesh = NULL;
mLayer->meshIndices = NULL;

View File

@@ -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);
}
status_t OpenGLRenderer::startFrame() {
if (mFrameStarted) return DrawGlInfo::kStatusDone;
mFrameStarted = true;
mDirtyClip = true;
updateLayers();
discardFramebuffer(mTilingClip.left, mTilingClip.top, mTilingClip.right, mTilingClip.bottom);
discardFramebuffer(left, top, right, 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);
}

View File

@@ -361,6 +361,18 @@ protected:
*/
void initViewport(int width, int height);
/**
* Perform the setup specific to a frame. This method does not
* issue any OpenGL commands.
*/
void setupFrameState(float left, float top, float right, float bottom, bool opaque);
/**
* Indicates the start of rendering. This method will setup the
* initial OpenGL state (viewport, clearing the buffer, etc.)
*/
status_t startFrame();
/**
* Clears the underlying surface if needed.
*/
@@ -897,6 +909,7 @@ private:
bool updateLayer(Layer* layer, bool inFrame);
void updateLayers();
void flushLayers();
/**
* Renders the specified region as a series of rectangles. This method
@@ -948,6 +961,10 @@ private:
sp<Snapshot> mSnapshot;
// State used to define the clipping region
Rect mTilingClip;
// Is the target render surface opaque
bool mOpaque;
// Is a frame currently being rendered
bool mFrameStarted;
// Used to draw textured quads
TextureVertex mMeshVertices[4];
@@ -996,6 +1013,7 @@ private:
String8 mName;
friend class DisplayListRenderer;
friend class Layer;
friend class TextSetupFunctor;
}; // class OpenGLRenderer