[graphite] Add instanced geometry for text.
Bug: skia:13118
Change-Id: Ifb738ffdefe489b08bfccedffa3d71c59818444c
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/562761
Reviewed-by: Michael Ludwig <michaelludwig@google.com>
Commit-Queue: Jim Van Verth <jvanverth@google.com>
diff --git a/src/gpu/graphite/DrawTypes.h b/src/gpu/graphite/DrawTypes.h
index e79e12c..9212c0b 100644
--- a/src/gpu/graphite/DrawTypes.h
+++ b/src/gpu/graphite/DrawTypes.h
@@ -71,7 +71,7 @@
kInt,
kUInt,
- kUShort_norm,
+ kUShort_norm, // unsigned short, e.g. depth, 0 -> 0.0f, 65535 -> 1.0f.
kUShort4_norm, // vector of 4 unsigned shorts. 0 -> 0.0f, 65535 -> 1.0f.
diff --git a/src/gpu/graphite/render/TextDirectRenderStep.cpp b/src/gpu/graphite/render/TextDirectRenderStep.cpp
index 76ab4de..2f3e57b 100644
--- a/src/gpu/graphite/render/TextDirectRenderStep.cpp
+++ b/src/gpu/graphite/render/TextDirectRenderStep.cpp
@@ -41,13 +41,16 @@
"",
Flags::kPerformsShading | Flags::kHasTextures | Flags::kEmitsCoverage,
/*uniforms=*/{{"atlasSizeInv", SkSLType::kFloat2}},
- PrimitiveType::kTriangles,
+ PrimitiveType::kTriangleStrip,
kDirectShadingPass,
- /*vertexAttrs=*/
- {{"position", VertexAttribType::kFloat2, SkSLType::kFloat2},
- {"depth", VertexAttribType::kFloat, SkSLType::kFloat},
- {"texCoords", VertexAttribType::kUShort2, SkSLType::kUShort2}},
- /*instanceAttrs=*/{},
+ /*vertexAttrs=*/ {},
+ /*instanceAttrs=*/
+ {{"mat0", VertexAttribType::kFloat3, SkSLType::kFloat3},
+ {"mat1", VertexAttribType::kFloat3, SkSLType::kFloat3},
+ {"mat2", VertexAttribType::kFloat3, SkSLType::kFloat3},
+ {"uvScale", VertexAttribType::kUShort2, SkSLType::kUShort2},
+ {"uvPos", VertexAttribType::kUShort2, SkSLType::kUShort2},
+ {"depth", VertexAttribType::kUShort_norm, SkSLType::kFloat}},
/*varyings=*/
{{"textureCoords", SkSLType::kFloat2},
{"texIndex", SkSLType::kFloat}})
@@ -57,14 +60,16 @@
const char* TextDirectRenderStep::vertexSkSL() const {
return R"(
- int2 coords = int2(texCoords.x, texCoords.y);
- int texIdx = coords.x >> 13;
- float2 unormTexCoords = float2(coords.x & 0x1FFF, coords.y);
+ float2 baseCoords = float2(float(sk_VertexID >> 1), float(sk_VertexID & 1));
+ baseCoords *= float2(uvScale);
+ float3 position = baseCoords.x*mat0 + baseCoords.y*mat1 + mat2;
+ int texIdx = (int)(uvPos.x >> 13);
+ float2 unormTexCoords = baseCoords + float2(uvPos.x & 0x1fff, uvPos.y);
textureCoords = unormTexCoords * atlasSizeInv;
texIndex = float(texIdx);
- float4 devPosition = float4(position, depth, 1);
+ float4 devPosition = float4(position.xy, depth, position.z);
)";
}
@@ -119,9 +124,10 @@
void TextDirectRenderStep::writeVertices(DrawWriter* dw, const DrawParams& params) const {
const SubRunData& subRunData = params.geometry().subRunData();
// TODO: pass through the color from the SkPaint via the SubRunData
- subRunData.subRun()->fillVertexData(dw, subRunData.startGlyphIndex(), subRunData.glyphCount(),
- params.order().depthAsFloat(),
- params.transform());
+ uint16_t unormDepth = params.order().depth().bits();
+
+ subRunData.subRun()->fillInstanceData(dw, subRunData.startGlyphIndex(), subRunData.glyphCount(),
+ unormDepth, params.transform());
}
void TextDirectRenderStep::writeUniformsAndTextures(const DrawParams& params,
diff --git a/src/gpu/graphite/render/TextSDFRenderStep.cpp b/src/gpu/graphite/render/TextSDFRenderStep.cpp
index 29c2ee0..dfc5295 100644
--- a/src/gpu/graphite/render/TextSDFRenderStep.cpp
+++ b/src/gpu/graphite/render/TextSDFRenderStep.cpp
@@ -40,13 +40,16 @@
Flags::kPerformsShading | Flags::kHasTextures | Flags::kEmitsCoverage,
/*uniforms=*/{{"atlasSizeInv", SkSLType::kFloat2},
{"distanceAdjust", SkSLType::kFloat}},
- PrimitiveType::kTriangles,
+ PrimitiveType::kTriangleStrip,
kDirectShadingPass,
- /*vertexAttrs=*/
- {{"position", VertexAttribType::kFloat2, SkSLType::kFloat2},
- {"depth", VertexAttribType::kFloat, SkSLType::kFloat},
- {"texCoords", VertexAttribType::kUShort2, SkSLType::kUShort2}},
- /*instanceAttrs=*/{},
+ /*vertexAttrs=*/ {},
+ /*instanceAttrs=*/
+ {{"mat0", VertexAttribType::kFloat3, SkSLType::kFloat3},
+ {"mat1", VertexAttribType::kFloat3, SkSLType::kFloat3},
+ {"mat2", VertexAttribType::kFloat3, SkSLType::kFloat3},
+ {"uvScale", VertexAttribType::kUShort2, SkSLType::kUShort2},
+ {"uvPos", VertexAttribType::kUShort2, SkSLType::kUShort2},
+ {"depth", VertexAttribType::kUShort_norm, SkSLType::kFloat}},
/*varyings=*/
{{"unormTexCoords", SkSLType::kFloat2},
{"textureCoords", SkSLType::kFloat2},
@@ -58,15 +61,18 @@
const char* TextSDFRenderStep::vertexSkSL() const {
return R"(
- int2 coords = int2(texCoords.x, texCoords.y);
- int texIdx = coords.x >> 13;
+ float2 baseCoords = float2(float(sk_VertexID >> 1), float(sk_VertexID & 1));
+ baseCoords *= float2(uvScale);
+ float3 position = baseCoords.x*mat0 + baseCoords.y*mat1 + mat2;
- unormTexCoords = float2(coords.x & 0x1FFF, coords.y);
+ int texIdx = (int)(uvPos.x >> 13);
+ unormTexCoords = baseCoords + float2(uvPos.x & 0x1fff, uvPos.y);
+
textureCoords = unormTexCoords * atlasSizeInv;
texIndex = float(texIdx);
- float4 devPosition = float4(position, depth, 1);
- )";
+ float4 devPosition = float4(position.xy, depth, position.z);
+ )";
}
std::string TextSDFRenderStep::texturesAndSamplersSkSL(int binding) const {
@@ -141,8 +147,9 @@
void TextSDFRenderStep::writeVertices(DrawWriter* dw, const DrawParams& params) const {
const SubRunData& subRunData = params.geometry().subRunData();
- subRunData.subRun()->fillVertexData(dw, subRunData.startGlyphIndex(), subRunData.glyphCount(),
- params.order().depthAsFloat(), params.transform());
+ uint16_t unormDepth = params.order().depth().bits();
+ subRunData.subRun()->fillInstanceData(dw, subRunData.startGlyphIndex(), subRunData.glyphCount(),
+ unormDepth, params.transform());
}
void TextSDFRenderStep::writeUniformsAndTextures(const DrawParams& params,
diff --git a/src/text/gpu/SubRunContainer.cpp b/src/text/gpu/SubRunContainer.cpp
index 73ba8a5..60d74a0 100644
--- a/src/text/gpu/SubRunContainer.cpp
+++ b/src/text/gpu/SubRunContainer.cpp
@@ -63,6 +63,8 @@
using namespace sktext::gpu;
#if defined(SK_GRAPHITE_ENABLED)
+using BindBufferInfo = skgpu::graphite::BindBufferInfo;
+using BufferType = skgpu::graphite::BufferType;
using Device = skgpu::graphite::Device;
using DrawWriter = skgpu::graphite::DrawWriter;
using Rect = skgpu::graphite::Rect;
@@ -130,6 +132,11 @@
SkSpan<const Glyph*> glyphs,
SkScalar depth,
const skgpu::graphite::Transform& toDevice) const;
+ void fillInstanceData(DrawWriter* dw,
+ int offset, int count,
+ SkSpan<const Glyph*> glyphs,
+ uint16_t depth,
+ const skgpu::graphite::Transform& toDevice) const;
#endif
SkRect deviceRect(const SkMatrix& drawMatrix, SkPoint drawOrigin) const;
MaskFormat grMaskType() const {return fMaskType;}
@@ -397,6 +404,36 @@
<< SkPoint{devOut[1].x, devOut[1].y} << depth << AtlasPt{ar, at}; // R,T
}
}
+
+void TransformedMaskVertexFiller::fillInstanceData(DrawWriter* dw,
+ int offset, int count,
+ SkSpan<const Glyph*> glyphs,
+ uint16_t depth,
+ const Transform& toDevice) const {
+ auto quadData = [&]() {
+ return SkMakeZip(glyphs.subspan(offset, count),
+ fLeftTop.subspan(offset, count));
+ };
+
+ DrawWriter::Instances instances{*dw, {}, {}, 4};
+ instances.reserve(count);
+ const SkM44& m44(toDevice);
+ skvx::float4 c0 = skvx::float4::Load(SkMatrixPriv::M44ColMajor(m44) + 0);
+ skvx::float4 c1 = skvx::float4::Load(SkMatrixPriv::M44ColMajor(m44) + 4);
+ skvx::float4 c3 = skvx::float4::Load(SkMatrixPriv::M44ColMajor(m44) + 12);
+ skvx::float4 newC0 = fStrikeToSourceScale*c0;
+ skvx::float4 newC1 = fStrikeToSourceScale*c1;
+ for (auto [glyph, leftTop]: quadData()) {
+ auto[al, at, ar, ab] = glyph->fAtlasLocator.getUVs();
+ skvx::float4 newC3 = leftTop.x()*c0 + leftTop.y()*c1 + c3;
+ instances.append(1) << newC0.x() << newC0.y() << newC0.w()
+ << newC1.x() << newC1.y() << newC1.w()
+ << newC3.x() << newC3.y() << newC3.w()
+ << AtlasPt{uint16_t(ar-al), uint16_t(ab-at)} << AtlasPt{al, at}
+ << depth;
+ }
+}
+
#endif
@@ -1206,6 +1243,10 @@
int offset, int count,
SkScalar depth,
const skgpu::graphite::Transform& transform) const override;
+ void fillInstanceData(skgpu::graphite::DrawWriter*,
+ int offset, int count,
+ uint16_t depth,
+ const skgpu::graphite::Transform& transform) const override;
MaskFormat maskFormat() const override { return fMaskFormat; }
#endif
@@ -1652,6 +1693,33 @@
transformed_direct_dw(dw, quadData(), depth, toDevice);
}
}
+
+void DirectMaskSubRun::fillInstanceData(DrawWriter* dw,
+ int offset, int count,
+ uint16_t depth,
+ const skgpu::graphite::Transform& toDevice) const {
+ auto quadData = [&]() {
+ return SkMakeZip(fGlyphs.glyphs().subspan(offset, count),
+ fLeftTopDevicePos.subspan(offset, count));
+ };
+
+ DrawWriter::Instances instances{*dw, {}, {}, 4};
+ instances.reserve(count);
+ const SkM44& m44(toDevice);
+ skvx::float4 c0 = skvx::float4::Load(SkMatrixPriv::M44ColMajor(m44) + 0);
+ skvx::float4 c1 = skvx::float4::Load(SkMatrixPriv::M44ColMajor(m44) + 4);
+ skvx::float4 c3 = skvx::float4::Load(SkMatrixPriv::M44ColMajor(m44) + 12);
+ for (auto [glyph, leftTop]: quadData()) {
+ auto[al, at, ar, ab] = glyph->fAtlasLocator.getUVs();
+ skvx::float4 newC3 = leftTop.x()*c0 + leftTop.y()*c1 + c3;
+ instances.append(1) << c0.x() << c0.y() << c0.w()
+ << c1.x() << c1.y() << c1.w()
+ << newC3.x() << newC3.y() << newC3.w()
+ << AtlasPt{uint16_t(ar-al), uint16_t(ab-at)} << AtlasPt{al, at}
+ << depth;
+ }
+}
+
#endif
// true if only need to translate by integer amount, device rect.
@@ -1755,6 +1823,10 @@
int offset, int count,
SkScalar depth,
const skgpu::graphite::Transform& transform) const override;
+ void fillInstanceData(DrawWriter*,
+ int offset, int count,
+ uint16_t depth,
+ const skgpu::graphite::Transform& transform) const override;
MaskFormat maskFormat() const override { return fVertexFiller.grMaskType(); }
#endif
@@ -1945,6 +2017,18 @@
depth,
transform);
}
+
+void TransformedMaskSubRun::fillInstanceData(DrawWriter* dw,
+ int offset, int count,
+ uint16_t depth,
+ const Transform& transform) const {
+ fVertexFiller.fillInstanceData(dw,
+ offset, count,
+ fGlyphs.glyphs(),
+ depth,
+ transform);
+}
+
#endif
int TransformedMaskSubRun::glyphCount() const {
@@ -2036,6 +2120,10 @@
int offset, int count,
SkScalar depth,
const skgpu::graphite::Transform& transform) const override;
+ void fillInstanceData(DrawWriter*,
+ int offset, int count,
+ uint16_t depth,
+ const skgpu::graphite::Transform& transform) const override;
MaskFormat maskFormat() const override { return fVertexFiller.grMaskType(); }
#endif
@@ -2283,13 +2371,24 @@
void SDFTSubRun::fillVertexData(DrawWriter* dw,
int offset, int count,
SkScalar depth,
- const skgpu::graphite::Transform& transform) const {
+ const Transform& transform) const {
fVertexFiller.fillVertexData(dw,
offset, count,
fGlyphs.glyphs(),
depth,
transform);
}
+
+void SDFTSubRun::fillInstanceData(DrawWriter* dw,
+ int offset, int count,
+ uint16_t depth,
+ const Transform& transform) const {
+ fVertexFiller.fillInstanceData(dw,
+ offset, count,
+ fGlyphs.glyphs(),
+ depth,
+ transform);
+}
#endif
int SDFTSubRun::glyphCount() const {
diff --git a/src/text/gpu/SubRunContainer.h b/src/text/gpu/SubRunContainer.h
index d0467b3..789dcf0 100644
--- a/src/text/gpu/SubRunContainer.h
+++ b/src/text/gpu/SubRunContainer.h
@@ -117,6 +117,11 @@
int offset, int count,
SkScalar depth,
const skgpu::graphite::Transform& transform) const = 0;
+ virtual void fillInstanceData(
+ skgpu::graphite::DrawWriter*,
+ int offset, int count,
+ uint16_t depth,
+ const skgpu::graphite::Transform& transform) const = 0;
virtual skgpu::MaskFormat maskFormat() const = 0;
#endif