Add TextureView support to new renderer/reorderer

bug:22480459

Change-Id: I2e4c0bc6b904706132f3f5087ededc9cac9b40fb
This commit is contained in:
Chris Craik
2015-12-16 14:27:20 -08:00
parent d7448e65e2
commit d2dfd8f128
18 changed files with 121 additions and 30 deletions

View File

@@ -2,7 +2,7 @@ LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
HWUI_NEW_OPS := false
HWUI_NEW_OPS := true
hwui_src_files := \
font/CacheTexture.cpp \

View File

@@ -735,6 +735,20 @@ void BakedOpDispatcher::onTextOnPathOp(BakedOpRenderer& renderer, const TextOnPa
}
}
void BakedOpDispatcher::onTextureLayerOp(BakedOpRenderer& renderer, const TextureLayerOp& op, const BakedOpState& state) {
const bool tryToSnap = !op.layer->getForceFilter();
float alpha = (op.layer->getAlpha() / 255.0f) * state.alpha;
Glop glop;
GlopBuilder(renderer.renderState(), renderer.caches(), &glop)
.setRoundRectClipState(state.roundRectClipState)
.setMeshTexturedUvQuad(nullptr, Rect(0, 1, 1, 0)) // TODO: simplify with VBO
.setFillTextureLayer(*(op.layer), alpha)
.setTransform(state.computedState.transform, TransformFlags::None)
.setModelViewMapUnitToRectOptionalSnap(tryToSnap, Rect(op.layer->getWidth(), op.layer->getHeight()))
.build();
renderer.renderGlop(state, glop);
}
void BakedOpDispatcher::onLayerOp(BakedOpRenderer& renderer, const LayerOp& op, const BakedOpState& state) {
OffscreenBuffer* buffer = *op.layerHandle;

View File

@@ -53,8 +53,7 @@ void DeferredLayerUpdater::setPaint(const SkPaint* paint) {
SkRefCnt_SafeAssign(mColorFilter, colorFilter);
}
bool DeferredLayerUpdater::apply() {
bool success = true;
void DeferredLayerUpdater::apply() {
// These properties are applied the same to both layer types
mLayer->setColorFilter(mColorFilter);
mLayer->setAlpha(mAlpha, mMode);
@@ -73,7 +72,6 @@ bool DeferredLayerUpdater::apply() {
setTransform(nullptr);
}
}
return success;
}
void DeferredLayerUpdater::doUpdateTexImage() {

View File

@@ -77,13 +77,13 @@ public:
ANDROID_API void setPaint(const SkPaint* paint);
ANDROID_API bool apply();
void apply();
Layer* backingLayer() {
return mLayer;
}
ANDROID_API void detachSurfaceTexture();
void detachSurfaceTexture();
private:
// Generic properties

View File

@@ -287,7 +287,7 @@ Layer* LayerRenderer::createTextureLayer(RenderState& renderState) {
}
void LayerRenderer::updateTextureLayer(Layer* layer, uint32_t width, uint32_t height,
bool isOpaque, bool forceFilter, GLenum renderTarget, float* textureTransform) {
bool isOpaque, bool forceFilter, GLenum renderTarget, const float* textureTransform) {
if (layer) {
layer->setBlend(!isOpaque);
layer->setForceFilter(forceFilter);

View File

@@ -59,7 +59,7 @@ public:
static Layer* createRenderLayer(RenderState& renderState, uint32_t width, uint32_t height);
static bool resizeLayer(Layer* layer, uint32_t width, uint32_t height);
static void updateTextureLayer(Layer* layer, uint32_t width, uint32_t height,
bool isOpaque, bool forceFilter, GLenum renderTarget, float* textureTransform);
bool isOpaque, bool forceFilter, GLenum renderTarget, const float* textureTransform);
static void destroyLayer(Layer* layer);
static bool copyLayer(RenderState& renderState, Layer* layer, SkBitmap* bitmap);

View File

@@ -139,9 +139,11 @@ public:
}
void multiply(const Matrix4& v) {
Matrix4 u;
u.loadMultiply(*this, v);
*this = u;
if (!v.isIdentity()) {
Matrix4 u;
u.loadMultiply(*this, v);
*this = u;
}
}
void multiply(float v);

View File

@@ -783,7 +783,7 @@ void OpReorderer::deferCirclePropsOp(const CirclePropsOp& op) {
void OpReorderer::deferFunctorOp(const FunctorOp& op) {
BakedOpState* bakedState = tryBakeOpState(op);
if (!bakedState) return; // quick rejected
currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::None);
currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::Functor);
}
void OpReorderer::deferLinesOp(const LinesOp& op) {
@@ -871,6 +871,12 @@ void OpReorderer::deferTextOnPathOp(const TextOnPathOp& op) {
currentLayer().deferUnmergeableOp(mAllocator, bakedState, textBatchId(*(op.paint)));
}
void OpReorderer::deferTextureLayerOp(const TextureLayerOp& op) {
BakedOpState* bakedState = tryBakeOpState(op);
if (!bakedState) return; // quick rejected
currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::TextureLayer);
}
void OpReorderer::saveForLayer(uint32_t layerWidth, uint32_t layerHeight,
float contentTranslateX, float contentTranslateY,
const Rect& repaintRect,

View File

@@ -43,7 +43,6 @@ typedef const void* mergeid_t;
namespace OpBatchType {
enum {
None = 0, // Don't batch
Bitmap,
MergedPatch,
AlphaVertices,
@@ -52,6 +51,8 @@ namespace OpBatchType {
Text,
ColorText,
Shadow,
TextureLayer,
Functor,
Count // must be last
};

View File

@@ -63,6 +63,7 @@ struct Vertex;
U_OP_FN(SimpleRectsOp) \
M_OP_FN(TextOp) \
U_OP_FN(TextOnPathOp) \
U_OP_FN(TextureLayerOp) \
U_OP_FN(BeginLayerOp) \
U_OP_FN(EndLayerOp) \
U_OP_FN(LayerOp)
@@ -345,11 +346,17 @@ struct TextOnPathOp : RecordedOp {
const float vOffset;
};
struct TextureLayerOp : RecordedOp {
TextureLayerOp(BASE_PARAMS_PAINTLESS, Layer* layer)
: SUPER_PAINTLESS(TextureLayerOp)
, layer(layer) {}
Layer* layer;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
// Layers
////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Stateful operation! denotes the creation of an off-screen layer,
* and that commands following will render into it.

View File

@@ -16,6 +16,7 @@
#include "RecordingCanvas.h"
#include "DeferredLayerUpdater.h"
#include "RecordedOp.h"
#include "RenderNode.h"
@@ -542,6 +543,21 @@ void RecordingCanvas::drawRenderNode(RenderNode* renderNode) {
}
}
void RecordingCanvas::drawLayer(DeferredLayerUpdater* layerHandle) {
// We ref the DeferredLayerUpdater due to its thread-safe ref-counting semantics.
mDisplayList->ref(layerHandle);
Layer* layer = layerHandle->backingLayer();
Matrix4 totalTransform(*(mState.currentSnapshot()->transform));
totalTransform.multiply(layer->getTransform());
addOp(new (alloc()) TextureLayerOp(
Rect(layer->getWidth(), layer->getHeight()),
totalTransform,
mState.getRenderTargetClipBounds(),
layer));
}
void RecordingCanvas::callDrawGLFunction(Functor* functor) {
mDisplayList->functors.push_back(functor);
addOp(new (alloc()) FunctorOp(

View File

@@ -36,7 +36,7 @@
namespace android {
namespace uirenderer {
class OpReceiver;
class DeferredLayerUpdater;
struct RecordedOp;
class RecordingCanvas: public Canvas, public CanvasStateClient {
@@ -59,6 +59,8 @@ public:
mDeferredBarrierType = enableReorder
? DeferredBarrierType::OutOfOrder : DeferredBarrierType::InOrder;
}
void drawLayer(DeferredLayerUpdater* layerHandle);
void drawRenderNode(RenderNode* renderNode);
// TODO: rename for consistency

View File

@@ -182,16 +182,6 @@ void CanvasContext::makeCurrent() {
}
}
void CanvasContext::processLayerUpdate(DeferredLayerUpdater* layerUpdater) {
#if !HWUI_NEW_OPS
bool success = layerUpdater->apply();
LOG_ALWAYS_FATAL_IF(!success, "Failed to update layer!");
if (layerUpdater->backingLayer()->deferredUpdateScheduled) {
mCanvas->pushLayerUpdate(layerUpdater->backingLayer());
}
#endif
}
static bool wasSkipped(FrameInfo* info) {
return info && ((*info)[FrameInfoIndex::Flags] & FrameInfoFlags::SkippedFrame);
}

View File

@@ -83,7 +83,6 @@ public:
void setLightCenter(const Vector3& lightCenter);
void setOpaque(bool opaque);
void makeCurrent();
void processLayerUpdate(DeferredLayerUpdater* layerUpdater);
void prepareTree(TreeInfo& info, int64_t* uiFrameInfo,
int64_t syncQueued, RenderNode* target);
void draw();

View File

@@ -117,7 +117,7 @@ bool DrawFrameTask::syncFrameState(TreeInfo& info) {
Caches::getInstance().textureCache.resetMarkInUse(mContext);
for (size_t i = 0; i < mLayers.size(); i++) {
mContext->processLayerUpdate(mLayers[i].get());
mLayers[i]->apply();
}
mLayers.clear();
mContext->prepareTree(info, mFrameInfo, mSyncQueued, mTargetNode);

View File

@@ -16,6 +16,9 @@
#include "TestUtils.h"
#include "DeferredLayerUpdater.h"
#include "LayerRenderer.h"
namespace android {
namespace uirenderer {
@@ -36,6 +39,22 @@ SkColor TestUtils::interpolateColor(float fraction, SkColor start, SkColor end)
| (int)((startB + (int)(fraction * (endB - startB))));
}
sp<DeferredLayerUpdater> TestUtils::createTextureLayerUpdater(
renderthread::RenderThread& renderThread, uint32_t width, uint32_t height,
std::function<void(Matrix4*)> transformSetupCallback) {
bool isOpaque = true;
bool forceFilter = true;
GLenum renderTarget = GL_TEXTURE_EXTERNAL_OES;
Layer* layer = LayerRenderer::createTextureLayer(renderThread.renderState());
LayerRenderer::updateTextureLayer(layer, width, height, isOpaque, forceFilter,
renderTarget, Matrix4::identity().data);
transformSetupCallback(&(layer->getTransform()));
sp<DeferredLayerUpdater> layerUpdater = new DeferredLayerUpdater(layer);
return layerUpdater;
}
void TestUtils::drawTextToCanvas(TestCanvas* canvas, const char* text,
const SkPaint& paint, float x, float y) {
// drawing text requires GlyphID TextEncoding (which JNI layer would have done)

View File

@@ -113,6 +113,10 @@ public:
return bitmap;
}
static sp<DeferredLayerUpdater> createTextureLayerUpdater(
renderthread::RenderThread& renderThread, uint32_t width, uint32_t height,
std::function<void(Matrix4*)> transformSetupCallback);
template<class CanvasType>
static std::unique_ptr<DisplayList> createDisplayList(int width, int height,
std::function<void(CanvasType& canvas)> canvasCallback) {

View File

@@ -17,6 +17,7 @@
#include <gtest/gtest.h>
#include <BakedOpState.h>
#include <DeferredLayerUpdater.h>
#include <LayerUpdateQueue.h>
#include <OpReorderer.h>
#include <RecordedOp.h>
@@ -281,6 +282,39 @@ TEST(OpReorderer, textStrikethrough) {
<< "Expect number of ops = 2 * loop count";
}
RENDERTHREAD_TEST(OpReorderer, textureLayer) {
class TextureLayerTestRenderer : public TestRendererBase {
public:
void onTextureLayerOp(const TextureLayerOp& op, const BakedOpState& state) override {
EXPECT_EQ(0, mIndex++);
EXPECT_EQ(Rect(50, 50, 150, 150), state.computedState.clipRect);
EXPECT_EQ(Rect(50, 50, 105, 105), state.computedState.clippedBounds);
Matrix4 expected;
expected.loadTranslate(5, 5, 0);
EXPECT_MATRIX_APPROX_EQ(expected, state.computedState.transform);
}
};
auto layerUpdater = TestUtils::createTextureLayerUpdater(renderThread, 100, 100,
[](Matrix4* transform) {
transform->loadTranslate(5, 5, 0);
});
auto node = TestUtils::createNode(0, 0, 200, 200,
[&layerUpdater](RenderProperties& props, RecordingCanvas& canvas) {
canvas.save(SkCanvas::kMatrixClip_SaveFlag);
canvas.clipRect(50, 50, 150, 150, SkRegion::kIntersect_Op);
canvas.drawLayer(layerUpdater.get());
canvas.restore();
});
OpReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
createSyncedNodeList(node), sLightCenter);
TextureLayerTestRenderer renderer;
reorderer.replayBakedOps<TestDispatcher>(renderer);
EXPECT_EQ(1, renderer.getIndex());
}
TEST(OpReorderer, renderNode) {
class RenderNodeTestRenderer : public TestRendererBase {
public:
@@ -307,16 +341,15 @@ TEST(OpReorderer, renderNode) {
canvas.drawRect(0, 0, 100, 100, paint);
});
RenderNode* childPtr = child.get();
auto parent = TestUtils::createNode(0, 0, 200, 200,
[childPtr](RenderProperties& props, RecordingCanvas& canvas) {
[&child](RenderProperties& props, RecordingCanvas& canvas) {
SkPaint paint;
paint.setColor(SK_ColorDKGRAY);
canvas.drawRect(0, 0, 200, 200, paint);
canvas.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
canvas.translate(40, 40);
canvas.drawRenderNode(childPtr);
canvas.drawRenderNode(child.get());
canvas.restore();
});