blob: b243f990d27d2aabe3550457660250706bacbece [file] [log] [blame]
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef ANDROID_HWUI_RECORDED_OP_H
#define ANDROID_HWUI_RECORDED_OP_H
#include "font/FontUtil.h"
#include "Matrix.h"
#include "Rect.h"
#include "RenderNode.h"
#include "utils/LinearAllocator.h"
#include "Vector.h"
#include <androidfw/ResourceTypes.h>
#include <SkXfermode.h>
class SkBitmap;
class SkPaint;
namespace android {
namespace uirenderer {
struct ClipBase;
class OffscreenBuffer;
class RenderNode;
struct Vertex;
/**
* Authoritative op list, used for generating the op ID enum, ID based LUTS, and
* the functions to which they dispatch. Parameter macros are executed for each op,
* in order, based on the op's type.
*
* There are 4 types of op:
*
* Pre render - not directly consumed by renderer, reorder stage resolves this into renderable type
* Render only - generated renderable ops - never passed to a reorderer
* Unmergeable - reorderable, renderable (but not mergeable)
* Mergeable - reorderable, renderable (and mergeable)
*/
#define MAP_OPS_BASED_ON_TYPE(PRE_RENDER_OP_FN, RENDER_ONLY_OP_FN, UNMERGEABLE_OP_FN, MERGEABLE_OP_FN) \
PRE_RENDER_OP_FN(RenderNodeOp) \
PRE_RENDER_OP_FN(CirclePropsOp) \
PRE_RENDER_OP_FN(RoundRectPropsOp) \
PRE_RENDER_OP_FN(BeginLayerOp) \
PRE_RENDER_OP_FN(EndLayerOp) \
\
RENDER_ONLY_OP_FN(ShadowOp) \
RENDER_ONLY_OP_FN(LayerOp) \
\
UNMERGEABLE_OP_FN(ArcOp) \
UNMERGEABLE_OP_FN(BitmapMeshOp) \
UNMERGEABLE_OP_FN(BitmapRectOp) \
UNMERGEABLE_OP_FN(FunctorOp) \
UNMERGEABLE_OP_FN(LinesOp) \
UNMERGEABLE_OP_FN(OvalOp) \
UNMERGEABLE_OP_FN(PathOp) \
UNMERGEABLE_OP_FN(PointsOp) \
UNMERGEABLE_OP_FN(RectOp) \
UNMERGEABLE_OP_FN(RoundRectOp) \
UNMERGEABLE_OP_FN(SimpleRectsOp) \
UNMERGEABLE_OP_FN(TextOnPathOp) \
UNMERGEABLE_OP_FN(TextureLayerOp) \
\
MERGEABLE_OP_FN(BitmapOp) \
MERGEABLE_OP_FN(PatchOp) \
MERGEABLE_OP_FN(TextOp)
/**
* LUT generators, which will insert nullptr for unsupported ops
*/
#define NULLPTR_OP_FN(Type) nullptr,
#define BUILD_DEFERRABLE_OP_LUT(OP_FN) \
{ MAP_OPS_BASED_ON_TYPE(OP_FN, NULLPTR_OP_FN, OP_FN, OP_FN) }
#define BUILD_MERGEABLE_OP_LUT(OP_FN) \
{ MAP_OPS_BASED_ON_TYPE(NULLPTR_OP_FN, NULLPTR_OP_FN, NULLPTR_OP_FN, OP_FN) }
#define BUILD_RENDERABLE_OP_LUT(OP_FN) \
{ MAP_OPS_BASED_ON_TYPE(NULLPTR_OP_FN, OP_FN, OP_FN, OP_FN) }
/**
* Op mapping functions, which skip unsupported ops.
*
* Note: Do not use for LUTS, since these do not preserve ID order.
*/
#define NULL_OP_FN(Type)
#define MAP_MERGEABLE_OPS(OP_FN) \
MAP_OPS_BASED_ON_TYPE(NULL_OP_FN, NULL_OP_FN, NULL_OP_FN, OP_FN)
#define MAP_RENDERABLE_OPS(OP_FN) \
MAP_OPS_BASED_ON_TYPE(NULL_OP_FN, OP_FN, OP_FN, OP_FN)
#define MAP_DEFERRABLE_OPS(OP_FN) \
MAP_OPS_BASED_ON_TYPE(OP_FN, NULL_OP_FN, OP_FN, OP_FN)
// Generate OpId enum
#define IDENTITY_FN(Type) Type,
namespace RecordedOpId {
enum {
MAP_OPS_BASED_ON_TYPE(IDENTITY_FN, IDENTITY_FN, IDENTITY_FN, IDENTITY_FN)
Count,
};
}
static_assert(RecordedOpId::RenderNodeOp == 0,
"First index must be zero for LUTs to work");
#define BASE_PARAMS const Rect& unmappedBounds, const Matrix4& localMatrix, const ClipBase* localClip, const SkPaint* paint
#define BASE_PARAMS_PAINTLESS const Rect& unmappedBounds, const Matrix4& localMatrix, const ClipBase* localClip
#define SUPER(Type) RecordedOp(RecordedOpId::Type, unmappedBounds, localMatrix, localClip, paint)
#define SUPER_PAINTLESS(Type) RecordedOp(RecordedOpId::Type, unmappedBounds, localMatrix, localClip, nullptr)
struct RecordedOp {
/* ID from RecordedOpId - generally used for jumping into function tables */
const int opId;
/* bounds in *local* space, without accounting for DisplayList transformation, or stroke */
const Rect unmappedBounds;
/* transform in recording space (vs DisplayList origin) */
const Matrix4 localMatrix;
/* clip in recording space - nullptr if not clipped */
const ClipBase* localClip;
/* optional paint, stored in base object to simplify merging logic */
const SkPaint* paint;
protected:
RecordedOp(unsigned int opId, BASE_PARAMS)
: opId(opId)
, unmappedBounds(unmappedBounds)
, localMatrix(localMatrix)
, localClip(localClip)
, paint(paint) {}
};
struct RenderNodeOp : RecordedOp {
RenderNodeOp(BASE_PARAMS_PAINTLESS, RenderNode* renderNode)
: SUPER_PAINTLESS(RenderNodeOp)
, renderNode(renderNode) {}
RenderNode * renderNode; // not const, since drawing modifies it
/**
* Holds the transformation between the projection surface ViewGroup and this RenderNode
* drawing instance. Represents any translations / transformations done within the drawing of
* the compositing ancestor ViewGroup's draw, before the draw of the View represented by this
* DisplayList draw instance.
*
* Note: doesn't include transformation within the RenderNode, or its properties.
*/
Matrix4 transformFromCompositingAncestor;
bool skipInOrderDraw = false;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
// Standard Ops
////////////////////////////////////////////////////////////////////////////////////////////////////
struct ArcOp : RecordedOp {
ArcOp(BASE_PARAMS, float startAngle, float sweepAngle, bool useCenter)
: SUPER(ArcOp)
, startAngle(startAngle)
, sweepAngle(sweepAngle)
, useCenter(useCenter) {}
const float startAngle;
const float sweepAngle;
const bool useCenter;
};
struct BitmapOp : RecordedOp {
BitmapOp(BASE_PARAMS, const SkBitmap* bitmap)
: SUPER(BitmapOp)
, bitmap(bitmap) {}
const SkBitmap* bitmap;
// TODO: asset atlas/texture id lookup?
};
struct BitmapMeshOp : RecordedOp {
BitmapMeshOp(BASE_PARAMS, const SkBitmap* bitmap, int meshWidth, int meshHeight,
const float* vertices, const int* colors)
: SUPER(BitmapMeshOp)
, bitmap(bitmap)
, meshWidth(meshWidth)
, meshHeight(meshHeight)
, vertices(vertices)
, colors(colors) {}
const SkBitmap* bitmap;
const int meshWidth;
const int meshHeight;
const float* vertices;
const int* colors;
};
struct BitmapRectOp : RecordedOp {
BitmapRectOp(BASE_PARAMS, const SkBitmap* bitmap, const Rect& src)
: SUPER(BitmapRectOp)
, bitmap(bitmap)
, src(src) {}
const SkBitmap* bitmap;
const Rect src;
};
struct CirclePropsOp : RecordedOp {
CirclePropsOp(const Matrix4& localMatrix, const ClipBase* localClip, const SkPaint* paint,
float* x, float* y, float* radius)
: RecordedOp(RecordedOpId::CirclePropsOp, Rect(), localMatrix, localClip, paint)
, x(x)
, y(y)
, radius(radius) {}
const float* x;
const float* y;
const float* radius;
};
struct FunctorOp : RecordedOp {
FunctorOp(BASE_PARAMS_PAINTLESS, Functor* functor)
: SUPER_PAINTLESS(FunctorOp)
, functor(functor) {}
Functor* functor;
};
struct LinesOp : RecordedOp {
LinesOp(BASE_PARAMS, const float* points, const int floatCount)
: SUPER(LinesOp)
, points(points)
, floatCount(floatCount) {}
const float* points;
const int floatCount;
};
struct OvalOp : RecordedOp {
OvalOp(BASE_PARAMS)
: SUPER(OvalOp) {}
};
struct PatchOp : RecordedOp {
PatchOp(BASE_PARAMS, const SkBitmap* bitmap, const Res_png_9patch* patch)
: SUPER(PatchOp)
, bitmap(bitmap)
, patch(patch) {}
const SkBitmap* bitmap;
const Res_png_9patch* patch;
};
struct PathOp : RecordedOp {
PathOp(BASE_PARAMS, const SkPath* path)
: SUPER(PathOp)
, path(path) {}
const SkPath* path;
};
struct PointsOp : RecordedOp {
PointsOp(BASE_PARAMS, const float* points, const int floatCount)
: SUPER(PointsOp)
, points(points)
, floatCount(floatCount) {}
const float* points;
const int floatCount;
};
struct RectOp : RecordedOp {
RectOp(BASE_PARAMS)
: SUPER(RectOp) {}
};
struct RoundRectOp : RecordedOp {
RoundRectOp(BASE_PARAMS, float rx, float ry)
: SUPER(RoundRectOp)
, rx(rx)
, ry(ry) {}
const float rx;
const float ry;
};
struct RoundRectPropsOp : RecordedOp {
RoundRectPropsOp(const Matrix4& localMatrix, const ClipBase* localClip, const SkPaint* paint,
float* left, float* top, float* right, float* bottom, float *rx, float *ry)
: RecordedOp(RecordedOpId::RoundRectPropsOp, Rect(), localMatrix, localClip, paint)
, left(left)
, top(top)
, right(right)
, bottom(bottom)
, rx(rx)
, ry(ry) {}
const float* left;
const float* top;
const float* right;
const float* bottom;
const float* rx;
const float* ry;
};
/**
* Real-time, dynamic-lit shadow.
*
* Uses invalid/empty bounds and matrix since ShadowOp bounds aren't known at defer time,
* and are resolved dynamically, and transform isn't needed.
*
* State construction handles these properties specially, ignoring matrix/bounds.
*/
struct ShadowOp : RecordedOp {
ShadowOp(const RenderNodeOp& casterOp, float casterAlpha, const SkPath* casterPath,
const Rect& localClipRect, const Vector3& lightCenter)
: RecordedOp(RecordedOpId::ShadowOp, Rect(), Matrix4::identity(), nullptr, nullptr)
, shadowMatrixXY(casterOp.localMatrix)
, shadowMatrixZ(casterOp.localMatrix)
, casterAlpha(casterAlpha)
, casterPath(casterPath)
, localClipRect(localClipRect)
, lightCenter(lightCenter) {
const RenderNode& node = *casterOp.renderNode;
node.applyViewPropertyTransforms(shadowMatrixXY, false);
node.applyViewPropertyTransforms(shadowMatrixZ, true);
};
Matrix4 shadowMatrixXY;
Matrix4 shadowMatrixZ;
const float casterAlpha;
const SkPath* casterPath;
const Rect localClipRect;
const Vector3 lightCenter;
};
struct SimpleRectsOp : RecordedOp { // Filled, no AA (TODO: better name?)
SimpleRectsOp(BASE_PARAMS, Vertex* vertices, size_t vertexCount)
: SUPER(SimpleRectsOp)
, vertices(vertices)
, vertexCount(vertexCount) {}
Vertex* vertices;
const size_t vertexCount;
};
struct TextOp : RecordedOp {
TextOp(BASE_PARAMS, const glyph_t* glyphs, const float* positions, int glyphCount,
float x, float y)
: SUPER(TextOp)
, glyphs(glyphs)
, positions(positions)
, glyphCount(glyphCount)
, x(x)
, y(y) {}
const glyph_t* glyphs;
const float* positions;
const int glyphCount;
const float x;
const float y;
};
struct TextOnPathOp : RecordedOp {
TextOnPathOp(BASE_PARAMS, const glyph_t* glyphs, int glyphCount,
const SkPath* path, float hOffset, float vOffset)
: SUPER(TextOnPathOp)
, glyphs(glyphs)
, glyphCount(glyphCount)
, path(path)
, hOffset(hOffset)
, vOffset(vOffset) {}
const glyph_t* glyphs;
const int glyphCount;
const SkPath* path;
const float hOffset;
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.
*/
struct BeginLayerOp : RecordedOp {
BeginLayerOp(BASE_PARAMS)
: SUPER(BeginLayerOp) {}
};
/**
* Stateful operation! Denotes end of off-screen layer, and that
* commands since last BeginLayerOp should be drawn into parent FBO.
*
* State in this op is empty, it just serves to signal that a layer has been finished.
*/
struct EndLayerOp : RecordedOp {
EndLayerOp()
: RecordedOp(RecordedOpId::EndLayerOp, Rect(), Matrix4::identity(), nullptr, nullptr) {}
};
/**
* Draws an OffscreenBuffer.
*
* Alpha, mode, and colorfilter are embedded, since LayerOps are always dynamically generated,
* when creating/tracking a SkPaint* during defer isn't worth the bother.
*/
struct LayerOp : RecordedOp {
// Records a one-use (saveLayer) layer for drawing. Once drawn, the layer will be destroyed.
LayerOp(BASE_PARAMS, OffscreenBuffer** layerHandle)
: SUPER_PAINTLESS(LayerOp)
, layerHandle(layerHandle)
, alpha(paint ? paint->getAlpha() / 255.0f : 1.0f)
, mode(PaintUtils::getXfermodeDirect(paint))
, colorFilter(paint ? paint->getColorFilter() : nullptr)
, destroy(true) {}
LayerOp(RenderNode& node)
: RecordedOp(RecordedOpId::LayerOp, Rect(node.getWidth(), node.getHeight()), Matrix4::identity(), nullptr, nullptr)
, layerHandle(node.getLayerHandle())
, alpha(node.properties().layerProperties().alpha() / 255.0f)
, mode(node.properties().layerProperties().xferMode())
, colorFilter(node.properties().layerProperties().colorFilter())
, destroy(false) {}
// Records a handle to the Layer object, since the Layer itself won't be
// constructed until after this operation is constructed.
OffscreenBuffer** layerHandle;
const float alpha;
const SkXfermode::Mode mode;
// pointer to object owned by either LayerProperties, or a recorded Paint object in a
// BeginLayerOp. Lives longer than LayerOp in either case, so no skia ref counting is used.
SkColorFilter* colorFilter;
// whether to destroy the layer, once rendered
const bool destroy;
};
}; // namespace uirenderer
}; // namespace android
#endif // ANDROID_HWUI_RECORDED_OP_H