[graphite] Consolidate ordering constraints into DrawOrder type

Bug: skia:12466
Change-Id: I734c3a9595948dfb74f8ec72684183fe743bfefb
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/462883
Auto-Submit: Michael Ludwig <michaelludwig@google.com>
Commit-Queue: Jim Van Verth <jvanverth@google.com>
Reviewed-by: Jim Van Verth <jvanverth@google.com>
This commit is contained in:
Michael Ludwig 2021-10-25 20:29:20 -04:00 committed by SkCQ
parent 649e3c2f98
commit 04bff8ba6e
10 changed files with 245 additions and 113 deletions

View File

@ -45,12 +45,6 @@ enum class Protected : bool {
kYes = true,
};
/**
* An ordinal number that allows draw commands to be re-ordered so long as when they are executed,
* the read/writes to the color|depth|stencil attachments respect the original painter's order.
*/
using CompressedPaintersOrder = uint16_t;
} // namespace skgpu
#endif // skgpu_GraphiteTypes_DEFINED

View File

@ -50,8 +50,8 @@ Device::Device(sk_sp<Recorder> recorder, sk_sp<DrawContext> dc)
, fRecorder(std::move(recorder))
, fDC(std::move(dc))
, fColorDepthBoundsManager(std::make_unique<NaiveBoundsManager>())
, fMaxPaintOrder(0)
, fMaxZ(0)
, fCurrentDepth(DrawOrder::kClearDepth)
, fMaxStencilIndex(DrawOrder::kUnassigned)
, fDrawsOverlap(false) {
SkASSERT(SkToBool(fDC) && SkToBool(fRecorder));
}
@ -151,6 +151,8 @@ void Device::drawShape(const Shape& shape,
Transform localToDevice(this->localToDevice44());
if (!localToDevice.valid()) {
// If the transform is not invertible or not finite then drawing isn't well defined.
// TBD: This warning should go through the general purpose graphite logging system
SkDebugf("[graphite] WARNING - Skipping draw with non-invertible/non-finite transform.\n");
return;
}
@ -190,61 +192,72 @@ void Device::drawShape(const Shape& shape,
SkASSERT(!SkToBool(paint.getPathEffect()) || (flags & DrawFlags::kIgnorePathEffect));
SkASSERT(!SkToBool(paint.getMaskFilter()) || (flags & DrawFlags::kIgnoreMaskFilter));
uint16_t drawZ = fMaxZ + 1;
ClipResult clip = this->applyClipToDraw(localToDevice, shape, style, drawZ);
DrawOrder order(fCurrentDepth.next());
ClipResult clip = this->applyClipToDraw(localToDevice, shape, style, order.depth());
if (clip.fDrawBounds.isEmptyNegativeOrNaN()) {
// Clipped out, so don't record anything
return;
}
// A draw's order always depends on the clips that must be drawn before it
order.dependsOnPaintersOrder(clip.fOrder);
auto blendMode = paint.asBlendMode();
PaintParams shading{paint.getColor4f(),
blendMode.has_value() ? *blendMode : SkBlendMode::kSrcOver,
paint.refShader()};
// If a draw is opaque, its ordering only depends on clipping; otherwise it must be drawn after
// the most recent draw it intersects with, in order to blend correctly.
// If a draw is not opaque, it must be drawn after the most recent draw it intersects with in
// order to blend correctly. We always query the most recent draw (even when opaque) because it
// also lets Device easily track whether or not there are any overlapping draws.
const bool opaque = is_opaque(shading);
CompressedPaintersOrder prevDrawOrder =
CompressedPaintersOrder prevDraw =
fColorDepthBoundsManager->getMostRecentDraw(clip.fDrawBounds);
CompressedPaintersOrder drawOrder =
1 + (opaque ? clip.fOrder : std::max(clip.fOrder, prevDrawOrder));
if (!opaque) {
order.dependsOnPaintersOrder(prevDraw);
}
SkStrokeRec::Style styleType = style.getStyle();
const SkStrokeRec::Style styleType = style.getStyle();
if (styleType == SkStrokeRec::kStroke_Style ||
styleType == SkStrokeRec::kHairline_Style ||
styleType == SkStrokeRec::kStrokeAndFill_Style) {
// TODO: If DC supports stroked primitives, Device could choose one of those based on shape
StrokeParams stroke(style.getWidth(), style.getMiter(), style.getJoin(), style.getCap());
fDC->strokePath(localToDevice, shape, stroke, clip.fScissor,
drawOrder, drawZ, &shading);
fDC->strokePath(localToDevice, shape, stroke, clip.fScissor, order, &shading);
}
if (styleType == SkStrokeRec::kFill_Style ||
styleType == SkStrokeRec::kStrokeAndFill_Style) {
// TODO: If DC supports filled primitives, Device could choose one of those based on shape
if (shape.convex()) {
fDC->fillConvexPath(localToDevice, shape, clip.fScissor,
drawOrder, drawZ, &shading);
} else {
// FIXME must determine stencil order; a separate bounds manager? a rect tree? defer?
fDC->stencilAndFillPath(localToDevice, shape, clip.fScissor,
drawOrder, 0, drawZ, &shading);
}
// TODO: Route all filled shapes to stencil-and-cover for the sprint; convex will draw
// correctly but uses an unnecessary stencil step.
// if (shape.convex()) {
// fDC->fillConvexPath(localToDevice, shape, clip.fScissor, order, &shading);
// } else {
order.dependsOnStencil(fMaxStencilIndex.next());
fDC->stencilAndFillPath(localToDevice, shape, clip.fScissor, order, &shading);
// }
}
// Record the painters order and Z used for this draw
// Record the painters order and depth used for this draw
const bool fullyOpaque = opaque && shape.isRect() &&
localToDevice.type() <= Transform::Type::kRectStaysRect;
fColorDepthBoundsManager->recordDraw(shape.bounds(), drawOrder, drawZ, fullyOpaque);
fMaxPaintOrder = std::max(fMaxPaintOrder, drawOrder);
fMaxZ = drawZ;
fDrawsOverlap |= (prevDrawOrder != 0);
fColorDepthBoundsManager->recordDraw(shape.bounds(),
order.paintOrder(),
order.depth(),
fullyOpaque);
fCurrentDepth = order.depth();
if (order.stencilIndex() != DrawOrder::kUnassigned) {
fMaxStencilIndex = std::max(fMaxStencilIndex, order.stencilIndex());
}
fDrawsOverlap |= (prevDraw != DrawOrder::kNoIntersection);
}
Device::ClipResult Device::applyClipToDraw(const Transform& localToDevice,
const Shape& shape,
const SkStrokeRec& style,
uint16_t z) {
PaintersDepth z) {
SkIRect scissor = this->devClipBounds();
Rect drawBounds = shape.bounds();
@ -262,11 +275,11 @@ Device::ClipResult Device::applyClipToDraw(const Transform& localToDevice,
drawBounds.intersect(SkRect::Make(scissor));
if (drawBounds.isEmptyNegativeOrNaN()) {
// Trivially clipped out, so return now
return {scissor, drawBounds, 0};
return {scissor, drawBounds, DrawOrder::kNoIntersection};
}
// TODO: iterate the clip stack and accumulate draw bounds into clip usage
return {scissor, drawBounds, 0};
return {scissor, drawBounds, DrawOrder::kNoIntersection};
}
sk_sp<SkSpecialImage> Device::makeSpecial(const SkBitmap&) {

View File

@ -8,10 +8,10 @@
#ifndef skgpu_Device_DEFINED
#define skgpu_Device_DEFINED
#include "experimental/graphite/include/private/GraphiteTypesPriv.h"
#include "src/core/SkDevice.h"
#include "experimental/graphite/include/private/GraphiteTypesPriv.h"
#include "experimental/graphite/src/DrawOrder.h"
#include "experimental/graphite/src/geom/Rect.h"
class SkStrokeRec;
@ -25,9 +25,6 @@ class Recorder;
class Shape;
class Transform;
struct PaintParams;
struct StrokeParams;
class Device final : public SkBaseDevice {
public:
~Device() override;
@ -155,7 +152,7 @@ private:
//
// This also records the draw's bounds to any clip elements that affect it so that they are
// recorded when popped off the stack, or making an image snapshot of the Device.
ClipResult applyClipToDraw(const Transform&, const Shape&, const SkStrokeRec&, uint16_t z);
ClipResult applyClipToDraw(const Transform&, const Shape&, const SkStrokeRec&, PaintersDepth z);
sk_sp<Recorder> fRecorder;
sk_sp<DrawContext> fDC;
@ -163,11 +160,13 @@ private:
// Tracks accumulated intersections for ordering dependent use of the color and depth attachment
// (i.e. depth-based clipping, and transparent blending)
std::unique_ptr<BoundsManager> fColorDepthBoundsManager;
// The max recorded painters order sent to the DrawContext, needed to know how many available
// values are left before overrunning 16-bit limit and forcing a reset.
CompressedPaintersOrder fMaxPaintOrder;
// The max depth value sent to the DrawContext, incremented so each draw has a unique value.
uint16_t fMaxZ;
PaintersDepth fCurrentDepth;
// TODO: Temporary way to assign stencil IDs for draws, but since each draw gets its own
// value, it prevents the ability for draw steps to be re-arranged into blocks of stencil then
// covers. However, it does ensure stenciling is correct until we wire up the intersection tree
DisjointStencilIndex fMaxStencilIndex;
bool fDrawsOverlap;
};

View File

@ -36,31 +36,26 @@ DrawContext::~DrawContext() {
void DrawContext::stencilAndFillPath(const Transform& localToDevice,
const Shape& shape,
const SkIRect& scissor,
CompressedPaintersOrder colorDepthOrder,
CompressedPaintersOrder stencilOrder,
uint16_t depth,
DrawOrder order,
const PaintParams* paint) {
fPendingDraws->stencilAndFillPath(localToDevice, shape, scissor, colorDepthOrder, stencilOrder,
depth, paint);
fPendingDraws->stencilAndFillPath(localToDevice, shape, scissor, order,paint);
}
void DrawContext::fillConvexPath(const Transform& localToDevice,
const Shape& shape,
const SkIRect& scissor,
CompressedPaintersOrder colorDepthOrder,
uint16_t depth,
DrawOrder order,
const PaintParams* paint) {
fPendingDraws->fillConvexPath(localToDevice, shape, scissor, colorDepthOrder, depth, paint);
fPendingDraws->fillConvexPath(localToDevice, shape, scissor, order, paint);
}
void DrawContext::strokePath(const Transform& localToDevice,
const Shape& shape,
const StrokeParams& stroke,
const SkIRect& scissor,
CompressedPaintersOrder colorDepthOrder,
uint16_t depth,
DrawOrder order,
const PaintParams* paint) {
fPendingDraws->strokePath(localToDevice, shape, stroke, scissor, colorDepthOrder, depth, paint);
fPendingDraws->strokePath(localToDevice, shape, stroke, scissor, order, paint);
}
void DrawContext::snapDrawPass(const BoundsManager* occlusionCuller) {

View File

@ -11,7 +11,7 @@
#include "include/core/SkImageInfo.h"
#include "include/core/SkRefCnt.h"
#include "experimental/graphite/include/GraphiteTypes.h"
#include "experimental/graphite/src/DrawOrder.h"
#include <vector>
@ -45,24 +45,20 @@ public:
void stencilAndFillPath(const Transform& localToDevice,
const Shape& shape,
const SkIRect& scissor,
CompressedPaintersOrder colorDepthOrder,
CompressedPaintersOrder stencilOrder,
uint16_t depth,
DrawOrder order,
const PaintParams* paint);
void fillConvexPath(const Transform& localToDevice,
const Shape& shape,
const SkIRect& scissor,
CompressedPaintersOrder colorDepthOrder,
uint16_t depth,
DrawOrder order,
const PaintParams* paint);
void strokePath(const Transform& localToDevice,
const Shape& shape,
const StrokeParams& stroke,
const SkIRect& scissor,
CompressedPaintersOrder colorDepthOrder,
uint16_t depth,
DrawOrder order,
const PaintParams* paint);
// Ends the current DrawList being accumulated by the SDC, converting it into an optimized and

View File

@ -12,7 +12,7 @@
#include "include/core/SkPaint.h"
#include "include/core/SkShader.h"
#include "experimental/graphite/include/GraphiteTypes.h"
#include "experimental/graphite/src/DrawOrder.h"
#include <cstdint>
@ -61,12 +61,6 @@ struct StrokeParams;
*/
class DrawList {
public:
// TBD: Do we always need the inverse deviceToLocal matrix? If not the entire matrix, do we need
// some other matrix-dependent value (e.g. scale factor) frequently? Since the localToDevice
// transform from the Device changes at the same or slower rate as draw commands, it may make
// sense for it to compute these dependent values and provide them here. Storing the scale
// factor per draw command is low overhead, but unsure about storing 2 matrices per command.
// NOTE: All path rendering functions, e.g. [fill|stroke|...]Path() that take a Shape
// draw using the same underlying techniques regardless of the shape's type. If a Shape has
// a type matching a simpler primitive technique or coverage AA, the caller must explicitly
@ -78,9 +72,7 @@ public:
void stencilAndFillPath(const Transform& localToDevice,
const Shape& shape,
const SkIRect& scissor, // TBD: expand this to one xformed rrect clip?
CompressedPaintersOrder colorDepthOrder,
CompressedPaintersOrder stencilOrder,
uint16_t depth,
DrawOrder ordering,
const PaintParams* paint) {
// TODO: Implement this and assert localToDevice.valid()
}
@ -88,8 +80,7 @@ public:
void fillConvexPath(const Transform& localToDevice,
const Shape& shape,
const SkIRect& scissor,
CompressedPaintersOrder colorDepthOrder,
uint16_t depth,
DrawOrder ordering,
const PaintParams* paint) {
// TODO: Implement this and assert localToDevice.valid()
}
@ -98,8 +89,7 @@ public:
const Shape& shape,
const StrokeParams& stroke,
const SkIRect& scissor,
CompressedPaintersOrder colorDepthOrder,
uint16_t depth,
DrawOrder ordering,
const PaintParams* paint) {
// TODO: Implement this and assert localToDevice.valid()
}
@ -112,17 +102,6 @@ public:
int count() const { return 0; }
// TBD: Figure out preparation/flush APIs and/or how to iterate the draw commands. These will
// be responsible for sorting by sort z and shading state, doing occlusion culling, and possibly
// merging compatible, consecutive remaining commands. It can also easily track if there are
// remaining depth-only draws or complex path draws that would trigger DMSAA. I[ml] can see this
// all being internal to DrawCommandList, or being supported by accessors and iterators with the
// rest of the logic stored in SDC. It is also unknown at this time how much conversion the
// PaintParams will need to go through (vs. just building a key) in order to do state sorting.
// TBD: Any value in de-duplicating paint params/programs during accumulation or being able
// to query the set of required programs for a given command list? Any time query or flush time?
private:
// TODO: actually implement this, probably stl for now but will likely need something that
// is allocation efficient. Should also explore having 1 vector of commands, vs. parallel

View File

@ -0,0 +1,163 @@
/*
* Copyright 2021 Google LLC
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef skgpu_DrawOrder_DEFINED
#define skgpu_DrawOrder_DEFINED
#include "include/core/SkTypes.h"
namespace skgpu {
// Helper to encapsulate an unsigned number and enforce that it can only be used to create a
// monotonic sequence. The template argument 'Sequence' is used to define different sequences
// enforced by the compiler. For simplicity, and current needs within Graphite, it's assumed the
// entire sequence can be indexed by uint16_t.
template<typename Sequence>
class MonotonicValue {
public:
static constexpr MonotonicValue First() { return 0; }
static constexpr MonotonicValue Last() { return 0xffff; }
MonotonicValue() = default;
MonotonicValue(const MonotonicValue& o) = default;
MonotonicValue& operator=(const MonotonicValue& o) = default;
bool operator< (MonotonicValue o) const { return fIndex < o.fIndex; }
bool operator<=(MonotonicValue o) const { return fIndex <= o.fIndex; }
bool operator> (MonotonicValue o) const { return fIndex > o.fIndex; }
bool operator>=(MonotonicValue o) const { return fIndex >= o.fIndex; }
bool operator==(MonotonicValue o) const { return fIndex == o.fIndex; }
bool operator!=(MonotonicValue o) const { return fIndex != o.fIndex; }
uint16_t bits() const { return fIndex; }
// Get the next value in the sequence after this one
MonotonicValue next() const { return fIndex + 1; }
private:
constexpr MonotonicValue(uint16_t index) : fIndex(index) {}
uint16_t fIndex = 0;
};
/**
* CompressedPaintersOrder is an ordinal number that allows draw commands to be re-ordered so long
* as when they are executed, the read/writes to the color|depth attachments respect the original
* painter's order. Logical draws with the same CompressedPaintersOrder can be assumed to be
* executed in any order, however that may have been determined (e.g. BoundsManager or relying on
* a depth test during rasterization).
*/
struct CompressedPaintersOrderSequence {};
using CompressedPaintersOrder = MonotonicValue<CompressedPaintersOrderSequence>;
/**
* Each DisjointStencilIndex specifies an implicit set of non-overlapping draws. Assuming that two
* draws have the same CompressedPaintersOrder and the same DisjointStencilIndex, their substeps
* for multi-pass rendering (stencil-then-cover, etc.) can be intermingled with each other and
* produce the same results as if each draw's substeps were executed in order before moving on to
* the next draw's.
*
* Ordering within a set can be entirely arbitrary (i.e. all stencil steps can go before all cover
* steps). Ordering between sets is also arbitrary since all draws share the same
* CompressedPaintersOrder, so long as one set is entirely drawn before the next.
*
* Two draws that have different CompressedPaintersOrders but the same DisjointStencilIndex are
* unrelated, they may or may not overlap. The painters order scopes the disjoint sets.
*/
struct DisjointStencilIndexSequence {};
using DisjointStencilIndex = MonotonicValue<DisjointStencilIndexSequence>;
/**
* Every draw has an associated depth value. The value is constant across the entire draw and is
* not related to any varying Z coordinate induced by a 4x4 transform. The painter's depth is stored
* in the depth attachment and the GREATER depth test is used to reject or accept pixels/samples
* relative to what has already been rendered into the depth attachment. This allows draws that do
* not depend on the previous color to be radically re-ordered relative to their original painter's
* order while producing correct results.
*/
struct PaintersDepthSequence {};
using PaintersDepth = MonotonicValue<PaintersDepthSequence>;
/**
* DrawOrder aggregates the three separate sequences that Graphite uses to re-order draws and their
* substeps as much as possible while preserving the painter's order semantics of the Skia API.
*
* To build the full DrawOrder for a draw, start with its assigned PaintersDepth (i.e. the original
* painter's order of the draw call). From there, the DrawOrder can be updated to reflect
* dependencies on previous draws, either from depth-only clip draws or because the draw is
* transparent and must blend with the previous color values. Lastly, once the
* CompressedPaintersOrder is finalized, the DrawOrder can be updated to reflect whether or not
* the draw will involve the stencil buffer--and if so, specify the disjoint stencil set it
* belongs to.
*
* The original and effective order that draws are executed in is defined by the PaintersDepth.
* However, the actual execution order is defined by first the CompressedPaintersOrder and then
* the DisjointStencilIndex. This means that draws with much higher depths can be executed earlier
* if painter's order compression allows for it.
*
*
*FIXME Integrate this?
* This reduces to a vertex
* coloring problem on the intersection graph formed by the commands and how their bounds
* overlap, followed by ordering by pipeline description and uniform data. General vertex
* coloring is NP-complete so DrawPass uses a greedy algorithm where the order it "colors" the
* vertices is based on the ordering constraints for the color+depth buffer and optionally the
* stencil buffer (stored in fColorDepthIndex and fStencilIndex respectively). skgpu::Device
* determines the ordering on-the-fly by using BoundsManager to approximate intersections as
* draw commands are recorded. It is possible to issue draws to Skia that produce pathologic
* orderings using this method, but it strikes a reasonable balance between finding a near
* optimal ordering that respects painter's order and is very efficient to compute.
*
*/
class DrawOrder {
public:
// The first PaintersDepth is reserved for clearing the depth attachment; any draw using this
// depth will always fail the depth test.
static constexpr PaintersDepth kClearDepth = PaintersDepth::First();
// The first CompressedPaintersOrder is reserved to indicate there is no previous draw that
// must come before a draw.
static constexpr CompressedPaintersOrder kNoIntersection = CompressedPaintersOrder::First();
// The first DisjointStencilIndex is reserved to indicate an unassigned stencil set.
static constexpr DisjointStencilIndex kUnassigned = DisjointStencilIndex::First();
explicit DrawOrder(PaintersDepth originalOrder)
: fPaintOrder(kNoIntersection)
, fStencilIndex(kUnassigned)
, fDepth(originalOrder) {}
CompressedPaintersOrder paintOrder() const { return fPaintOrder; }
DisjointStencilIndex stencilIndex() const { return fStencilIndex; }
PaintersDepth depth() const { return fDepth; }
DrawOrder& dependsOnPaintersOrder(CompressedPaintersOrder prevDraw) {
// A draw must be ordered after all previous draws that it depends on
CompressedPaintersOrder next = prevDraw.next();
if (fPaintOrder < next) {
fPaintOrder = next;
}
return *this;
}
DrawOrder& dependsOnStencil(DisjointStencilIndex disjointSet) {
// Stencil usage should only be set once
SkASSERT(fStencilIndex == kUnassigned);
fStencilIndex = disjointSet;
return *this;
}
private:
CompressedPaintersOrder fPaintOrder;
DisjointStencilIndex fStencilIndex;
PaintersDepth fDepth;
};
} // namespace skgpu
#endif // skgpu_DrawOrder_DEFINED

View File

@ -68,8 +68,8 @@ struct SortKey {
int pipelineIndex,
uint16_t geomDataHash,
uint32_t shadingDataHash)
: fPipelineKey{colorDepthOrder,
stencilOrder,
: fPipelineKey{colorDepthOrder.bits(),
stencilOrder.bits(),
static_cast<uint16_t>(drawStage),
static_cast<uint32_t>(pipelineIndex)}
, fDataHash{geomDataHash,
@ -87,16 +87,6 @@ struct SortKey {
DrawStage stage() const { return static_cast<DrawStage>(fPipelineKey.fDrawStage); }
// Exposed for inspection, but generally the painters ordering isn't needed after sorting
// since draws can be merged with different values as long as they have the same pipeline and
// their sorted ordering is preserved within the pipeline.
CompressedPaintersOrder colorDepthOrder() const {
return static_cast<CompressedPaintersOrder>(fPipelineKey.fColorDepthOrder);
}
CompressedPaintersOrder stencilOrder() const {
return static_cast<CompressedPaintersOrder>(fPipelineKey.fStencilOrder);
}
// These are exposed to help optimize detecting when new uniforms need to be bound.
// Differing hashes definitely represent different uniform bindings, but identical hashes
// require a complete comparison.

View File

@ -8,7 +8,7 @@
#ifndef skgpu_geom_BoundsManager_DEFINED
#define skgpu_geom_BoundsManager_DEFINED
#include "experimental/graphite/include/GraphiteTypes.h"
#include "experimental/graphite/src/DrawOrder.h"
#include "experimental/graphite/src/geom/Rect.h"
#include "src/core/SkTBlockList.h"
@ -34,9 +34,11 @@ public:
virtual CompressedPaintersOrder getMostRecentDraw(const Rect& bounds) const = 0;
virtual bool isOccluded(const Rect& bounds, uint16_t z) const = 0;
virtual bool isOccluded(const Rect& bounds, PaintersDepth z) const = 0;
virtual void recordDraw(const Rect& bounds, CompressedPaintersOrder order, uint16_t z,
virtual void recordDraw(const Rect& bounds,
CompressedPaintersOrder order,
PaintersDepth z,
bool fullyOpaque=false) = 0;
};
@ -53,17 +55,17 @@ public:
return fLatestDraw;
}
bool isOccluded(const Rect& bounds, uint16_t z) const override { return false; }
bool isOccluded(const Rect& bounds, PaintersDepth z) const override { return false; }
void recordDraw(const Rect& bounds, CompressedPaintersOrder order, uint16_t z,
void recordDraw(const Rect& bounds, CompressedPaintersOrder order, PaintersDepth z,
bool fullyOpaque=false) override {
if (order > fLatestDraw) {
if (fLatestDraw < order) {
fLatestDraw = order;
}
}
private:
CompressedPaintersOrder fLatestDraw = 0;
CompressedPaintersOrder fLatestDraw = CompressedPaintersOrder::First();
};
// A BoundsManager that tracks every draw and can exactly determine all queries
@ -73,26 +75,26 @@ public:
~BruteForceBoundsManager() override {}
CompressedPaintersOrder getMostRecentDraw(const Rect& bounds) const override {
CompressedPaintersOrder max = 0;
CompressedPaintersOrder max = CompressedPaintersOrder::First();
for (const Record& r : fRects.items()) {
if (r.fOrder > max && r.fBounds.intersects(bounds)) {
if (max < r.fOrder && r.fBounds.intersects(bounds)) {
max = r.fOrder;
}
}
return max;
}
bool isOccluded(const Rect& bounds, uint16_t z) const override {
bool isOccluded(const Rect& bounds, PaintersDepth z) const override {
// Iterate in reverse since the records were likely recorded in increasing Z
for (const Record& r : fRects.ritems()) {
if (r.fOpaque && r.fZ >= z && r.fBounds.contains(bounds)) {
if (r.fOpaque && z < r.fZ && r.fBounds.contains(bounds)) {
return true;
}
}
return false;
}
void recordDraw(const Rect& bounds, CompressedPaintersOrder order, uint16_t z,
void recordDraw(const Rect& bounds, CompressedPaintersOrder order, PaintersDepth z,
bool fullyOpaque=false) override {
fRects.push_back({bounds, order, z, fullyOpaque});
}
@ -101,7 +103,7 @@ private:
struct Record {
Rect fBounds;
CompressedPaintersOrder fOrder;
uint16_t fZ;
PaintersDepth fZ;
bool fOpaque;
};

View File

@ -33,6 +33,7 @@ skia_graphite_sources = [
"$_src/DrawContext.cpp",
"$_src/DrawContext.h",
"$_src/DrawList.h",
"$_src/DrawOrder.h",
"$_src/DrawPass.cpp",
"$_src/DrawPass.h",
"$_src/Gpu.cpp",