Use vertex writer for per-edge aa; remove templated tessellate function
Bug: skia: Change-Id: I5e1014cea7bb869636e6c706f54a2145e58214fd Reviewed-on: https://skia-review.googlesource.com/c/171229 Reviewed-by: Brian Osman <brianosman@google.com> Commit-Queue: Michael Ludwig <michaelludwig@google.com>
This commit is contained in:
parent
2c8e2bc682
commit
c182b9470f
@ -32,16 +32,15 @@ static bool coords_form_rect(const float xs[4], const float ys[4]) {
|
|||||||
GrQuadType GrQuad::quadType() const {
|
GrQuadType GrQuad::quadType() const {
|
||||||
// Since GrQuad applies any perspective information at construction time, there's only two
|
// Since GrQuad applies any perspective information at construction time, there's only two
|
||||||
// types to choose from.
|
// types to choose from.
|
||||||
return coords_form_rect(fX, fY) ? GrQuadType::kRect_QuadType : GrQuadType::kStandard_QuadType;
|
return coords_form_rect(fX, fY) ? GrQuadType::kRect : GrQuadType::kStandard;
|
||||||
}
|
}
|
||||||
|
|
||||||
GrQuadType GrPerspQuad::quadType() const {
|
GrQuadType GrPerspQuad::quadType() const {
|
||||||
if (this->hasPerspective()) {
|
if (this->hasPerspective()) {
|
||||||
return GrQuadType::kPerspective_QuadType;
|
return GrQuadType::kPerspective;
|
||||||
} else {
|
} else {
|
||||||
// Rect or standard quad, can ignore w since they are all ones
|
// Rect or standard quad, can ignore w since they are all ones
|
||||||
return coords_form_rect(fX, fY) ? GrQuadType::kRect_QuadType
|
return coords_form_rect(fX, fY) ? GrQuadType::kRect : GrQuadType::kStandard;
|
||||||
: GrQuadType::kStandard_QuadType;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -69,7 +68,7 @@ void GrResolveAATypeForQuad(GrAAType requestedAAType, GrQuadAAFlags requestedEdg
|
|||||||
} else {
|
} else {
|
||||||
// For coverage AA, if the quad is a rect and it lines up with pixel boundaries
|
// For coverage AA, if the quad is a rect and it lines up with pixel boundaries
|
||||||
// then overall aa and per-edge aa can be completely disabled
|
// then overall aa and per-edge aa can be completely disabled
|
||||||
if (knownType == GrQuadType::kRect_QuadType && !quad.aaHasEffectOnRect()) {
|
if (knownType == GrQuadType::kRect && !quad.aaHasEffectOnRect()) {
|
||||||
*outAAType = GrAAType::kNone;
|
*outAAType = GrAAType::kNone;
|
||||||
*outEdgeFlags = GrQuadAAFlags::kNone;
|
*outEdgeFlags = GrQuadAAFlags::kNone;
|
||||||
}
|
}
|
||||||
@ -97,11 +96,11 @@ template void GrResolveAATypeForQuad(GrAAType, GrQuadAAFlags, const GrPerspQuad&
|
|||||||
|
|
||||||
GrQuadType GrQuadTypeForTransformedRect(const SkMatrix& matrix) {
|
GrQuadType GrQuadTypeForTransformedRect(const SkMatrix& matrix) {
|
||||||
if (matrix.rectStaysRect()) {
|
if (matrix.rectStaysRect()) {
|
||||||
return GrQuadType::kRect_QuadType;
|
return GrQuadType::kRect;
|
||||||
} else if (matrix.hasPerspective()) {
|
} else if (matrix.hasPerspective()) {
|
||||||
return GrQuadType::kPerspective_QuadType;
|
return GrQuadType::kPerspective;
|
||||||
} else {
|
} else {
|
||||||
return GrQuadType::kStandard_QuadType;
|
return GrQuadType::kStandard;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -143,7 +142,7 @@ GrQuad::GrQuad(const SkRect& rect, const SkMatrix& m) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool GrQuad::aaHasEffectOnRect() const {
|
bool GrQuad::aaHasEffectOnRect() const {
|
||||||
SkASSERT(this->quadType() == GrQuadType::kRect_QuadType);
|
SkASSERT(this->quadType() == GrQuadType::kRect);
|
||||||
return aa_affects_rect(fX[0], fY[0], fX[3], fY[3]);
|
return aa_affects_rect(fX[0], fY[0], fX[3], fY[3]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -188,7 +187,7 @@ GrPerspQuad::GrPerspQuad(const SkRect& rect, const SkMatrix& m) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool GrPerspQuad::aaHasEffectOnRect() const {
|
bool GrPerspQuad::aaHasEffectOnRect() const {
|
||||||
SkASSERT(this->quadType() == GrQuadType::kRect_QuadType);
|
SkASSERT(this->quadType() == GrQuadType::kRect);
|
||||||
// If rect, ws must all be 1s so no need to divide
|
// If rect, ws must all be 1s so no need to divide
|
||||||
return aa_affects_rect(fX[0], fY[0], fX[3], fY[3]);
|
return aa_affects_rect(fX[0], fY[0], fX[3], fY[3]);
|
||||||
}
|
}
|
||||||
|
@ -24,10 +24,12 @@ enum class GrQuadAAFlags;
|
|||||||
// ws() == all ones.
|
// ws() == all ones.
|
||||||
// 3. Is a perspective quad - the matrix has perspective, subsuming all previous quad types.
|
// 3. Is a perspective quad - the matrix has perspective, subsuming all previous quad types.
|
||||||
enum class GrQuadType {
|
enum class GrQuadType {
|
||||||
kRect_QuadType,
|
kRect,
|
||||||
kStandard_QuadType,
|
kStandard,
|
||||||
kPerspective_QuadType
|
kPerspective,
|
||||||
|
kLast = kPerspective
|
||||||
};
|
};
|
||||||
|
static const int kGrQuadTypeCount = static_cast<int>(GrQuadType::kLast) + 1;
|
||||||
|
|
||||||
// If an SkRect is transformed by this matrix, what class of quad is required to represent it. Since
|
// If an SkRect is transformed by this matrix, what class of quad is required to represent it. Since
|
||||||
// quadType() is only provided on Gr[Persp]Quad in debug builds, production code should use this
|
// quadType() is only provided on Gr[Persp]Quad in debug builds, production code should use this
|
||||||
@ -35,7 +37,7 @@ enum class GrQuadType {
|
|||||||
GrQuadType GrQuadTypeForTransformedRect(const SkMatrix& matrix);
|
GrQuadType GrQuadTypeForTransformedRect(const SkMatrix& matrix);
|
||||||
|
|
||||||
// Resolve disagreements between the overall requested AA type and the per-edge quad AA flags.
|
// Resolve disagreements between the overall requested AA type and the per-edge quad AA flags.
|
||||||
// knownQuadType must have come from GrQuadtypeForTransformedRect with the matrix that created the
|
// knownQuadType must have come from GrQuadTypeForTransformedRect with the matrix that created the
|
||||||
// provided quad. Both outAAType and outEdgeFlags will be updated.
|
// provided quad. Both outAAType and outEdgeFlags will be updated.
|
||||||
template <typename Q>
|
template <typename Q>
|
||||||
void GrResolveAATypeForQuad(GrAAType requestedAAType, GrQuadAAFlags requestedEdgeFlags,
|
void GrResolveAATypeForQuad(GrAAType requestedAAType, GrQuadAAFlags requestedEdgeFlags,
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
#include "GrQuadPerEdgeAA.h"
|
#include "GrQuadPerEdgeAA.h"
|
||||||
#include "GrQuad.h"
|
#include "GrQuad.h"
|
||||||
|
#include "GrVertexWriter.h"
|
||||||
#include "glsl/GrGLSLColorSpaceXformHelper.h"
|
#include "glsl/GrGLSLColorSpaceXformHelper.h"
|
||||||
#include "glsl/GrGLSLPrimitiveProcessor.h"
|
#include "glsl/GrGLSLPrimitiveProcessor.h"
|
||||||
#include "glsl/GrGLSLFragmentShaderBuilder.h"
|
#include "glsl/GrGLSLFragmentShaderBuilder.h"
|
||||||
@ -234,69 +235,45 @@ static SkPoint3 compute_non_aa_persp_edge_coeffs(const Sk4f& w) {
|
|||||||
// When there's guaranteed no perspective, the edge coefficients for non-AA quads is constant
|
// When there's guaranteed no perspective, the edge coefficients for non-AA quads is constant
|
||||||
static constexpr SkPoint3 kNonAANoPerspEdgeCoeffs = {0, 0, 1};
|
static constexpr SkPoint3 kNonAANoPerspEdgeCoeffs = {0, 0, 1};
|
||||||
|
|
||||||
// This packs the four quad vertices' values for a given channel (the data) into a block. Returns
|
|
||||||
// the offset for the next block to be written to localStorage
|
|
||||||
static int store(const Sk4f& data, float* localStorage, int offset) {
|
|
||||||
data.store(localStorage + offset);
|
|
||||||
return offset + 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
// This unpacks dimCt values from a series of channels. By initializing offset from 0 to 3 (plus
|
|
||||||
// any channels' offsets to skip over), the particular quad vertex can be accessed. Returns the
|
|
||||||
// offset for the next channel of data in localStorage.
|
|
||||||
static int load(const float* localStorage, int offset, float* coordOut, int dimCt) {
|
|
||||||
for (int i = 0; i < dimCt; i++) {
|
|
||||||
coordOut[i] = localStorage[offset];
|
|
||||||
offset += 4;
|
|
||||||
}
|
|
||||||
return offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
|
|
||||||
void GrQuadPerEdgeAA::TessellateImpl(void* vertices, size_t vertexSize, float* localStorage,
|
namespace GrQuadPerEdgeAA {
|
||||||
const GrPerspQuad& deviceQuad, int posDim, size_t posOffset, size_t posSize,
|
|
||||||
const void* color, size_t colorOffset, size_t colorSize,
|
////////////////// Tessellate Implementation
|
||||||
const GrPerspQuad& srcQuad, int srcDim, size_t srcOffset, size_t srcSize,
|
|
||||||
const void* domain, size_t domainOffset, size_t domainSize,
|
void* Tessellate(void* vertices, const VertexSpec& spec, const GrPerspQuad& deviceQuad,
|
||||||
GrQuadAAFlags aaFlags, size_t aaOffset, size_t aaSize) {
|
const GrColor& color, const GrPerspQuad& localQuad, const SkRect& domain,
|
||||||
// Make sure the device and local positions are dimensions that are supported
|
GrQuadAAFlags aaFlags) {
|
||||||
SkASSERT(posDim == 2 || posDim == 3);
|
bool deviceHasPerspective = spec.deviceQuadType() == GrQuadType::kPerspective;
|
||||||
SkASSERT(srcDim == 0 || srcDim == 2 || srcDim == 3);
|
bool localHasPerspective = spec.localQuadType() == GrQuadType::kPerspective;
|
||||||
// Make sure that the position sizes are the proper multiples of sizeof(float) since we copy
|
|
||||||
// floats directly into the block without converting types
|
|
||||||
SkASSERT(posSize == posDim * sizeof(float));
|
|
||||||
SkASSERT(srcSize == srcDim * sizeof(float));
|
|
||||||
// Make sure the component sizes completely fill the vertex
|
|
||||||
SkASSERT(vertexSize == posSize + colorSize + srcSize + domainSize + aaSize);
|
|
||||||
|
|
||||||
// Load position data into Sk4fs (always x, y and maybe w)
|
// Load position data into Sk4fs (always x, y and maybe w)
|
||||||
Sk4f x = deviceQuad.x4f();
|
Sk4f x = deviceQuad.x4f();
|
||||||
Sk4f y = deviceQuad.y4f();
|
Sk4f y = deviceQuad.y4f();
|
||||||
Sk4f w;
|
Sk4f w;
|
||||||
if (posDim == 3) {
|
if (deviceHasPerspective) {
|
||||||
w = deviceQuad.w4f();
|
w = deviceQuad.w4f();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load local position data into Sk4fs (either none, just u,v or all three)
|
// Load local position data into Sk4fs (either none, just u,v or all three)
|
||||||
Sk4f u, v, r;
|
Sk4f u, v, r;
|
||||||
if (srcDim > 0) {
|
if (spec.hasLocalCoords()) {
|
||||||
u = srcQuad.x4f();
|
u = localQuad.x4f();
|
||||||
v = srcQuad.y4f();
|
v = localQuad.y4f();
|
||||||
|
|
||||||
if (srcDim == 3) {
|
if (localHasPerspective) {
|
||||||
r = srcQuad.w4f();
|
r = localQuad.w4f();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Sk4f a, b, c;
|
Sk4f a, b, c;
|
||||||
if (aaSize) {
|
if (spec.usesCoverageAA()) {
|
||||||
// Must calculate edges and possibly outside the positions
|
// Must calculate edges and possibly outside the positions
|
||||||
if (aaFlags == GrQuadAAFlags::kNone) {
|
if (aaFlags == GrQuadAAFlags::kNone) {
|
||||||
// A non-AA quad that got batched into an AA group, so its edges will be the same for
|
// A non-AA quad that got batched into an AA group, so its edges will be the same for
|
||||||
// all four vertices and it does not need to be outset
|
// all four vertices and it does not need to be outset
|
||||||
SkPoint3 edgeCoeffs;
|
SkPoint3 edgeCoeffs;
|
||||||
if (posDim == 3) {
|
if (deviceHasPerspective) {
|
||||||
edgeCoeffs = compute_non_aa_persp_edge_coeffs(w);
|
edgeCoeffs = compute_non_aa_persp_edge_coeffs(w);
|
||||||
} else {
|
} else {
|
||||||
edgeCoeffs = kNonAANoPerspEdgeCoeffs;
|
edgeCoeffs = kNonAANoPerspEdgeCoeffs;
|
||||||
@ -306,99 +283,93 @@ void GrQuadPerEdgeAA::TessellateImpl(void* vertices, size_t vertexSize, float* l
|
|||||||
a = edgeCoeffs.fX;
|
a = edgeCoeffs.fX;
|
||||||
b = edgeCoeffs.fY;
|
b = edgeCoeffs.fY;
|
||||||
c = edgeCoeffs.fZ;
|
c = edgeCoeffs.fZ;
|
||||||
} else if (posDim == 2) {
|
} else if (deviceHasPerspective) {
|
||||||
// For simplicity, pointers to u, v, and r are always provided, but srcDim
|
// For simplicity, pointers to u, v, and r are always provided, but the local dim param
|
||||||
// ensures that only loaded Sk4fs are modified in the compute functions.
|
// ensures that only loaded Sk4fs are modified in the compute functions.
|
||||||
compute_quad_edges_and_outset_vertices(
|
compute_quad_edges_and_outset_persp_vertices(aaFlags, &x, &y, &w, &a, &b, &c,
|
||||||
aaFlags, &x, &y, &a, &b, &c, &u, &v, &r, srcDim, /* outset */ true);
|
&u, &v, &r, spec.localDimensionality());
|
||||||
} else {
|
} else {
|
||||||
compute_quad_edges_and_outset_persp_vertices(
|
compute_quad_edges_and_outset_vertices(aaFlags, &x, &y, &a, &b, &c, &u, &v, &r,
|
||||||
aaFlags, &x, &y, &w, &a, &b, &c, &u, &v, &r, srcDim);
|
spec.localDimensionality(), /* outset */ true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// It is faster to unpack the Sk4fs all at once than access their components out of order.
|
// Now rearrange the Sk4fs into the interleaved vertex layout:
|
||||||
int offset = store(x, localStorage, 0);
|
// i.e. x1x2x3x4 y1y2y3y4 -> x1y1 x2y2 x3y3 x4y
|
||||||
offset = store(y, localStorage, offset);
|
GrVertexWriter vb{vertices};
|
||||||
if (posDim == 3) {
|
|
||||||
offset = store(w, localStorage, offset);
|
|
||||||
}
|
|
||||||
if (srcDim > 0) {
|
|
||||||
offset = store(u, localStorage, offset);
|
|
||||||
offset = store(v, localStorage, offset);
|
|
||||||
if (srcDim == 3) {
|
|
||||||
offset = store(r, localStorage, offset);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
int edgeOffset = offset; // The 4 edges are separate from the 4 vertices
|
|
||||||
if (aaSize) {
|
|
||||||
offset = store(a, localStorage, offset);
|
|
||||||
offset = store(b, localStorage, offset);
|
|
||||||
offset = store(c, localStorage, offset);
|
|
||||||
}
|
|
||||||
// Now rearrange the unpacked buffer into the vertex layout
|
|
||||||
char* vb = reinterpret_cast<char*>(vertices);
|
|
||||||
for (int i = 0; i < 4; ++i) {
|
for (int i = 0; i < 4; ++i) {
|
||||||
// Starting the offset at i makes sure that all loads read the data for the i^th vertex
|
|
||||||
offset = i;
|
|
||||||
|
|
||||||
// NOTE: while this code uses explicit offsets to make it independent of the actual
|
|
||||||
// vertex layout, it is a good idea to keep the writes in the same order as the fields
|
|
||||||
|
|
||||||
// save position
|
// save position
|
||||||
offset = load(localStorage, offset, reinterpret_cast<float*>(vb + posOffset), posDim);
|
if (deviceHasPerspective) {
|
||||||
|
vb.write<SkPoint3>({x[i], y[i], w[i]});
|
||||||
|
} else {
|
||||||
|
vb.write<SkPoint>({x[i], y[i]});
|
||||||
|
}
|
||||||
|
|
||||||
// save color
|
// save color
|
||||||
if (colorSize) {
|
if (spec.hasVertexColors()) {
|
||||||
memcpy(vb + colorOffset, color, colorSize);
|
vb.write<GrColor>(color);
|
||||||
}
|
}
|
||||||
|
|
||||||
// save local position
|
// save local position
|
||||||
if (srcDim) {
|
if (spec.hasLocalCoords()) {
|
||||||
offset = load(localStorage, offset, reinterpret_cast<float*>(vb + srcOffset), srcDim);
|
if (localHasPerspective) {
|
||||||
|
vb.write<SkPoint3>({u[i], v[i], r[i]});
|
||||||
|
} else {
|
||||||
|
vb.write<SkPoint>({u[i], v[i]});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// save the domain
|
// save the domain
|
||||||
if (domainSize) {
|
if (spec.hasDomain()) {
|
||||||
memcpy(vb + domainOffset, domain, domainSize);
|
vb.write<SkRect>(domain);
|
||||||
}
|
}
|
||||||
|
|
||||||
// save the edges
|
// save the edges
|
||||||
if (aaSize) {
|
if (spec.usesCoverageAA()) {
|
||||||
float* edgeBuffer = reinterpret_cast<float*>(vb + aaOffset);
|
|
||||||
for (int j = 0; j < 4; j++) {
|
for (int j = 0; j < 4; j++) {
|
||||||
load(localStorage, edgeOffset + j, edgeBuffer, 3);
|
vb.write<SkPoint3>({a[j], b[j], c[j]});
|
||||||
edgeBuffer += 3;
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
vb += vertexSize;
|
return vb.fPtr;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
GrQuadPerEdgeAA::GPAttributes::GPAttributes(int posDim, int localDim, bool hasColor, GrAAType aa,
|
////////////////// VertexSpec Implementation
|
||||||
Domain domain) {
|
|
||||||
SkASSERT(posDim == 2 || posDim == 3);
|
|
||||||
SkASSERT(localDim == 0 || localDim == 2 || localDim == 3);
|
|
||||||
|
|
||||||
if (posDim == 3) {
|
int VertexSpec::deviceDimensionality() const {
|
||||||
|
return this->deviceQuadType() == GrQuadType::kPerspective ? 3 : 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
int VertexSpec::localDimensionality() const {
|
||||||
|
return fHasLocalCoords ? (this->localQuadType() == GrQuadType::kPerspective ? 3 : 2) : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////// GPAttributes Implementation
|
||||||
|
|
||||||
|
GPAttributes::GPAttributes(const VertexSpec& spec) {
|
||||||
|
if (spec.deviceDimensionality() == 3) {
|
||||||
fPositions = {"position", kFloat3_GrVertexAttribType, kFloat3_GrSLType};
|
fPositions = {"position", kFloat3_GrVertexAttribType, kFloat3_GrSLType};
|
||||||
} else {
|
} else {
|
||||||
fPositions = {"position", kFloat2_GrVertexAttribType, kFloat2_GrSLType};
|
fPositions = {"position", kFloat2_GrVertexAttribType, kFloat2_GrSLType};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int localDim = spec.localDimensionality();
|
||||||
if (localDim == 3) {
|
if (localDim == 3) {
|
||||||
fLocalCoords = {"localCoord", kFloat3_GrVertexAttribType, kFloat3_GrSLType};
|
fLocalCoords = {"localCoord", kFloat3_GrVertexAttribType, kFloat3_GrSLType};
|
||||||
} else if (localDim == 2) {
|
} else if (localDim == 2) {
|
||||||
fLocalCoords = {"localCoord", kFloat2_GrVertexAttribType, kFloat2_GrSLType};
|
fLocalCoords = {"localCoord", kFloat2_GrVertexAttribType, kFloat2_GrSLType};
|
||||||
} // else localDim == 0 and attribute remains uninitialized
|
} // else localDim == 0 and attribute remains uninitialized
|
||||||
|
|
||||||
if (hasColor) {
|
if (spec.hasVertexColors()) {
|
||||||
fColors = {"color", kUByte4_norm_GrVertexAttribType, kHalf4_GrSLType};
|
fColors = {"color", kUByte4_norm_GrVertexAttribType, kHalf4_GrSLType};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (domain == Domain::kYes) {
|
if (spec.hasDomain()) {
|
||||||
fDomain = {"domain", kFloat4_GrVertexAttribType, kFloat4_GrSLType};
|
fDomain = {"domain", kFloat4_GrVertexAttribType, kFloat4_GrSLType};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (aa == GrAAType::kCoverage) {
|
if (spec.usesCoverageAA()) {
|
||||||
fAAEdges[0] = {"aaEdge0", kFloat3_GrVertexAttribType, kFloat3_GrSLType};
|
fAAEdges[0] = {"aaEdge0", kFloat3_GrVertexAttribType, kFloat3_GrSLType};
|
||||||
fAAEdges[1] = {"aaEdge1", kFloat3_GrVertexAttribType, kFloat3_GrSLType};
|
fAAEdges[1] = {"aaEdge1", kFloat3_GrVertexAttribType, kFloat3_GrSLType};
|
||||||
fAAEdges[2] = {"aaEdge2", kFloat3_GrVertexAttribType, kFloat3_GrSLType};
|
fAAEdges[2] = {"aaEdge2", kFloat3_GrVertexAttribType, kFloat3_GrSLType};
|
||||||
@ -406,13 +377,13 @@ GrQuadPerEdgeAA::GPAttributes::GPAttributes(int posDim, int localDim, bool hasCo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GrQuadPerEdgeAA::GPAttributes::needsPerspectiveInterpolation() const {
|
bool GPAttributes::needsPerspectiveInterpolation() const {
|
||||||
// This only needs to check the position; local position having perspective does not change
|
// This only needs to check the position; local position having perspective does not change
|
||||||
// how the varyings are interpolated
|
// how the varyings are interpolated
|
||||||
return fPositions.cpuType() == kFloat3_GrVertexAttribType;
|
return fPositions.cpuType() == kFloat3_GrVertexAttribType;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t GrQuadPerEdgeAA::GPAttributes::getKey() const {
|
uint32_t GPAttributes::getKey() const {
|
||||||
// aa, color, domain are single bit flags
|
// aa, color, domain are single bit flags
|
||||||
uint32_t x = this->usesCoverageAA() ? 0 : 1;
|
uint32_t x = this->usesCoverageAA() ? 0 : 1;
|
||||||
x |= this->hasVertexColors() ? 0 : 2;
|
x |= this->hasVertexColors() ? 0 : 2;
|
||||||
@ -426,7 +397,7 @@ uint32_t GrQuadPerEdgeAA::GPAttributes::getKey() const {
|
|||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GrQuadPerEdgeAA::GPAttributes::emitColor(GrGLSLPrimitiveProcessor::EmitArgs& args,
|
void GPAttributes::emitColor(GrGLSLPrimitiveProcessor::EmitArgs& args,
|
||||||
GrGLSLColorSpaceXformHelper* csXformHelper,
|
GrGLSLColorSpaceXformHelper* csXformHelper,
|
||||||
const char* colorVarName) const {
|
const char* colorVarName) const {
|
||||||
using Interpolation = GrGLSLVaryingHandler::Interpolation;
|
using Interpolation = GrGLSLVaryingHandler::Interpolation;
|
||||||
@ -450,7 +421,7 @@ void GrQuadPerEdgeAA::GPAttributes::emitColor(GrGLSLPrimitiveProcessor::EmitArgs
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GrQuadPerEdgeAA::GPAttributes::emitExplicitLocalCoords(
|
void GPAttributes::emitExplicitLocalCoords(
|
||||||
GrGLSLPrimitiveProcessor::EmitArgs& args, const char* localCoordName,
|
GrGLSLPrimitiveProcessor::EmitArgs& args, const char* localCoordName,
|
||||||
const char* domainName) const {
|
const char* domainName) const {
|
||||||
using Interpolation = GrGLSLVaryingHandler::Interpolation;
|
using Interpolation = GrGLSLVaryingHandler::Interpolation;
|
||||||
@ -480,7 +451,7 @@ void GrQuadPerEdgeAA::GPAttributes::emitExplicitLocalCoords(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GrQuadPerEdgeAA::GPAttributes::emitCoverage(GrGLSLPrimitiveProcessor::EmitArgs& args,
|
void GPAttributes::emitCoverage(GrGLSLPrimitiveProcessor::EmitArgs& args,
|
||||||
const char* edgeDistName) const {
|
const char* edgeDistName) const {
|
||||||
if (this->usesCoverageAA()) {
|
if (this->usesCoverageAA()) {
|
||||||
bool mulByFragCoordW = false;
|
bool mulByFragCoordW = false;
|
||||||
@ -528,3 +499,5 @@ void GrQuadPerEdgeAA::GPAttributes::emitCoverage(GrGLSLPrimitiveProcessor::EmitA
|
|||||||
args.fFragBuilder->codeAppendf("%s = float4(1);", args.fOutputCoverage);
|
args.fFragBuilder->codeAppendf("%s = float4(1);", args.fOutputCoverage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace GrQuadPerEdgeAA
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
#include "GrColor.h"
|
#include "GrColor.h"
|
||||||
#include "GrPrimitiveProcessor.h"
|
#include "GrPrimitiveProcessor.h"
|
||||||
|
#include "GrQuad.h"
|
||||||
#include "GrSamplerState.h"
|
#include "GrSamplerState.h"
|
||||||
#include "GrTypesPriv.h"
|
#include "GrTypesPriv.h"
|
||||||
#include "glsl/GrGLSLPrimitiveProcessor.h"
|
#include "glsl/GrGLSLPrimitiveProcessor.h"
|
||||||
@ -17,47 +18,47 @@
|
|||||||
#include "SkPoint3.h"
|
#include "SkPoint3.h"
|
||||||
|
|
||||||
class GrGLSLColorSpaceXformHelper;
|
class GrGLSLColorSpaceXformHelper;
|
||||||
class GrPerspQuad;
|
|
||||||
|
|
||||||
class GrQuadPerEdgeAA {
|
namespace GrQuadPerEdgeAA {
|
||||||
public:
|
|
||||||
enum class Domain : bool { kNo = false, kYes = true };
|
enum class Domain : bool { kNo = false, kYes = true };
|
||||||
|
|
||||||
// The vertex template provides a clean way of specifying the layout and components of a vertex
|
// Specifies the vertex configuration for an op that renders per-edge AA quads. The vertex
|
||||||
// for a per-edge aa quad. However, because there are so many permutations possible, the struct
|
// order (when enabled) is device position, color, local position, domain, aa edge equations.
|
||||||
// is defined this way to take away all layout control from the compiler and make
|
// This order matches the constructor argument order of VertexSpec and is the order that
|
||||||
// sure that it matches what we need to send to the GPU.
|
// GPAttributes maintains. If hasLocalCoords is false, then the local quad type can be ignored.
|
||||||
//
|
struct VertexSpec {
|
||||||
// It is expected that most code using these vertices will only need to call the templated
|
public:
|
||||||
// Tessellate() function with an appropriately sized vertex buffer and not need to modify or
|
VertexSpec(GrQuadType deviceQuadType, bool hasColor, GrQuadType localQuadType,
|
||||||
// read the fields of a particular vertex.
|
bool hasLocalCoords, Domain domain, GrAAType aa)
|
||||||
template <int PosDim, typename C, int LocalPosDim, Domain D, GrAA AA>
|
: fDeviceQuadType(static_cast<unsigned>(deviceQuadType))
|
||||||
struct Vertex {
|
, fLocalQuadType(static_cast<unsigned>(localQuadType))
|
||||||
using Color = C;
|
, fHasLocalCoords(hasLocalCoords)
|
||||||
static constexpr GrAA kAA = AA;
|
, fHasColor(hasColor)
|
||||||
static constexpr Domain kDomain = D;
|
, fHasDomain(static_cast<unsigned>(domain))
|
||||||
static constexpr size_t kPositionDim = PosDim;
|
, fUsesCoverageAA(aa == GrAAType::kCoverage) { }
|
||||||
static constexpr size_t kLocalPositionDim = LocalPosDim;
|
|
||||||
|
|
||||||
static constexpr size_t kPositionOffset = 0;
|
GrQuadType deviceQuadType() const { return static_cast<GrQuadType>(fDeviceQuadType); }
|
||||||
static constexpr size_t kPositionSize = PosDim * sizeof(float);
|
GrQuadType localQuadType() const { return static_cast<GrQuadType>(fLocalQuadType); }
|
||||||
|
bool hasLocalCoords() const { return fHasLocalCoords; }
|
||||||
|
bool hasVertexColors() const { return fHasColor; }
|
||||||
|
bool hasDomain() const { return fHasDomain; }
|
||||||
|
bool usesCoverageAA() const { return fUsesCoverageAA; }
|
||||||
|
|
||||||
static constexpr size_t kColorOffset = kPositionOffset + kPositionSize;
|
// Will always be 2 or 3
|
||||||
static constexpr size_t kColorSize = sizeof(Color);
|
int deviceDimensionality() const;
|
||||||
|
// Will always be 0 if hasLocalCoords is false, otherwise will be 2 or 3
|
||||||
|
int localDimensionality() const;
|
||||||
|
|
||||||
static constexpr size_t kLocalPositionOffset = kColorOffset + kColorSize;
|
private:
|
||||||
static constexpr size_t kLocalPositionSize = LocalPosDim * sizeof(float);
|
static_assert(kGrQuadTypeCount <= 4, "GrQuadType doesn't fit in 2 bits");
|
||||||
|
|
||||||
static constexpr size_t kDomainOffset = kLocalPositionOffset + kLocalPositionSize;
|
unsigned fDeviceQuadType: 2;
|
||||||
static constexpr size_t kDomainSize = D == Domain::kYes ? sizeof(SkRect) : 0;
|
unsigned fLocalQuadType: 2;
|
||||||
|
unsigned fHasLocalCoords: 1;
|
||||||
static constexpr size_t kAAOffset = kDomainOffset + kDomainSize;
|
unsigned fHasColor: 1;
|
||||||
static constexpr size_t kAASize = AA == GrAA::kYes ? 4 * sizeof(SkPoint3) : 0;
|
unsigned fHasDomain: 1;
|
||||||
|
unsigned fUsesCoverageAA: 1;
|
||||||
static constexpr size_t kVertexSize = kAAOffset + kAASize;
|
|
||||||
|
|
||||||
// Make sure sizeof(Vertex<...>) == kVertexSize
|
|
||||||
char fData[kVertexSize];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Utility class that manages the attribute state necessary to render a particular batch of
|
// Utility class that manages the attribute state necessary to render a particular batch of
|
||||||
@ -77,7 +78,7 @@ public:
|
|||||||
public:
|
public:
|
||||||
using Attribute = GrPrimitiveProcessor::Attribute;
|
using Attribute = GrPrimitiveProcessor::Attribute;
|
||||||
|
|
||||||
GPAttributes(int posDim, int localDim, bool hasColor, GrAAType aa, Domain domain);
|
GPAttributes(const VertexSpec& vertexSpec);
|
||||||
|
|
||||||
const Attribute& positions() const { return fPositions; }
|
const Attribute& positions() const { return fPositions; }
|
||||||
const Attribute& colors() const { return fColors; }
|
const Attribute& colors() const { return fColors; }
|
||||||
@ -131,44 +132,18 @@ public:
|
|||||||
Attribute fAAEdges[4]; // named "aaEdgeX" for X = 0,1,2,3
|
Attribute fAAEdges[4]; // named "aaEdgeX" for X = 0,1,2,3
|
||||||
};
|
};
|
||||||
|
|
||||||
// Tessellate the given quad specification into the vertices buffer. If the specific vertex
|
|
||||||
// type does not use color, local positions, domain, etc. then the passed in values used for
|
|
||||||
// that field will be ignored.
|
|
||||||
template<typename V>
|
|
||||||
static void Tessellate(V* vertices, const GrPerspQuad& deviceQuad, typename V::Color color,
|
|
||||||
const GrPerspQuad& srcQuad, const SkRect& domain, GrQuadAAFlags aa) {
|
|
||||||
static_assert(sizeof(V) == V::kVertexSize, "Incorrect vertex size");
|
|
||||||
static constexpr bool useCoverageAA = V::kAA == GrAA::kYes;
|
|
||||||
float localStorage[4 * (V::kPositionDim + V::kLocalPositionDim + (useCoverageAA ? 3 : 0))];
|
|
||||||
TessellateImpl(vertices, V::kVertexSize, localStorage,
|
|
||||||
deviceQuad, V::kPositionDim, V::kPositionOffset, V::kPositionSize,
|
|
||||||
&color, V::kColorOffset, V::kColorSize,
|
|
||||||
srcQuad, V::kLocalPositionDim, V::kLocalPositionOffset, V::kLocalPositionSize,
|
|
||||||
&domain, V::kDomainOffset, V::kDomainSize,
|
|
||||||
aa, V::kAAOffset, V::kAASize);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
// Fill vertices with the vertex data needed to represent the given quad. The device position,
|
||||||
// Don't let the "namespace" class be instantiated
|
// local coords, vertex color, domain, and edge coefficients will be written and/or computed
|
||||||
GrQuadPerEdgeAA();
|
// based on the configuration in the vertex spec; if that attribute is disabled in the spec,
|
||||||
|
// then its corresponding function argument is ignored.
|
||||||
|
//
|
||||||
|
// Returns the advanced pointer in vertices.
|
||||||
|
// TODO4F: Switch GrColor to GrVertexColor
|
||||||
|
void* Tessellate(void* vertices, const VertexSpec& spec, const GrPerspQuad& deviceQuad,
|
||||||
|
const GrColor& color, const GrPerspQuad& localQuad, const SkRect& domain,
|
||||||
|
GrQuadAAFlags aa);
|
||||||
|
|
||||||
// Internal implementation that can handle all vertex template variations without being
|
} // namespace GrQuadPerEdgeAA
|
||||||
// replicated by the template in order to keep code size down.
|
|
||||||
//
|
|
||||||
// This uses the field sizes to determine if particular data needs to be computed. The arguments
|
|
||||||
// are arranged so that the data and field specification match the field declaration order of
|
|
||||||
// the vertex type (pos, color, localPos, domain, aa).
|
|
||||||
//
|
|
||||||
// localStorage must be have a length > 4 * (devDimCt + srcDimCt + (aa ? 3 : 0)) and is assumed
|
|
||||||
// to be a pointer to a local variable in the wrapping template's stack. This is done instead of
|
|
||||||
// always allocating 36 floats in this function (36 is maximum needed). The minimum needed for a
|
|
||||||
// non-AA 2D quad with no local coordinates is just 8.
|
|
||||||
static void TessellateImpl(void* vertices, size_t vertexSize, float* localStorage,
|
|
||||||
const GrPerspQuad& deviceQuad, int posDim, size_t posOffset, size_t posSize,
|
|
||||||
const void* color, size_t colorOffset, size_t colorSize,
|
|
||||||
const GrPerspQuad& srcQuad, int srcDim, size_t srcOffset, size_t srcSize,
|
|
||||||
const void* domain, size_t domainOffset, size_t domainSize,
|
|
||||||
GrQuadAAFlags aaFlags, size_t aaOffset, size_t aaSize);
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // GrQuadPerEdgeAA_DEFINED
|
#endif // GrQuadPerEdgeAA_DEFINED
|
||||||
|
@ -37,6 +37,7 @@
|
|||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
using Domain = GrQuadPerEdgeAA::Domain;
|
using Domain = GrQuadPerEdgeAA::Domain;
|
||||||
|
using VertexSpec = GrQuadPerEdgeAA::VertexSpec;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Geometry Processor that draws a texture modulated by a vertex color (though, this is meant to be
|
* Geometry Processor that draws a texture modulated by a vertex color (though, this is meant to be
|
||||||
@ -50,11 +51,10 @@ public:
|
|||||||
const GrSamplerState::Filter filter,
|
const GrSamplerState::Filter filter,
|
||||||
sk_sp<GrColorSpaceXform> textureColorSpaceXform,
|
sk_sp<GrColorSpaceXform> textureColorSpaceXform,
|
||||||
sk_sp<GrColorSpaceXform> paintColorSpaceXform,
|
sk_sp<GrColorSpaceXform> paintColorSpaceXform,
|
||||||
int positionDim, GrAAType aa, Domain domain,
|
const VertexSpec& vertexSpec, const GrShaderCaps& caps) {
|
||||||
const GrShaderCaps& caps) {
|
|
||||||
return sk_sp<TextureGeometryProcessor>(new TextureGeometryProcessor(
|
return sk_sp<TextureGeometryProcessor>(new TextureGeometryProcessor(
|
||||||
textureType, textureConfig, filter, std::move(textureColorSpaceXform),
|
textureType, textureConfig, filter, std::move(textureColorSpaceXform),
|
||||||
std::move(paintColorSpaceXform), positionDim, aa, domain, caps));
|
std::move(paintColorSpaceXform), vertexSpec, caps));
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* name() const override { return "TextureGeometryProcessor"; }
|
const char* name() const override { return "TextureGeometryProcessor"; }
|
||||||
@ -117,13 +117,14 @@ private:
|
|||||||
TextureGeometryProcessor(GrTextureType textureType, GrPixelConfig textureConfig,
|
TextureGeometryProcessor(GrTextureType textureType, GrPixelConfig textureConfig,
|
||||||
GrSamplerState::Filter filter,
|
GrSamplerState::Filter filter,
|
||||||
sk_sp<GrColorSpaceXform> textureColorSpaceXform,
|
sk_sp<GrColorSpaceXform> textureColorSpaceXform,
|
||||||
sk_sp<GrColorSpaceXform> paintColorSpaceXform, int positionDim,
|
sk_sp<GrColorSpaceXform> paintColorSpaceXform,
|
||||||
GrAAType aa, Domain domain, const GrShaderCaps& caps)
|
const VertexSpec& vertexSpec, const GrShaderCaps& caps)
|
||||||
: INHERITED(kTextureGeometryProcessor_ClassID)
|
: INHERITED(kTextureGeometryProcessor_ClassID)
|
||||||
, fAttrs(positionDim, /* src dim */ 2, /* vertex color */ true, aa, domain)
|
, fAttrs(vertexSpec)
|
||||||
, fTextureColorSpaceXform(std::move(textureColorSpaceXform))
|
, fTextureColorSpaceXform(std::move(textureColorSpaceXform))
|
||||||
, fPaintColorSpaceXform(std::move(paintColorSpaceXform))
|
, fPaintColorSpaceXform(std::move(paintColorSpaceXform))
|
||||||
, fSampler(textureType, textureConfig, filter) {
|
, fSampler(textureType, textureConfig, filter) {
|
||||||
|
SkASSERT(vertexSpec.hasVertexColors() && vertexSpec.localDimensionality() == 2);
|
||||||
this->setTextureSamplerCnt(1);
|
this->setTextureSamplerCnt(1);
|
||||||
this->setVertexAttributes(fAttrs.attributes(), fAttrs.attributeCount());
|
this->setVertexAttributes(fAttrs.attributes(), fAttrs.attributeCount());
|
||||||
}
|
}
|
||||||
@ -139,7 +140,7 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
static bool filter_has_effect_for_rect_stays_rect(const GrPerspQuad& quad, const SkRect& srcRect) {
|
static bool filter_has_effect_for_rect_stays_rect(const GrPerspQuad& quad, const SkRect& srcRect) {
|
||||||
SkASSERT(quad.quadType() == GrQuadType::kRect_QuadType);
|
SkASSERT(quad.quadType() == GrQuadType::kRect);
|
||||||
float ql = quad.x(0);
|
float ql = quad.x(0);
|
||||||
float qt = quad.y(0);
|
float qt = quad.y(0);
|
||||||
float qr = quad.x(3);
|
float qr = quad.x(3);
|
||||||
@ -320,11 +321,11 @@ private:
|
|||||||
GrResolveAATypeForQuad(aaType, aaFlags, quad, quadType, &aaType, &aaFlags);
|
GrResolveAATypeForQuad(aaType, aaFlags, quad, quadType, &aaType, &aaFlags);
|
||||||
fAAType = static_cast<unsigned>(aaType);
|
fAAType = static_cast<unsigned>(aaType);
|
||||||
|
|
||||||
fPerspective = static_cast<unsigned>(quadType == GrQuadType::kPerspective_QuadType);
|
fPerspective = static_cast<unsigned>(quadType == GrQuadType::kPerspective);
|
||||||
// We expect our caller to have already caught this optimization.
|
// We expect our caller to have already caught this optimization.
|
||||||
SkASSERT(!srcRect.contains(proxy->getWorstCaseBoundsRect()) ||
|
SkASSERT(!srcRect.contains(proxy->getWorstCaseBoundsRect()) ||
|
||||||
constraint == SkCanvas::kFast_SrcRectConstraint);
|
constraint == SkCanvas::kFast_SrcRectConstraint);
|
||||||
if (quadType == GrQuadType::kRect_QuadType) {
|
if (quadType == GrQuadType::kRect) {
|
||||||
// Disable filtering if possible (note AA optimizations for rects are automatically
|
// Disable filtering if possible (note AA optimizations for rects are automatically
|
||||||
// handled above in GrResolveAATypeForQuad).
|
// handled above in GrResolveAATypeForQuad).
|
||||||
if (this->filter() != GrSamplerState::Filter::kNearest &&
|
if (this->filter() != GrSamplerState::Filter::kNearest &&
|
||||||
@ -386,7 +387,7 @@ private:
|
|||||||
overallAAType = aaType;
|
overallAAType = aaType;
|
||||||
}
|
}
|
||||||
if (!mustFilter && this->filter() != GrSamplerState::Filter::kNearest) {
|
if (!mustFilter && this->filter() != GrSamplerState::Filter::kNearest) {
|
||||||
mustFilter = quadType != GrQuadType::kRect_QuadType ||
|
mustFilter = quadType != GrQuadType::kRect ||
|
||||||
filter_has_effect_for_rect_stays_rect(quad, set[p].fSrcRect);
|
filter_has_effect_for_rect_stays_rect(quad, set[p].fSrcRect);
|
||||||
}
|
}
|
||||||
fQuads.emplace_back(set[p].fSrcRect, quad, aaFlags, SkCanvas::kFast_SrcRectConstraint,
|
fQuads.emplace_back(set[p].fSrcRect, quad, aaFlags, SkCanvas::kFast_SrcRectConstraint,
|
||||||
@ -401,13 +402,9 @@ private:
|
|||||||
fDomain = static_cast<unsigned>(false);
|
fDomain = static_cast<unsigned>(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <int PosDim, Domain D, GrAA AA>
|
void tess(void* v, const VertexSpec& spec, const GrTextureProxy* proxy,
|
||||||
void tess(void* v, const GrGeometryProcessor* gp, const GrTextureProxy* proxy, int start,
|
int start, int cnt) const {
|
||||||
int cnt) const {
|
|
||||||
TRACE_EVENT0("skia", TRACE_FUNC);
|
TRACE_EVENT0("skia", TRACE_FUNC);
|
||||||
using Vertex = GrQuadPerEdgeAA::Vertex<PosDim, GrColor, 2, D, AA>;
|
|
||||||
SkASSERT(gp->vertexStride() == sizeof(Vertex));
|
|
||||||
auto vertices = static_cast<Vertex*>(v);
|
|
||||||
auto origin = proxy->origin();
|
auto origin = proxy->origin();
|
||||||
const auto* texture = proxy->peekTexture();
|
const auto* texture = proxy->peekTexture();
|
||||||
float iw = 1.f / texture->width();
|
float iw = 1.f / texture->width();
|
||||||
@ -417,9 +414,8 @@ private:
|
|||||||
const auto q = fQuads[i];
|
const auto q = fQuads[i];
|
||||||
GrPerspQuad srcQuad = compute_src_quad(origin, q.srcRect(), iw, ih);
|
GrPerspQuad srcQuad = compute_src_quad(origin, q.srcRect(), iw, ih);
|
||||||
SkRect domain = compute_domain(q.domain(), this->filter(), origin, q.srcRect(), iw, ih);
|
SkRect domain = compute_domain(q.domain(), this->filter(), origin, q.srcRect(), iw, ih);
|
||||||
GrQuadPerEdgeAA::Tessellate<Vertex>(
|
v = GrQuadPerEdgeAA::Tessellate(v, spec, q.quad(), q.color(), srcQuad, domain,
|
||||||
vertices, q.quad(), q.color(), srcQuad, domain, q.aaFlags());
|
q.aaFlags());
|
||||||
vertices += 4;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -453,10 +449,13 @@ private:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VertexSpec vertexSpec(hasPerspective ? GrQuadType::kPerspective : GrQuadType::kStandard,
|
||||||
|
/* hasColor */ true, GrQuadType::kRect, /* hasLocal */ true,
|
||||||
|
domain, aaType);
|
||||||
|
|
||||||
sk_sp<GrGeometryProcessor> gp = TextureGeometryProcessor::Make(
|
sk_sp<GrGeometryProcessor> gp = TextureGeometryProcessor::Make(
|
||||||
textureType, config, this->filter(), std::move(fTextureColorSpaceXform),
|
textureType, config, this->filter(), std::move(fTextureColorSpaceXform),
|
||||||
std::move(fPaintColorSpaceXform), hasPerspective ? 3 : 2, aaType, domain,
|
std::move(fPaintColorSpaceXform), vertexSpec, *target->caps().shaderCaps());
|
||||||
*target->caps().shaderCaps());
|
|
||||||
GrPipeline::InitArgs args;
|
GrPipeline::InitArgs args;
|
||||||
args.fProxy = target->proxy();
|
args.fProxy = target->proxy();
|
||||||
args.fCaps = &target->caps();
|
args.fCaps = &target->caps();
|
||||||
@ -480,33 +479,8 @@ private:
|
|||||||
}
|
}
|
||||||
const auto* pipeline =
|
const auto* pipeline =
|
||||||
target->allocPipeline(args, GrProcessorSet::MakeEmptySet(), std::move(clip));
|
target->allocPipeline(args, GrProcessorSet::MakeEmptySet(), std::move(clip));
|
||||||
using TessFn = decltype(&TextureOp::tess<2, Domain::kNo, GrAA::kNo>);
|
|
||||||
#define TESS_FN_AND_VERTEX_SIZE(Point, Domain, AA) \
|
|
||||||
{ \
|
|
||||||
&TextureOp::tess<Point, Domain, AA>, \
|
|
||||||
sizeof(GrQuadPerEdgeAA::Vertex<Point, GrColor, 2, Domain, AA>) \
|
|
||||||
}
|
|
||||||
static constexpr struct {
|
|
||||||
TessFn fTessFn;
|
|
||||||
size_t fVertexSize;
|
|
||||||
} kTessFnsAndVertexSizes[] = {
|
|
||||||
TESS_FN_AND_VERTEX_SIZE(2, Domain::kNo, GrAA::kNo),
|
|
||||||
TESS_FN_AND_VERTEX_SIZE(2, Domain::kNo, GrAA::kYes),
|
|
||||||
TESS_FN_AND_VERTEX_SIZE(2, Domain::kYes, GrAA::kNo),
|
|
||||||
TESS_FN_AND_VERTEX_SIZE(2, Domain::kYes, GrAA::kYes),
|
|
||||||
TESS_FN_AND_VERTEX_SIZE(3, Domain::kNo, GrAA::kNo),
|
|
||||||
TESS_FN_AND_VERTEX_SIZE(3, Domain::kNo, GrAA::kYes),
|
|
||||||
TESS_FN_AND_VERTEX_SIZE(3, Domain::kYes, GrAA::kNo),
|
|
||||||
TESS_FN_AND_VERTEX_SIZE(3, Domain::kYes, GrAA::kYes),
|
|
||||||
};
|
|
||||||
#undef TESS_FN_AND_VERTEX_SIZE
|
|
||||||
int tessFnIdx = 0;
|
|
||||||
tessFnIdx |= (GrAAType::kCoverage == aaType) ? 0x1 : 0x0;
|
|
||||||
tessFnIdx |= (domain == Domain::kYes) ? 0x2 : 0x0;
|
|
||||||
tessFnIdx |= hasPerspective ? 0x4 : 0x0;
|
|
||||||
|
|
||||||
size_t vertexSize = kTessFnsAndVertexSizes[tessFnIdx].fVertexSize;
|
size_t vertexSize = gp->vertexStride();
|
||||||
SkASSERT(vertexSize == gp->vertexStride());
|
|
||||||
|
|
||||||
GrMesh* meshes = target->allocMeshes(numProxies);
|
GrMesh* meshes = target->allocMeshes(numProxies);
|
||||||
const GrBuffer* vbuffer;
|
const GrBuffer* vbuffer;
|
||||||
@ -534,8 +508,7 @@ private:
|
|||||||
}
|
}
|
||||||
SkASSERT(numAllocatedVertices >= meshVertexCnt);
|
SkASSERT(numAllocatedVertices >= meshVertexCnt);
|
||||||
|
|
||||||
(op.*(kTessFnsAndVertexSizes[tessFnIdx].fTessFn))(vdata, gp.get(), proxy, q,
|
op.tess(vdata, vertexSpec, proxy, q, quadCnt);
|
||||||
quadCnt);
|
|
||||||
|
|
||||||
if (quadCnt > 1) {
|
if (quadCnt > 1) {
|
||||||
meshes[m].setPrimitiveType(GrPrimitiveType::kTriangles);
|
meshes[m].setPrimitiveType(GrPrimitiveType::kTriangles);
|
||||||
|
Loading…
Reference in New Issue
Block a user