RecordedOp.h revision ec4a4b13eae2241d1613890c1c1c096bed891845
1/* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#pragma once 18 19#include "font/FontUtil.h" 20#include "Matrix.h" 21#include "Rect.h" 22#include "RenderNode.h" 23#include "TessellationCache.h" 24#include "utils/LinearAllocator.h" 25#include "utils/PaintUtils.h" 26#include "Vector.h" 27 28#include <androidfw/ResourceTypes.h> 29 30class SkBitmap; 31class SkPaint; 32 33namespace android { 34namespace uirenderer { 35 36struct ClipBase; 37class OffscreenBuffer; 38class RenderNode; 39struct Vertex; 40 41namespace VectorDrawable { 42class Tree; 43} 44 45/** 46 * Authoritative op list, used for generating the op ID enum, ID based LUTS, and 47 * the functions to which they dispatch. Parameter macros are executed for each op, 48 * in order, based on the op's type. 49 * 50 * There are 4 types of op, which defines dispatch/LUT capability: 51 * 52 * | DisplayList | Render | Merge | 53 * -------------|-------------|-------------|-------------| 54 * PRE RENDER | Yes | | | 55 * RENDER ONLY | | Yes | | 56 * UNMERGEABLE | Yes | Yes | | 57 * MERGEABLE | Yes | Yes | Yes | 58 * 59 * PRE RENDER - These ops are recorded into DisplayLists, but can't be directly rendered. This 60 * may be because they need to be transformed into other op types (e.g. CirclePropsOp), 61 * be traversed to access multiple renderable ops within (e.g. RenderNodeOp), or because they 62 * modify renderbuffer lifecycle, instead of directly rendering content (the various LayerOps). 63 * 64 * RENDER ONLY - These ops cannot be recorded into DisplayLists, and are instead implicitly 65 * constructed from other commands/RenderNode properties. They cannot be merged. 66 * 67 * UNMERGEABLE - These ops can be recorded into DisplayLists and rendered directly, but do not 68 * support merged rendering. 69 * 70 * MERGEABLE - These ops can be recorded into DisplayLists and rendered individually, or merged 71 * under certain circumstances. 72 */ 73#define MAP_OPS_BASED_ON_TYPE(PRE_RENDER_OP_FN, RENDER_ONLY_OP_FN, UNMERGEABLE_OP_FN, MERGEABLE_OP_FN) \ 74 PRE_RENDER_OP_FN(RenderNodeOp) \ 75 PRE_RENDER_OP_FN(CirclePropsOp) \ 76 PRE_RENDER_OP_FN(RoundRectPropsOp) \ 77 PRE_RENDER_OP_FN(BeginLayerOp) \ 78 PRE_RENDER_OP_FN(EndLayerOp) \ 79 PRE_RENDER_OP_FN(BeginUnclippedLayerOp) \ 80 PRE_RENDER_OP_FN(EndUnclippedLayerOp) \ 81 PRE_RENDER_OP_FN(VectorDrawableOp) \ 82 \ 83 RENDER_ONLY_OP_FN(ShadowOp) \ 84 RENDER_ONLY_OP_FN(LayerOp) \ 85 RENDER_ONLY_OP_FN(CopyToLayerOp) \ 86 RENDER_ONLY_OP_FN(CopyFromLayerOp) \ 87 \ 88 UNMERGEABLE_OP_FN(ArcOp) \ 89 UNMERGEABLE_OP_FN(BitmapMeshOp) \ 90 UNMERGEABLE_OP_FN(BitmapRectOp) \ 91 UNMERGEABLE_OP_FN(ColorOp) \ 92 UNMERGEABLE_OP_FN(FunctorOp) \ 93 UNMERGEABLE_OP_FN(LinesOp) \ 94 UNMERGEABLE_OP_FN(OvalOp) \ 95 UNMERGEABLE_OP_FN(PathOp) \ 96 UNMERGEABLE_OP_FN(PointsOp) \ 97 UNMERGEABLE_OP_FN(RectOp) \ 98 UNMERGEABLE_OP_FN(RoundRectOp) \ 99 UNMERGEABLE_OP_FN(SimpleRectsOp) \ 100 UNMERGEABLE_OP_FN(TextOnPathOp) \ 101 UNMERGEABLE_OP_FN(TextureLayerOp) \ 102 \ 103 MERGEABLE_OP_FN(BitmapOp) \ 104 MERGEABLE_OP_FN(PatchOp) \ 105 MERGEABLE_OP_FN(TextOp) 106 107/** 108 * LUT generators, which will insert nullptr for unsupported ops 109 */ 110#define NULLPTR_OP_FN(Type) nullptr, 111 112#define BUILD_DEFERRABLE_OP_LUT(OP_FN) \ 113 { MAP_OPS_BASED_ON_TYPE(OP_FN, NULLPTR_OP_FN, OP_FN, OP_FN) } 114 115#define BUILD_MERGEABLE_OP_LUT(OP_FN) \ 116 { MAP_OPS_BASED_ON_TYPE(NULLPTR_OP_FN, NULLPTR_OP_FN, NULLPTR_OP_FN, OP_FN) } 117 118#define BUILD_RENDERABLE_OP_LUT(OP_FN) \ 119 { MAP_OPS_BASED_ON_TYPE(NULLPTR_OP_FN, OP_FN, OP_FN, OP_FN) } 120 121#define BUILD_FULL_OP_LUT(OP_FN) \ 122 { MAP_OPS_BASED_ON_TYPE(OP_FN, OP_FN, OP_FN, OP_FN) } 123 124/** 125 * Op mapping functions, which skip unsupported ops. 126 * 127 * Note: Do not use for LUTS, since these do not preserve ID order. 128 */ 129#define NULL_OP_FN(Type) 130 131#define MAP_DEFERRABLE_OPS(OP_FN) \ 132 MAP_OPS_BASED_ON_TYPE(OP_FN, NULL_OP_FN, OP_FN, OP_FN) 133 134#define MAP_MERGEABLE_OPS(OP_FN) \ 135 MAP_OPS_BASED_ON_TYPE(NULL_OP_FN, NULL_OP_FN, NULL_OP_FN, OP_FN) 136 137#define MAP_RENDERABLE_OPS(OP_FN) \ 138 MAP_OPS_BASED_ON_TYPE(NULL_OP_FN, OP_FN, OP_FN, OP_FN) 139 140// Generate OpId enum 141#define IDENTITY_FN(Type) Type, 142namespace RecordedOpId { 143 enum { 144 MAP_OPS_BASED_ON_TYPE(IDENTITY_FN, IDENTITY_FN, IDENTITY_FN, IDENTITY_FN) 145 Count, 146 }; 147} 148static_assert(RecordedOpId::RenderNodeOp == 0, 149 "First index must be zero for LUTs to work"); 150 151#define BASE_PARAMS const Rect& unmappedBounds, const Matrix4& localMatrix, const ClipBase* localClip, const SkPaint* paint 152#define BASE_PARAMS_PAINTLESS const Rect& unmappedBounds, const Matrix4& localMatrix, const ClipBase* localClip 153#define SUPER(Type) RecordedOp(RecordedOpId::Type, unmappedBounds, localMatrix, localClip, paint) 154#define SUPER_PAINTLESS(Type) RecordedOp(RecordedOpId::Type, unmappedBounds, localMatrix, localClip, nullptr) 155 156struct RecordedOp { 157 /* ID from RecordedOpId - generally used for jumping into function tables */ 158 const int opId; 159 160 /* bounds in *local* space, without accounting for DisplayList transformation, or stroke */ 161 const Rect unmappedBounds; 162 163 /* transform in recording space (vs DisplayList origin) */ 164 const Matrix4 localMatrix; 165 166 /* clip in recording space - nullptr if not clipped */ 167 const ClipBase* localClip; 168 169 /* optional paint, stored in base object to simplify merging logic */ 170 const SkPaint* paint; 171protected: 172 RecordedOp(unsigned int opId, BASE_PARAMS) 173 : opId(opId) 174 , unmappedBounds(unmappedBounds) 175 , localMatrix(localMatrix) 176 , localClip(localClip) 177 , paint(paint) {} 178}; 179 180struct RenderNodeOp : RecordedOp { 181 RenderNodeOp(BASE_PARAMS_PAINTLESS, RenderNode* renderNode) 182 : SUPER_PAINTLESS(RenderNodeOp) 183 , renderNode(renderNode) {} 184 RenderNode * renderNode; // not const, since drawing modifies it 185 186 /** 187 * Holds the transformation between the projection surface ViewGroup and this RenderNode 188 * drawing instance. Represents any translations / transformations done within the drawing of 189 * the compositing ancestor ViewGroup's draw, before the draw of the View represented by this 190 * DisplayList draw instance. 191 * 192 * Note: doesn't include transformation within the RenderNode, or its properties. 193 */ 194 Matrix4 transformFromCompositingAncestor; 195 bool skipInOrderDraw = false; 196}; 197 198//////////////////////////////////////////////////////////////////////////////////////////////////// 199// Standard Ops 200//////////////////////////////////////////////////////////////////////////////////////////////////// 201 202struct ArcOp : RecordedOp { 203 ArcOp(BASE_PARAMS, float startAngle, float sweepAngle, bool useCenter) 204 : SUPER(ArcOp) 205 , startAngle(startAngle) 206 , sweepAngle(sweepAngle) 207 , useCenter(useCenter) {} 208 const float startAngle; 209 const float sweepAngle; 210 const bool useCenter; 211}; 212 213struct BitmapOp : RecordedOp { 214 BitmapOp(BASE_PARAMS, Bitmap* bitmap) 215 : SUPER(BitmapOp) 216 , bitmap(bitmap) {} 217 Bitmap* bitmap; 218}; 219 220struct BitmapMeshOp : RecordedOp { 221 BitmapMeshOp(BASE_PARAMS, Bitmap* bitmap, int meshWidth, int meshHeight, 222 const float* vertices, const int* colors) 223 : SUPER(BitmapMeshOp) 224 , bitmap(bitmap) 225 , meshWidth(meshWidth) 226 , meshHeight(meshHeight) 227 , vertices(vertices) 228 , colors(colors) {} 229 Bitmap* bitmap; 230 const int meshWidth; 231 const int meshHeight; 232 const float* vertices; 233 const int* colors; 234}; 235 236struct BitmapRectOp : RecordedOp { 237 BitmapRectOp(BASE_PARAMS, Bitmap* bitmap, const Rect& src) 238 : SUPER(BitmapRectOp) 239 , bitmap(bitmap) 240 , src(src) {} 241 Bitmap* bitmap; 242 const Rect src; 243}; 244 245struct CirclePropsOp : RecordedOp { 246 CirclePropsOp(const Matrix4& localMatrix, const ClipBase* localClip, const SkPaint* paint, 247 float* x, float* y, float* radius) 248 : RecordedOp(RecordedOpId::CirclePropsOp, Rect(), localMatrix, localClip, paint) 249 , x(x) 250 , y(y) 251 , radius(radius) {} 252 const float* x; 253 const float* y; 254 const float* radius; 255}; 256 257struct ColorOp : RecordedOp { 258 // Note: unbounded op that will fillclip, so no bounds/matrix needed 259 ColorOp(const ClipBase* localClip, int color, SkBlendMode mode) 260 : RecordedOp(RecordedOpId::ColorOp, Rect(), Matrix4::identity(), localClip, nullptr) 261 , color(color) 262 , mode(mode) {} 263 const int color; 264 const SkBlendMode mode; 265}; 266 267struct FunctorOp : RecordedOp { 268 // Note: undefined record-time bounds, since this op fills the clip 269 // TODO: explicitly define bounds 270 FunctorOp(const Matrix4& localMatrix, const ClipBase* localClip, Functor* functor) 271 : RecordedOp(RecordedOpId::FunctorOp, Rect(), localMatrix, localClip, nullptr) 272 , functor(functor) {} 273 Functor* functor; 274}; 275 276struct LinesOp : RecordedOp { 277 LinesOp(BASE_PARAMS, const float* points, const int floatCount) 278 : SUPER(LinesOp) 279 , points(points) 280 , floatCount(floatCount) {} 281 const float* points; 282 const int floatCount; 283}; 284 285struct OvalOp : RecordedOp { 286 OvalOp(BASE_PARAMS) 287 : SUPER(OvalOp) {} 288}; 289 290struct PatchOp : RecordedOp { 291 PatchOp(BASE_PARAMS, Bitmap* bitmap, const Res_png_9patch* patch) 292 : SUPER(PatchOp) 293 , bitmap(bitmap) 294 , patch(patch) {} 295 Bitmap* bitmap; 296 const Res_png_9patch* patch; 297}; 298 299struct PathOp : RecordedOp { 300 PathOp(BASE_PARAMS, const SkPath* path) 301 : SUPER(PathOp) 302 , path(path) {} 303 const SkPath* path; 304}; 305 306struct PointsOp : RecordedOp { 307 PointsOp(BASE_PARAMS, const float* points, const int floatCount) 308 : SUPER(PointsOp) 309 , points(points) 310 , floatCount(floatCount) {} 311 const float* points; 312 const int floatCount; 313}; 314 315struct RectOp : RecordedOp { 316 RectOp(BASE_PARAMS) 317 : SUPER(RectOp) {} 318}; 319 320struct RoundRectOp : RecordedOp { 321 RoundRectOp(BASE_PARAMS, float rx, float ry) 322 : SUPER(RoundRectOp) 323 , rx(rx) 324 , ry(ry) {} 325 const float rx; 326 const float ry; 327}; 328 329struct RoundRectPropsOp : RecordedOp { 330 RoundRectPropsOp(const Matrix4& localMatrix, const ClipBase* localClip, const SkPaint* paint, 331 float* left, float* top, float* right, float* bottom, float *rx, float *ry) 332 : RecordedOp(RecordedOpId::RoundRectPropsOp, Rect(), localMatrix, localClip, paint) 333 , left(left) 334 , top(top) 335 , right(right) 336 , bottom(bottom) 337 , rx(rx) 338 , ry(ry) {} 339 const float* left; 340 const float* top; 341 const float* right; 342 const float* bottom; 343 const float* rx; 344 const float* ry; 345}; 346 347struct VectorDrawableOp : RecordedOp { 348 VectorDrawableOp(VectorDrawable::Tree* tree, BASE_PARAMS_PAINTLESS) 349 : SUPER_PAINTLESS(VectorDrawableOp) 350 , vectorDrawable(tree) {} 351 VectorDrawable::Tree* vectorDrawable; 352}; 353 354/** 355 * Real-time, dynamic-lit shadow. 356 * 357 * Uses invalid/empty bounds and matrix since ShadowOp bounds aren't known at defer time, 358 * and are resolved dynamically, and transform isn't needed. 359 * 360 * State construction handles these properties specially, ignoring matrix/bounds. 361 */ 362struct ShadowOp : RecordedOp { 363 ShadowOp(sp<TessellationCache::ShadowTask>& shadowTask, float casterAlpha) 364 : RecordedOp(RecordedOpId::ShadowOp, Rect(), Matrix4::identity(), nullptr, nullptr) 365 , shadowTask(shadowTask) 366 , casterAlpha(casterAlpha) { 367 }; 368 sp<TessellationCache::ShadowTask> shadowTask; 369 const float casterAlpha; 370}; 371 372struct SimpleRectsOp : RecordedOp { // Filled, no AA (TODO: better name?) 373 SimpleRectsOp(BASE_PARAMS, Vertex* vertices, size_t vertexCount) 374 : SUPER(SimpleRectsOp) 375 , vertices(vertices) 376 , vertexCount(vertexCount) {} 377 Vertex* vertices; 378 const size_t vertexCount; 379}; 380 381struct TextOp : RecordedOp { 382 TextOp(BASE_PARAMS, const glyph_t* glyphs, const float* positions, int glyphCount, 383 float x, float y) 384 : SUPER(TextOp) 385 , glyphs(glyphs) 386 , positions(positions) 387 , glyphCount(glyphCount) 388 , x(x) 389 , y(y) {} 390 const glyph_t* glyphs; 391 const float* positions; 392 const int glyphCount; 393 const float x; 394 const float y; 395}; 396 397struct TextOnPathOp : RecordedOp { 398 // TODO: explicitly define bounds 399 TextOnPathOp(const Matrix4& localMatrix, const ClipBase* localClip, const SkPaint* paint, 400 const glyph_t* glyphs, int glyphCount, const SkPath* path, float hOffset, float vOffset) 401 : RecordedOp(RecordedOpId::TextOnPathOp, Rect(), localMatrix, localClip, paint) 402 , glyphs(glyphs) 403 , glyphCount(glyphCount) 404 , path(path) 405 , hOffset(hOffset) 406 , vOffset(vOffset) {} 407 const glyph_t* glyphs; 408 const int glyphCount; 409 410 const SkPath* path; 411 const float hOffset; 412 const float vOffset; 413}; 414 415struct TextureLayerOp : RecordedOp { 416 TextureLayerOp(BASE_PARAMS_PAINTLESS, Layer* layer) 417 : SUPER_PAINTLESS(TextureLayerOp) 418 , layer(layer) {} 419 420 // Copy an existing TextureLayerOp, replacing the underlying matrix 421 TextureLayerOp(const TextureLayerOp& op, const Matrix4& replacementMatrix) 422 : RecordedOp(RecordedOpId::TextureLayerOp, op.unmappedBounds, replacementMatrix, 423 op.localClip, op.paint) 424 , layer(op.layer) { 425 426 } 427 Layer* layer; 428}; 429 430//////////////////////////////////////////////////////////////////////////////////////////////////// 431// Layers 432//////////////////////////////////////////////////////////////////////////////////////////////////// 433 434/** 435 * Stateful operation! denotes the creation of an off-screen layer, 436 * and that commands following will render into it. 437 */ 438struct BeginLayerOp : RecordedOp { 439 BeginLayerOp(BASE_PARAMS) 440 : SUPER(BeginLayerOp) {} 441}; 442 443/** 444 * Stateful operation! Denotes end of off-screen layer, and that 445 * commands since last BeginLayerOp should be drawn into parent FBO. 446 * 447 * State in this op is empty, it just serves to signal that a layer has been finished. 448 */ 449struct EndLayerOp : RecordedOp { 450 EndLayerOp() 451 : RecordedOp(RecordedOpId::EndLayerOp, Rect(), Matrix4::identity(), nullptr, nullptr) {} 452}; 453 454struct BeginUnclippedLayerOp : RecordedOp { 455 BeginUnclippedLayerOp(BASE_PARAMS) 456 : SUPER(BeginUnclippedLayerOp) {} 457}; 458 459struct EndUnclippedLayerOp : RecordedOp { 460 EndUnclippedLayerOp() 461 : RecordedOp(RecordedOpId::EndUnclippedLayerOp, Rect(), Matrix4::identity(), nullptr, nullptr) {} 462}; 463 464struct CopyToLayerOp : RecordedOp { 465 CopyToLayerOp(const RecordedOp& op, OffscreenBuffer** layerHandle) 466 : RecordedOp(RecordedOpId::CopyToLayerOp, 467 op.unmappedBounds, 468 op.localMatrix, 469 nullptr, // clip intentionally ignored 470 op.paint) 471 , layerHandle(layerHandle) {} 472 473 // Records a handle to the Layer object, since the Layer itself won't be 474 // constructed until after this operation is constructed. 475 OffscreenBuffer** layerHandle; 476}; 477 478 479// draw the parameter layer underneath 480struct CopyFromLayerOp : RecordedOp { 481 CopyFromLayerOp(const RecordedOp& op, OffscreenBuffer** layerHandle) 482 : RecordedOp(RecordedOpId::CopyFromLayerOp, 483 op.unmappedBounds, 484 op.localMatrix, 485 nullptr, // clip intentionally ignored 486 op.paint) 487 , layerHandle(layerHandle) {} 488 489 // Records a handle to the Layer object, since the Layer itself won't be 490 // constructed until after this operation is constructed. 491 OffscreenBuffer** layerHandle; 492}; 493 494/** 495 * Draws an OffscreenBuffer. 496 * 497 * Alpha, mode, and colorfilter are embedded, since LayerOps are always dynamically generated, 498 * when creating/tracking a SkPaint* during defer isn't worth the bother. 499 */ 500struct LayerOp : RecordedOp { 501 // Records a one-use (saveLayer) layer for drawing. 502 LayerOp(BASE_PARAMS, OffscreenBuffer** layerHandle) 503 : SUPER_PAINTLESS(LayerOp) 504 , layerHandle(layerHandle) 505 , alpha(paint ? paint->getAlpha() / 255.0f : 1.0f) 506 , mode(PaintUtils::getBlendModeDirect(paint)) 507 , colorFilter(paint ? paint->getColorFilter() : nullptr) {} 508 509 explicit LayerOp(RenderNode& node) 510 : RecordedOp(RecordedOpId::LayerOp, Rect(node.getWidth(), node.getHeight()), Matrix4::identity(), nullptr, nullptr) 511 , layerHandle(node.getLayerHandle()) 512 , alpha(node.properties().layerProperties().alpha() / 255.0f) 513 , mode(node.properties().layerProperties().xferMode()) 514 , colorFilter(node.properties().layerProperties().colorFilter()) {} 515 516 // Records a handle to the Layer object, since the Layer itself won't be 517 // constructed until after this operation is constructed. 518 OffscreenBuffer** layerHandle; 519 const float alpha; 520 const SkBlendMode mode; 521 522 // pointer to object owned by either LayerProperties, or a recorded Paint object in a 523 // BeginLayerOp. Lives longer than LayerOp in either case, so no skia ref counting is used. 524 SkColorFilter* colorFilter; 525}; 526 527}; // namespace uirenderer 528}; // namespace android 529