Don't draw massively wide strokes with the tessellator
Since we outset the viewport by stroke width for pre-chopping, astronomically wide strokes can result in an astronomical viewport size, and therefore an exponential explosion chops and memory usage. It is also simply inefficient to tessellate these strokes due to the number of radial edges required. We're better off just converting them to a path after a certain point Bug: chromium:1266446 Change-Id: I23ea39b0bd64f22d4e293a881992e3669afbe530 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/473196 Reviewed-by: Greg Daniel <egdaniel@google.com> Commit-Queue: Chris Dalton <csmartdalton@google.com>
This commit is contained in:
parent
d8a753a263
commit
32071c3f14
@ -98,6 +98,15 @@ PathRenderer::CanDrawPath TessellationPathRenderer::onCanDrawPath(
|
||||
if (shape.inverseFilled()) {
|
||||
return CanDrawPath::kNo;
|
||||
}
|
||||
if (shape.style().strokeRec().getWidth() * args.fViewMatrix->getMaxScale() > 10000) {
|
||||
// crbug.com/1266446 -- Don't draw massively wide strokes with the tessellator. Since we
|
||||
// outset the viewport by stroke width for pre-chopping, astronomically wide strokes can
|
||||
// result in an astronomical viewport size, and therefore an exponential explosion chops
|
||||
// and memory usage. It is also simply inefficient to tessellate these strokes due to
|
||||
// the number of radial edges required. We're better off just converting them to a path
|
||||
// after a certain point.
|
||||
return CanDrawPath::kNo;
|
||||
}
|
||||
}
|
||||
if (args.fHasUserStencilSettings) {
|
||||
// Non-convex paths and strokes use the stencil buffer internally, so they can't support
|
||||
@ -116,10 +125,10 @@ bool TessellationPathRenderer::onDrawPath(const DrawPathArgs& args) {
|
||||
args.fShape->asPath(&path);
|
||||
|
||||
const SkRect pathDevBounds = args.fViewMatrix->mapRect(args.fShape->bounds());
|
||||
float n = wangs_formula::worst_case_cubic_pow4(kTessellationPrecision,
|
||||
pathDevBounds.width(),
|
||||
pathDevBounds.height());
|
||||
if (n > pow4(kMaxTessellationSegmentsPerCurve)) {
|
||||
float n4 = wangs_formula::worst_case_cubic_pow4(kTessellationPrecision,
|
||||
pathDevBounds.width(),
|
||||
pathDevBounds.height());
|
||||
if (n4 > pow4(kMaxTessellationSegmentsPerCurve)) {
|
||||
// The path is extremely large. Pre-chop its curves to keep the number of tessellation
|
||||
// segments tractable. This will also flatten curves that fall completely outside the
|
||||
// viewport.
|
||||
@ -206,10 +215,10 @@ void TessellationPathRenderer::onStencilPath(const StencilPathArgs& args) {
|
||||
SkPath path;
|
||||
args.fShape->asPath(&path);
|
||||
|
||||
float n = wangs_formula::worst_case_cubic_pow4(kTessellationPrecision,
|
||||
pathDevBounds.width(),
|
||||
pathDevBounds.height());
|
||||
if (n > pow4(kMaxTessellationSegmentsPerCurve)) {
|
||||
float n4 = wangs_formula::worst_case_cubic_pow4(kTessellationPrecision,
|
||||
pathDevBounds.width(),
|
||||
pathDevBounds.height());
|
||||
if (n4 > pow4(kMaxTessellationSegmentsPerCurve)) {
|
||||
SkRect viewport = SkRect::Make(*args.fClipConservativeBounds);
|
||||
path = PreChopPathCurves(path, *args.fViewMatrix, viewport);
|
||||
}
|
||||
|
@ -96,6 +96,14 @@ private:
|
||||
} // namespace
|
||||
|
||||
SkPath PreChopPathCurves(const SkPath& path, const SkMatrix& matrix, const SkRect& viewport) {
|
||||
// If the viewport is exceptionally large, we could end up blowing out memory with an unbounded
|
||||
// number of of chops. Therefore, we require that the viewport is manageable enough that a fully
|
||||
// contained curve can be tessellated in kMaxTessellationSegmentsPerCurve or fewer. (Any larger
|
||||
// and that amount of pixels wouldn't fit in memory anyway.)
|
||||
SkASSERT(wangs_formula::worst_case_cubic(
|
||||
kTessellationPrecision,
|
||||
viewport.width(),
|
||||
viewport.height()) <= kMaxTessellationSegmentsPerCurve);
|
||||
PathChopper chopper(matrix, viewport);
|
||||
for (auto [verb, p, w] : SkPathPriv::Iterate(path)) {
|
||||
switch (verb) {
|
||||
|
Loading…
Reference in New Issue
Block a user