[graphite] Refactor Shape to be wrapped into a Geometry class

Create a new Geometry class that encapsulates Shapes, but can later encapsulate Vertices & text subruns. DrawGeometry has been renamed to DrawParams for clarity and now stores a Geometry object instead of a Shape.

Bug: skia:13352
Change-Id: I42781b3eecff9845b893aa99fe78c08fd50fb995
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/547281
Reviewed-by: Greg Daniel <egdaniel@google.com>
Reviewed-by: Michael Ludwig <michaelludwig@google.com>
Commit-Queue: Nicolette Prevost <nicolettep@google.com>
This commit is contained in:
Nicolette Prevost 2022-06-15 11:29:40 -04:00 committed by SkCQ
parent 29dffe9ba4
commit 6dbbf38dc8
26 changed files with 223 additions and 131 deletions

View File

@ -49,6 +49,7 @@ skia_graphite_sources = [
"$_src/DrawList.cpp",
"$_src/DrawList.h",
"$_src/DrawOrder.h",
"$_src/DrawParams.h",
"$_src/DrawPass.cpp",
"$_src/DrawPass.h",
"$_src/DrawTypes.h",
@ -110,6 +111,7 @@ skia_graphite_sources = [
"$_src/UploadTask.cpp",
"$_src/UploadTask.h",
"$_src/geom/BoundsManager.h",
"$_src/geom/Geometry.h",
"$_src/geom/IntersectionTree.cpp",
"$_src/geom/IntersectionTree.h",
"$_src/geom/Rect.h",

View File

@ -16,7 +16,7 @@
#include "src/core/SkRectPriv.h"
#include "src/core/SkTLazy.h"
#include "src/gpu/graphite/Device.h"
#include "src/gpu/graphite/DrawGeometry.h"
#include "src/gpu/graphite/DrawParams.h"
#include "src/gpu/graphite/geom/BoundsManager.h"
namespace skgpu::graphite {

View File

@ -57,7 +57,7 @@ ExtractPaintData(Recorder* recorder,
UniformDataCache::Index ExtractRenderStepData(UniformDataCache* geometryUniformDataCache,
SkPipelineDataGatherer* gatherer,
const RenderStep* step,
const DrawGeometry& geometry) {
const DrawParams& geometry) {
SkDEBUGCODE(gatherer->checkReset());
step->writeUniforms(geometry, gatherer);

View File

@ -17,7 +17,7 @@ class SkUniquePaintParamsID;
namespace skgpu::graphite {
class DrawGeometry;
class DrawParams;
class PaintParams;
class Recorder;
class RenderStep;
@ -32,7 +32,7 @@ ExtractPaintData(Recorder*,
UniformDataCache::Index ExtractRenderStepData(UniformDataCache* geometryUniformDataCache,
SkPipelineDataGatherer* gatherer,
const RenderStep* step,
const DrawGeometry& geometry);
const DrawParams& params);
} // namespace skgpu::graphite

View File

@ -15,8 +15,8 @@
#include "src/gpu/graphite/CommandBuffer.h"
#include "src/gpu/graphite/ContextPriv.h"
#include "src/gpu/graphite/DrawContext.h"
#include "src/gpu/graphite/DrawGeometry.h"
#include "src/gpu/graphite/DrawList.h"
#include "src/gpu/graphite/DrawParams.h"
#include "src/gpu/graphite/Gpu.h"
#include "src/gpu/graphite/Log.h"
#include "src/gpu/graphite/RecorderPriv.h"
@ -24,6 +24,7 @@
#include "src/gpu/graphite/TextureProxy.h"
#include "src/gpu/graphite/TextureUtils.h"
#include "src/gpu/graphite/geom/BoundsManager.h"
#include "src/gpu/graphite/geom/Geometry.h"
#include "src/gpu/graphite/geom/IntersectionTree.h"
#include "src/gpu/graphite/geom/Shape.h"
#include "src/gpu/graphite/geom/Transform_graphite.h"
@ -699,10 +700,11 @@ void Device::recordDraw(const Transform& localToDevice,
clip.drawBounds());
ordering.dependsOnStencil(setIndex);
}
// TODO: if the chosen Renderer uses coverage AA, then 'ordering' depends on painter's order,
// so we will need to take into account the previous draw. Since no Renderer uses coverage AA
// right now, it's not an issue yet.
fDC->recordDraw(*renderer, localToDevice, shape, clip, ordering, paint, stroke);
fDC->recordDraw(*renderer, localToDevice, Geometry{shape}, clip, ordering, paint, stroke);
fRecorder->priv().tokenTracker()->issueDrawToken();
}

View File

@ -25,7 +25,8 @@
#include "src/gpu/graphite/ResourceTypes.h"
#include "src/gpu/graphite/TextureProxy.h"
#include "src/gpu/graphite/UploadTask.h"
#include "src/gpu/graphite/geom/Shape.h"
#include "src/gpu/graphite/geom/BoundsManager.h"
#include "src/gpu/graphite/geom/Geometry.h"
namespace skgpu::graphite {
@ -73,13 +74,13 @@ void DrawContext::clear(const SkColor4f& clearColor) {
void DrawContext::recordDraw(const Renderer& renderer,
const Transform& localToDevice,
const Shape& shape,
const Geometry& geometry,
const Clip& clip,
DrawOrder ordering,
const PaintParams* paint,
const StrokeStyle* stroke) {
SkASSERT(SkIRect::MakeSize(fTarget->dimensions()).contains(clip.scissor()));
fPendingDraws->recordDraw(renderer, localToDevice, shape, clip, ordering, paint, stroke);
fPendingDraws->recordDraw(renderer, localToDevice, geometry, clip, ordering, paint, stroke);
}
bool DrawContext::recordUpload(Recorder* recorder,

View File

@ -22,8 +22,8 @@ class SkPixmap;
namespace skgpu::graphite {
class Geometry;
class Recorder;
class Shape;
class Transform;
class DrawPass;
@ -53,7 +53,7 @@ public:
void recordDraw(const Renderer& renderer,
const Transform& localToDevice,
const Shape& shape,
const Geometry& geometry,
const Clip& clip,
DrawOrder ordering,
const PaintParams* paint,

View File

@ -9,6 +9,7 @@
#include "src/gpu/BufferWriter.h"
#include "src/gpu/graphite/Renderer.h"
#include "src/gpu/graphite/geom/Shape.h"
namespace skgpu::graphite {
@ -23,20 +24,20 @@ const Transform& DrawList::deduplicateTransform(const Transform& localToDevice)
void DrawList::recordDraw(const Renderer& renderer,
const Transform& localToDevice,
const Shape& shape,
const Geometry& geometry,
const Clip& clip,
DrawOrder ordering,
const PaintParams* paint,
const StrokeStyle* stroke) {
SkASSERT(localToDevice.valid());
SkASSERT(!shape.isEmpty() && !clip.drawBounds().isEmptyNegativeOrNaN());
SkASSERT(!geometry.isEmpty() && !clip.drawBounds().isEmptyNegativeOrNaN());
SkASSERT(!(renderer.depthStencilFlags() & DepthStencilFlags::kStencil) ||
ordering.stencilIndex() != DrawOrder::kUnassigned);
// TODO: Add validation that the renderer's expected shape type and stroke params match provided
fDraws.push_back({renderer, this->deduplicateTransform(localToDevice),
shape, clip, ordering, paint, stroke});
geometry, clip, ordering, paint, stroke});
fRenderStepCount += renderer.numRenderSteps();
}

View File

@ -11,9 +11,10 @@
#include "include/core/SkPaint.h"
#include "src/core/SkTBlockList.h"
#include "src/gpu/graphite/DrawGeometry.h"
#include "src/gpu/graphite/DrawOrder.h"
#include "src/gpu/graphite/DrawParams.h"
#include "src/gpu/graphite/PaintParams.h"
#include "src/gpu/graphite/geom/Geometry.h"
#include "src/gpu/graphite/geom/Transform_graphite.h"
#include <limits>
@ -22,7 +23,6 @@
namespace skgpu::graphite {
class Renderer;
class Shape;
/**
* A DrawList represents a collection of drawing commands (and related clip/shading state) in
@ -70,7 +70,7 @@ public:
// must have a valid stencil index as well.
void recordDraw(const Renderer& renderer,
const Transform& localToDevice,
const Shape& shape,
const Geometry& geometry,
const Clip& clip,
DrawOrder ordering,
const PaintParams* paint,
@ -84,14 +84,14 @@ private:
struct Draw {
const Renderer& fRenderer; // Statically defined by function that recorded the Draw
DrawGeometry fGeometry; // The GeomParam's transform is owned by fTransforms of the DrawList
DrawParams fDrawParams; // The DrawParam's transform is owned by fTransforms of the DrawList
std::optional<PaintParams> fPaintParams; // Not present implies depth-only draw
Draw(const Renderer& renderer, const Transform& transform, const Shape& shape,
Draw(const Renderer& renderer, const Transform& transform, const Geometry& geometry,
const Clip& clip, DrawOrder order, const PaintParams* paint,
const StrokeStyle* stroke)
: fRenderer(renderer)
, fGeometry(transform, shape, clip, order, stroke)
, fDrawParams(transform, geometry, clip, order, stroke)
, fPaintParams(paint ? std::optional<PaintParams>(*paint) : std::nullopt) {}
};

View File

@ -5,15 +5,15 @@
* found in the LICENSE file.
*/
#ifndef skgpu_DrawGeometry_DEFINED
#define skgpu_DrawGeometry_DEFINED
#ifndef skgpu_DrawParams_DEFINED
#define skgpu_DrawParams_DEFINED
#include "include/core/SkPaint.h"
#include "include/core/SkRect.h"
#include "src/gpu/graphite/DrawOrder.h"
#include "src/gpu/graphite/geom/Geometry.h"
#include "src/gpu/graphite/geom/Rect.h"
#include "src/gpu/graphite/geom/Shape.h"
#include "src/gpu/graphite/geom/Transform_graphite.h"
#include <optional>
@ -84,21 +84,21 @@ private:
// Encapsulates all geometric state for a single high-level draw call. RenderSteps are responsible
// for transforming this state into actual rendering; shading from PaintParams is handled separately
class DrawGeometry {
class DrawParams {
public:
DrawGeometry(const Transform& transform,
const Shape& shape,
const Clip& clip,
DrawOrder drawOrder,
const StrokeStyle* stroke)
DrawParams(const Transform& transform,
const Geometry& geometry,
const Clip& clip,
DrawOrder drawOrder,
const StrokeStyle* stroke)
: fTransform(transform)
, fShape(shape)
, fGeometry(geometry)
, fClip(clip)
, fOrder(drawOrder)
, fStroke(stroke ? std::optional<StrokeStyle>(*stroke) : std::nullopt) {}
const Transform& transform() const { return fTransform; }
const Shape& shape() const { return fShape; }
const Geometry& geometry() const { return fGeometry; }
const Clip& clip() const { return fClip; }
DrawOrder order() const { return fOrder; }
@ -112,7 +112,7 @@ public:
private:
const Transform& fTransform; // Lifetime of the transform must be held longer than the geometry
Shape fShape;
Geometry fGeometry;
Clip fClip;
DrawOrder fOrder;
@ -121,4 +121,4 @@ private:
} // namespace skgpu
#endif // skgpu_DrawGeometry_DEFINED
#endif // skgpu_DrawParams_DEFINED

View File

@ -82,9 +82,9 @@ public:
UniformDataCache::Index geomUniformIndex,
UniformDataCache::Index shadingUniformIndex,
TextureDataCache::Index textureDataIndex)
: fPipelineKey(ColorDepthOrderField::set(draw->fGeometry.order().paintOrder().bits()) |
StencilIndexField::set(draw->fGeometry.order().stencilIndex().bits()) |
RenderStepField::set(static_cast<uint32_t>(renderStep)) |
: fPipelineKey(ColorDepthOrderField::set(draw->fDrawParams.order().paintOrder().bits()) |
StencilIndexField::set(draw->fDrawParams.order().stencilIndex().bits()) |
RenderStepField::set(static_cast<uint32_t>(renderStep)) |
PipelineField::set(pipelineIndex))
, fUniformKey(GeometryUniformField::set(geomUniformIndex.asUInt()) |
ShadingUniformField::set(shadingUniformIndex.asUInt()) |
@ -370,7 +370,7 @@ std::unique_ptr<DrawPass> DrawPass::Make(Recorder* recorder,
UniformDataCache::Index uniformDataIndex;
std::tie(shaderID, uniformDataIndex, textureBindingIndex) =
ExtractPaintData(recorder, &gatherer, &builder,
draw.fGeometry.transform().inverse(),
draw.fDrawParams.transform().inverse(),
draw.fPaintParams.value());
shadingUniformIndex = shadingUniformBindings.addUniforms(uniformDataIndex);
} // else depth-only
@ -394,7 +394,7 @@ std::unique_ptr<DrawPass> DrawPass::Make(Recorder* recorder,
uniformDataIndex = ExtractRenderStepData(&geometryUniformDataCache,
&gatherer,
step,
draw.fGeometry);
draw.fDrawParams);
geometryUniformIndex = geometryUniformBindings.addUniforms(uniformDataIndex);
}
@ -418,7 +418,7 @@ std::unique_ptr<DrawPass> DrawPass::Make(Recorder* recorder,
stepTextureBindingIndex});
}
passBounds.join(draw.fGeometry.clip().drawBounds());
passBounds.join(draw.fDrawParams.clip().drawBounds());
drawPass->fDepthStencilFlags |= draw.fRenderer.depthStencilFlags();
drawPass->fRequiresMSAA |= draw.fRenderer.requiresMSAA();
}
@ -459,7 +459,7 @@ std::unique_ptr<DrawPass> DrawPass::Make(Recorder* recorder,
const bool stateChange = geometryUniformChange ||
shadingUniformChange ||
textureBindingsChange ||
draw.fGeometry.clip().scissor() != lastScissor;
draw.fDrawParams.clip().scissor() != lastScissor;
// Update DrawWriter *before* we actually change any state so that accumulated draws from
// the previous state use the proper state.
@ -507,13 +507,13 @@ std::unique_ptr<DrawPass> DrawPass::Make(Recorder* recorder,
drawPass->fCommands.push_back(Command(bts));
lastTextureBindings = key.textureBindings();
}
if (draw.fGeometry.clip().scissor() != lastScissor) {
drawPass->fCommands.emplace_back(SetScissor{draw.fGeometry.clip().scissor()});
lastScissor = draw.fGeometry.clip().scissor();
if (draw.fDrawParams.clip().scissor() != lastScissor) {
drawPass->fCommands.emplace_back(SetScissor{draw.fDrawParams.clip().scissor()});
lastScissor = draw.fDrawParams.clip().scissor();
}
}
renderStep.writeVertices(&drawWriter, draw.fGeometry);
renderStep.writeVertices(&drawWriter, draw.fDrawParams);
}
// Finish recording draw calls for any collected data at the end of the loop
drawWriter.flush();

View File

@ -29,7 +29,7 @@ class SkPipelineDataGatherer;
namespace skgpu::graphite {
class DrawWriter;
class DrawGeometry;
class DrawParams;
class ResourceProvider;
class RenderStep {
@ -39,7 +39,7 @@ public:
// The DrawWriter is configured with the vertex and instance strides of the RenderStep, and its
// primitive type. The recorded draws will be executed with a graphics pipeline compatible with
// this RenderStep.
virtual void writeVertices(DrawWriter*, const DrawGeometry&) const = 0;
virtual void writeVertices(DrawWriter*, const DrawParams&) const = 0;
// Write out the uniform values (aligned for the layout). These values will be de-duplicated
// across all draws using the RenderStep before uploading to the GPU, but it can be assumed the
@ -50,7 +50,7 @@ public:
// nice if we could remember the offsets for the layout/gpu and reuse them across draws.
// Similarly, it would be nice if this could write into reusable storage and then DrawPass or
// UniformCache handles making an sk_sp if we need to assign a new unique ID to the uniform data
virtual void writeUniforms(const DrawGeometry&, SkPipelineDataGatherer*) const = 0;
virtual void writeUniforms(const DrawParams&, SkPipelineDataGatherer*) const = 0;
// Returns a name formatted as "Subclass[variant]", where "Subclass" matches the C++ class name
// and variant is a unique term describing instance's specific configuration.

View File

@ -0,0 +1,98 @@
/*
* Copyright 2022 Google LLC
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef skgpu_graphite_geom_Geometry_DEFINED
#define skgpu_graphite_geom_Geometry_DEFINED
#include "include/core/SkVertices.h"
#include "src/gpu/graphite/geom/Rect.h"
#include "src/gpu/graphite/geom/Shape.h"
namespace skgpu::graphite {
/**
* Geometry is a container that can house Shapes, SkVertices, and eventually text subruns.
* TODO - Add text subruns & vertices functionality. As of right now, this class is really just a
* wrapper for Shape.
*/
class Geometry {
public:
enum class Type : uint8_t {
kEmpty, kShape, kVertices
};
Geometry() {}
explicit Geometry(const Shape& shape) { this->setShape(shape); }
~Geometry() { this->setType(Type::kEmpty); }
Geometry& operator=(Geometry&& geom) {
if (this != &geom) {
switch (geom.type()) {
case Type::kEmpty: this->setType(Type::kEmpty); break;
case Type::kShape: this->setShape(geom.shape()); geom.setType(Type::kEmpty); break;
default: break;
}
}
return *this;
}
Geometry& operator=(const Geometry& geom) {
switch (geom.type()) {
case Type::kEmpty: this->setType(Type::kEmpty); break;
case Type::kShape: this->setShape(geom.shape()); break;
default: break;
}
return *this;
}
Geometry(const Geometry& geom) {
*this = geom;
}
void setShape(const Shape& shape) {
if (fType == Type::kShape) {
fShape = shape;
} else {
this->setType(Type::kShape);
new (&fShape) Shape(shape);
}
}
// void setVertices(const SkVertices&);
const Shape& shape() const { SkASSERT(this->isShape()); return fShape; }
// const SkVertices& vertices() const;
Rect bounds() const {
switch (fType) {
case Type::kShape: return fShape.bounds();
default: return Rect(0, 0, 0, 0);
}
}
Type type() const { return fType; }
bool isShape() const { return fType == Type::kShape; }
bool isVertices() const { return fType == Type::kVertices; }
bool isEmpty() const {
return fType == (Type::kEmpty) || (this->isShape() && this->shape().isEmpty());
}
private:
void setType(Type type) {
if (this->isShape() && type != Type::kShape) {
fShape.~Shape();
}
fType = type;
}
Type fType = Type::kEmpty;
union {
Shape fShape;
// SkVertices fVertices;
};
};
} // namespace skgpu::graphite
#endif // skgpu_graphite_geom_Geometry_DEFINED

View File

@ -48,17 +48,6 @@ bool Shape::conservativeContains(skvx::float2 point) const {
SkUNREACHABLE;
}
bool Shape::closed() const {
switch (fType) {
case Type::kEmpty: return true;
case Type::kLine: return false;
case Type::kRect: return true;
case Type::kRRect: return true;
case Type::kPath: return SkPathPriv::IsClosedSingleContour(fPath);
}
SkUNREACHABLE;
}
bool Shape::convex(bool simpleFill) const {
if (this->isPath()) {
// SkPath.isConvex() really means "is this path convex were it to be closed".

View File

@ -86,10 +86,6 @@ public:
bool conservativeContains(const Rect& rect) const;
bool conservativeContains(skvx::float2 point) const;
// True if the underlying geometry represents a closed shape, without the need for an
// implicit close.
bool closed() const;
// True if the underlying shape is known to be convex, assuming no other styles. If 'simpleFill'
// is true, it is assumed the contours will be implicitly closed when drawn or used.
bool convex(bool simpleFill = true) const;

View File

@ -7,7 +7,7 @@
#include "src/gpu/graphite/render/CoverBoundsRenderStep.h"
#include "src/gpu/graphite/DrawGeometry.h"
#include "src/gpu/graphite/DrawParams.h"
#include "src/gpu/graphite/DrawWriter.h"
#include "src/gpu/graphite/render/StencilAndCoverDSS.h"
@ -32,21 +32,21 @@ const char* CoverBoundsRenderStep::vertexSkSL() const {
return " float4 devPosition = position;\n";
}
void CoverBoundsRenderStep::writeVertices(DrawWriter* writer, const DrawGeometry& geom) const {
void CoverBoundsRenderStep::writeVertices(DrawWriter* writer, const DrawParams& params) const {
SkV4 devPoints[4]; // ordered TL, TR, BR, BL
if (fInverseFill) {
// TODO: When we handle local coords, we'd need to map these corners by the inverse.
const SkIRect& bounds = geom.clip().scissor();
const SkIRect& bounds = params.clip().scissor();
devPoints[0] = {(float) bounds.fLeft, (float) bounds.fTop, 0.f, 1.f};
devPoints[1] = {(float) bounds.fRight, (float) bounds.fTop, 0.f, 1.f};
devPoints[2] = {(float) bounds.fRight, (float) bounds.fBottom, 0.f, 1.f};
devPoints[3] = {(float) bounds.fLeft, (float) bounds.fBottom, 0.f, 1.f};
} else {
geom.transform().mapPoints(geom.shape().bounds(), devPoints);
params.transform().mapPoints(params.geometry().shape().bounds(), devPoints);
}
float depth = geom.order().depthAsFloat();
float depth = params.order().depthAsFloat();
DrawWriter::Vertices verts{*writer};
verts.append(6) << devPoints[0].x << devPoints[0].y << depth << devPoints[0].w // TL
<< devPoints[3].x << devPoints[3].y << depth << devPoints[3].w // BL
@ -56,7 +56,7 @@ void CoverBoundsRenderStep::writeVertices(DrawWriter* writer, const DrawGeometry
<< devPoints[2].x << devPoints[2].y << depth << devPoints[2].w;// BR
}
void CoverBoundsRenderStep::writeUniforms(const DrawGeometry&, SkPipelineDataGatherer*) const {
void CoverBoundsRenderStep::writeUniforms(const DrawParams&, SkPipelineDataGatherer*) const {
// Control points are pre-transformed to device space on the CPU, so no uniforms needed.
}

View File

@ -19,8 +19,8 @@ public:
~CoverBoundsRenderStep() override;
const char* vertexSkSL() const override;
void writeVertices(DrawWriter*, const DrawGeometry&) const override;
void writeUniforms(const DrawGeometry&, SkPipelineDataGatherer*) const override;
void writeVertices(DrawWriter*, const DrawParams&) const override;
void writeUniforms(const DrawParams&, SkPipelineDataGatherer*) const override;
private:
const bool fInverseFill;

View File

@ -7,7 +7,7 @@
#include "src/gpu/graphite/render/MiddleOutFanRenderStep.h"
#include "src/gpu/graphite/DrawGeometry.h"
#include "src/gpu/graphite/DrawParams.h"
#include "src/gpu/graphite/DrawWriter.h"
#include "src/gpu/graphite/render/StencilAndCoverDSS.h"
@ -34,14 +34,14 @@ const char* MiddleOutFanRenderStep::vertexSkSL() const {
return " float4 devPosition = position;\n";
}
void MiddleOutFanRenderStep::writeVertices(DrawWriter* writer, const DrawGeometry& geom) const {
void MiddleOutFanRenderStep::writeVertices(DrawWriter* writer, const DrawParams& params) const {
// TODO: Have Shape provide a path-like iterator so we don't actually have to convert non
// paths to SkPath just to iterate their pts/verbs
SkPath path = geom.shape().asPath();
SkPath path = params.geometry().shape().asPath();
const int maxTrianglesInFans = std::max(path.countVerbs() - 2, 0);
float depth = geom.order().depthAsFloat();
float depth = params.order().depthAsFloat();
DrawWriter::Vertices verts{*writer};
verts.reserve(maxTrianglesInFans * 3);
@ -50,7 +50,7 @@ void MiddleOutFanRenderStep::writeVertices(DrawWriter* writer, const DrawGeometr
// TODO: PathMiddleOutFanIter should use SkV2 instead of SkPoint?
SkV2 p[3] = {{p0.fX, p0.fY}, {p1.fX, p1.fY}, {p2.fX, p2.fY}};
SkV4 devPoints[3];
geom.transform().mapPoints(p, devPoints, 3);
params.transform().mapPoints(p, devPoints, 3);
verts.append(3) << devPoints[0].x << devPoints[0].y << depth << devPoints[0].w // p0
<< devPoints[1].x << devPoints[1].y << depth << devPoints[1].w // p1
@ -59,7 +59,7 @@ void MiddleOutFanRenderStep::writeVertices(DrawWriter* writer, const DrawGeometr
}
}
void MiddleOutFanRenderStep::writeUniforms(const DrawGeometry&, SkPipelineDataGatherer*) const {
void MiddleOutFanRenderStep::writeUniforms(const DrawParams&, SkPipelineDataGatherer*) const {
// Control points are pre-transformed to device space on the CPU, so no uniforms needed.
}

View File

@ -22,8 +22,8 @@ public:
~MiddleOutFanRenderStep() override;
const char* vertexSkSL() const override;
void writeVertices(DrawWriter*, const DrawGeometry&) const override;
void writeUniforms(const DrawGeometry&, SkPipelineDataGatherer*) const override;
void writeVertices(DrawWriter*, const DrawParams&) const override;
void writeUniforms(const DrawParams&, SkPipelineDataGatherer*) const override;
};
} // namespace skgpu::graphite

View File

@ -7,7 +7,7 @@
#include "src/gpu/graphite/render/TessellateCurvesRenderStep.h"
#include "src/gpu/graphite/DrawGeometry.h"
#include "src/gpu/graphite/DrawParams.h"
#include "src/gpu/graphite/DrawWriter.h"
#include "src/gpu/graphite/render/DynamicInstancesPatchAllocator.h"
#include "src/gpu/graphite/render/StencilAndCoverDSS.h"
@ -57,8 +57,8 @@ const char* TessellateCurvesRenderStep::vertexSkSL() const {
"depth, 1.0);\n";
}
void TessellateCurvesRenderStep::writeVertices(DrawWriter* dw, const DrawGeometry& geom) const {
SkPath path = geom.shape().asPath(); // TODO: Iterate the Shape directly
void TessellateCurvesRenderStep::writeVertices(DrawWriter* dw, const DrawParams& params) const {
SkPath path = params.geometry().shape().asPath(); // TODO: Iterate the Shape directly
BindBufferInfo fixedVertexBuffer = dw->bufferManager()->getStaticBuffer(
BufferType::kVertex,
@ -72,7 +72,7 @@ void TessellateCurvesRenderStep::writeVertices(DrawWriter* dw, const DrawGeometr
int patchReserveCount = FixedCountCurves::PreallocCount(path.countVerbs());
Writer writer{kAttribs, *dw, fixedVertexBuffer, fixedIndexBuffer, patchReserveCount};
writer.updatePaintDepthAttrib(geom.order().depthAsFloat());
writer.updatePaintDepthAttrib(params.order().depthAsFloat());
// TODO: Is it better to pre-transform on the CPU and only have a matrix uniform to compute
// local coords, or is it better to always transform on the GPU (less CPU usage, more
@ -83,7 +83,7 @@ void TessellateCurvesRenderStep::writeVertices(DrawWriter* dw, const DrawGeometr
// TODO: This doesn't handle perspective yet, and ideally wouldn't go through SkMatrix.
// It may not be relevant, though, if transforms are applied on the GPU and we only need to
// determine an approximate 2x2 for 'shaderXform' and Wang's formula evaluation.
AffineMatrix m(geom.transform().matrix().asM33());
AffineMatrix m(params.transform().matrix().asM33());
// TODO: For filled curves, the path verb loop is simple enough that it's not too big a deal
// to copy the logic from PathCurveTessellator::write_patches. It may be required if we end
@ -123,7 +123,7 @@ void TessellateCurvesRenderStep::writeVertices(DrawWriter* dw, const DrawGeometr
}
}
void TessellateCurvesRenderStep::writeUniforms(const DrawGeometry&, SkPipelineDataGatherer*) const {
void TessellateCurvesRenderStep::writeUniforms(const DrawParams&, SkPipelineDataGatherer*) const {
// Control points are pre-transformed to device space on the CPU, so no uniforms needed.
}

View File

@ -22,8 +22,8 @@ public:
~TessellateCurvesRenderStep() override;
const char* vertexSkSL() const override;
void writeVertices(DrawWriter*, const DrawGeometry&) const override;
void writeUniforms(const DrawGeometry&, SkPipelineDataGatherer*) const override;
void writeVertices(DrawWriter*, const DrawParams&) const override;
void writeUniforms(const DrawParams&, SkPipelineDataGatherer*) const override;
};
} // namespace skgpu::graphite

View File

@ -10,7 +10,7 @@
#include "src/core/SkGeometry.h"
#include "src/core/SkPipelineData.h"
#include "src/gpu/graphite/DrawGeometry.h"
#include "src/gpu/graphite/DrawParams.h"
#include "src/gpu/graphite/DrawTypes.h"
#include "src/gpu/graphite/DrawWriter.h"
#include "src/gpu/graphite/render/DynamicInstancesPatchAllocator.h"
@ -89,8 +89,8 @@ const char* TessellateStrokesRenderStep::vertexSkSL() const {
depth, 1.0);)";
}
void TessellateStrokesRenderStep::writeVertices(DrawWriter* dw, const DrawGeometry& geom) const {
SkPath path = geom.shape().asPath(); // TODO: Iterate the Shape directly
void TessellateStrokesRenderStep::writeVertices(DrawWriter* dw, const DrawParams& params) const {
SkPath path = params.geometry().shape().asPath(); // TODO: Iterate the Shape directly
int patchReserveCount = FixedCountStrokes::PreallocCount(path.countVerbs());
// Stroke tessellation does not use fixed indices or vertex data, and only needs the vertex ID
@ -99,29 +99,29 @@ void TessellateStrokesRenderStep::writeVertices(DrawWriter* dw, const DrawGeomet
// we support Vulkan+Swiftshader, we will need the vertex buffer ID fallback unless Swiftshader
// has figured out how to support vertex IDs before then.
Writer writer{kAttribs, *dw, kNullBinding, kNullBinding, patchReserveCount};
writer.updatePaintDepthAttrib(geom.order().depthAsFloat());
writer.updatePaintDepthAttrib(params.order().depthAsFloat());
// The vector xform approximates how the control points are transformed by the shader to
// more accurately compute how many *parametric* segments are needed.
// getMaxScale() returns -1 if it can't compute a scale factor (e.g. perspective), taking the
// absolute value automatically converts that to an identity scale factor for our purposes.
writer.setShaderTransform(wangs_formula::VectorXform{geom.transform()},
geom.transform().maxScaleFactor());
writer.setShaderTransform(wangs_formula::VectorXform{params.transform()},
params.transform().maxScaleFactor());
SkASSERT(geom.isStroke());
writer.updateStrokeParamsAttrib({geom.strokeStyle().halfWidth(),
geom.strokeStyle().joinLimit()});
SkASSERT(params.isStroke());
writer.updateStrokeParamsAttrib({params.strokeStyle().halfWidth(),
params.strokeStyle().joinLimit()});
// TODO: If PatchWriter can handle adding caps to its deferred patches, and we can convert
// hairlines to use round caps instead of square, then StrokeIterator can be deleted entirely.
// Besides being simpler, PatchWriter already has what it needs from the shader matrix and
// stroke params, so we don't have to re-extract them here.
SkMatrix shaderMatrix = geom.transform();
SkMatrix shaderMatrix = params.transform();
SkStrokeRec stroke{SkStrokeRec::kHairline_InitStyle};
stroke.setStrokeStyle(geom.strokeStyle().width());
stroke.setStrokeParams(geom.strokeStyle().cap(),
geom.strokeStyle().join(),
geom.strokeStyle().miterLimit());
stroke.setStrokeStyle(params.strokeStyle().width());
stroke.setStrokeParams(params.strokeStyle().cap(),
params.strokeStyle().join(),
params.strokeStyle().miterLimit());
StrokeIterator strokeIter(path, &stroke, &shaderMatrix);
while (strokeIter.next()) {
using Verb = StrokeIterator::Verb;
@ -211,22 +211,22 @@ void TessellateStrokesRenderStep::writeVertices(DrawWriter* dw, const DrawGeomet
}
}
void TessellateStrokesRenderStep::writeUniforms(const DrawGeometry& geom,
void TessellateStrokesRenderStep::writeUniforms(const DrawParams& params,
SkPipelineDataGatherer* gatherer) const {
SkASSERT(geom.transform().type() < Transform::Type::kProjection); // TODO: Implement perspective
SkASSERT(params.transform().type() < Transform::Type::kProjection); // TODO: Implement perspective
SkDEBUGCODE(UniformExpectationsValidator uev(gatherer, this->uniforms());)
// affineMatrix = float4 (2x2 of transform), translate = float2, maxScale = float
// Column-major 2x2 of the transform.
skvx::float4 upper = {geom.transform().matrix().rc(0, 0), geom.transform().matrix().rc(1, 0),
geom.transform().matrix().rc(0, 1), geom.transform().matrix().rc(1, 1)};
skvx::float4 upper = {params.transform().matrix().rc(0, 0), params.transform().matrix().rc(1, 0),
params.transform().matrix().rc(0, 1), params.transform().matrix().rc(1, 1)};
gatherer->write(upper);
gatherer->write(SkPoint{geom.transform().matrix().rc(0, 3),
geom.transform().matrix().rc(1, 3)});
gatherer->write(SkPoint{params.transform().matrix().rc(0, 3),
params.transform().matrix().rc(1, 3)});
gatherer->write(geom.transform().maxScaleFactor());
gatherer->write(params.transform().maxScaleFactor());
}
const Renderer& Renderer::TessellatedStrokes() {

View File

@ -22,8 +22,8 @@ public:
~TessellateStrokesRenderStep() override;
const char* vertexSkSL() const override;
void writeVertices(DrawWriter*, const DrawGeometry&) const override;
void writeUniforms(const DrawGeometry&, SkPipelineDataGatherer*) const override;
void writeVertices(DrawWriter*, const DrawParams&) const override;
void writeUniforms(const DrawParams&, SkPipelineDataGatherer*) const override;
};
} // namespace skgpu::graphite

View File

@ -7,7 +7,7 @@
#include "src/gpu/graphite/render/TessellateWedgesRenderStep.h"
#include "src/gpu/graphite/DrawGeometry.h"
#include "src/gpu/graphite/DrawParams.h"
#include "src/gpu/graphite/DrawWriter.h"
#include "src/gpu/graphite/render/DynamicInstancesPatchAllocator.h"
@ -63,8 +63,8 @@ const char* TessellateWedgesRenderStep::vertexSkSL() const {
"fanPointAttrib), depth, 1.0);\n";
}
void TessellateWedgesRenderStep::writeVertices(DrawWriter* dw, const DrawGeometry& geom) const {
SkPath path = geom.shape().asPath(); // TODO: Iterate the Shape directly
void TessellateWedgesRenderStep::writeVertices(DrawWriter* dw, const DrawParams& geom) const {
SkPath path = geom.geometry().shape().asPath(); // TODO: Iterate the Shape directly
BindBufferInfo fixedVertexBuffer = dw->bufferManager()->getStaticBuffer(
BufferType::kVertex,
@ -154,7 +154,7 @@ void TessellateWedgesRenderStep::writeVertices(DrawWriter* dw, const DrawGeometr
}
}
void TessellateWedgesRenderStep::writeUniforms(const DrawGeometry&, SkPipelineDataGatherer*) const {
void TessellateWedgesRenderStep::writeUniforms(const DrawParams&, SkPipelineDataGatherer*) const {
// Control points are pre-transformed to device space on the CPU, so no uniforms needed.
}

View File

@ -20,8 +20,8 @@ public:
~TessellateWedgesRenderStep() override;
const char* vertexSkSL() const override;
void writeVertices(DrawWriter*, const DrawGeometry&) const override;
void writeUniforms(const DrawGeometry&, SkPipelineDataGatherer*) const override;
void writeVertices(DrawWriter*, const DrawParams&) const override;
void writeUniforms(const DrawParams&, SkPipelineDataGatherer*) const override;
};

View File

@ -20,7 +20,7 @@
#include "src/gpu/graphite/CommandBuffer.h"
#include "src/gpu/graphite/ContextPriv.h"
#include "src/gpu/graphite/DrawBufferManager.h"
#include "src/gpu/graphite/DrawGeometry.h"
#include "src/gpu/graphite/DrawParams.h"
#include "src/gpu/graphite/DrawWriter.h"
#include "src/gpu/graphite/GlobalCache.h"
#include "src/gpu/graphite/Gpu.h"
@ -33,6 +33,7 @@
#include "src/gpu/graphite/Texture.h"
#include "src/gpu/graphite/TextureProxy.h"
#include "src/gpu/graphite/UniformManager.h"
#include "src/gpu/graphite/geom/Geometry.h"
#include "src/gpu/graphite/geom/Shape.h"
#include "src/gpu/graphite/geom/Transform_graphite.h"
@ -71,13 +72,13 @@ public:
"float4 devPosition = float4(tmpPosition * scale + translate, 0.0, 1.0);\n";
}
void writeVertices(DrawWriter* writer, const DrawGeometry&) const override {
void writeVertices(DrawWriter* writer, const DrawParams&) const override {
// The shape is upload via uniforms, so this just needs to record 4 data-less vertices
writer->draw({}, 4);
}
void writeUniforms(const DrawGeometry& geom, SkPipelineDataGatherer* gatherer) const override {
SkASSERT(geom.shape().isRect());
void writeUniforms(const DrawParams& params, SkPipelineDataGatherer* gatherer) const override {
SkASSERT(params.geometry().shape().isRect());
#ifdef SK_DEBUG
static constexpr int kNumRectUniforms = 2;
@ -91,8 +92,8 @@ public:
// TODO: A << API for uniforms would be nice, particularly if it could take pre-computed
// offsets for each uniform.
gatherer->write(geom.shape().rect().size());
gatherer->write(geom.shape().rect().topLeft());
gatherer->write(params.geometry().shape().rect().size());
gatherer->write(params.geometry().shape().rect().topLeft());
}
private:
@ -125,8 +126,8 @@ public:
return "float4 devPosition = float4(position * scale + translate, 0.0, 1.0);\n";
}
void writeVertices(DrawWriter* writer, const DrawGeometry& geom) const override {
const Shape& shape = geom.shape();
void writeVertices(DrawWriter* writer, const DrawParams& params) const override {
const Shape& shape = params.geometry().shape();
DrawBufferManager* bufferMgr = writer->bufferManager();
auto [vertexWriter, vertices] = bufferMgr->getVertexWriter(4 * this->vertexStride());
vertexWriter << 0.5f * (shape.rect().left() + 1.f) << 0.5f * (shape.rect().top() + 1.f)
@ -142,7 +143,7 @@ public:
writer->drawIndexed(vertices, indices, 6);
}
void writeUniforms(const DrawGeometry&, SkPipelineDataGatherer* gatherer) const override {
void writeUniforms(const DrawParams&, SkPipelineDataGatherer* gatherer) const override {
#ifdef SK_DEBUG
static constexpr int kNumRectUniforms = 2;
static constexpr SkUniform kRectUniforms[kNumRectUniforms] = {
@ -184,8 +185,8 @@ public:
"float4 devPosition = float4(tmpPosition * dims + position, 0.0, 1.0);\n";
}
void writeVertices(DrawWriter* writer, const DrawGeometry& geom) const override {
SkASSERT(geom.shape().isRect());
void writeVertices(DrawWriter* writer, const DrawParams& params) const override {
SkASSERT(params.geometry().shape().isRect());
DrawBufferManager* bufferMgr = writer->bufferManager();
@ -196,10 +197,11 @@ public:
<< 2 << 1 << 3;
DrawWriter::Instances instances{*writer, {}, indices, 6};
instances.append(1) << geom.shape().rect().topLeft() << geom.shape().rect().size();
instances.append(1) << params.geometry().shape().rect().topLeft()
<< params.geometry().shape().rect().size();
}
void writeUniforms(const DrawGeometry&, SkPipelineDataGatherer*) const override { }
void writeUniforms(const DrawParams&, SkPipelineDataGatherer*) const override {}
private:
InstanceRectDraw()
@ -328,10 +330,11 @@ DEF_GRAPHITE_TEST_FOR_CONTEXTS(CommandBufferTest, reporter, context) {
drawWriter.newDynamicState();
Shape shape(d.fRect);
DrawOrder order(depth);
DrawGeometry geom{kIdentity, shape, {shape.bounds(), kBounds}, order, nullptr};
DrawParams params{kIdentity, Geometry{shape}, {shape.bounds(), kBounds}, order,
nullptr};
SkDEBUGCODE(gatherer.checkReset());
step->writeUniforms(geom, &gatherer);
step->writeUniforms(params, &gatherer);
if (gatherer.hasUniforms()) {
SkUniformDataBlock renderStepUniforms = gatherer.peekUniformData();
auto [writer, bindInfo] = bufferMgr.getUniformWriter(renderStepUniforms.size());
@ -349,7 +352,7 @@ DEF_GRAPHITE_TEST_FOR_CONTEXTS(CommandBufferTest, reporter, context) {
sk_ref_sp(bindInfo.fBuffer),
bindInfo.fOffset);
step->writeVertices(&drawWriter, geom);
step->writeVertices(&drawWriter, params);
}
};