* commit '2509437e309827dbfe8bf3797d59c0d01af13972': Avoid multiple font cache texture uploads Bug #8378964
This commit is contained in:
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user