Hairline batch
BUG=skia: Committed: https://skia.googlesource.com/skia/+/6eff8701f027016fbb3147412ec2292dcec2b7f5 Review URL: https://codereview.chromium.org/876673002
This commit is contained in:
parent
532faa9021
commit
658d55cd61
@ -7,6 +7,9 @@
|
||||
|
||||
#include "GrAAHairLinePathRenderer.h"
|
||||
|
||||
#include "GrBatch.h"
|
||||
#include "GrBatchTarget.h"
|
||||
#include "GrBufferAllocPool.h"
|
||||
#include "GrContext.h"
|
||||
#include "GrDefaultGeoProcFactory.h"
|
||||
#include "GrDrawTargetCaps.h"
|
||||
@ -253,14 +256,14 @@ int num_quad_subdivs(const SkPoint p[3]) {
|
||||
* subdivide large quads to reduce over-fill. This subdivision has to be
|
||||
* performed before applying the perspective matrix.
|
||||
*/
|
||||
int generate_lines_and_quads(const SkPath& path,
|
||||
const SkMatrix& m,
|
||||
const SkIRect& devClipBounds,
|
||||
GrAAHairLinePathRenderer::PtArray* lines,
|
||||
GrAAHairLinePathRenderer::PtArray* quads,
|
||||
GrAAHairLinePathRenderer::PtArray* conics,
|
||||
GrAAHairLinePathRenderer::IntArray* quadSubdivCnts,
|
||||
GrAAHairLinePathRenderer::FloatArray* conicWeights) {
|
||||
int gather_lines_and_quads(const SkPath& path,
|
||||
const SkMatrix& m,
|
||||
const SkIRect& devClipBounds,
|
||||
GrAAHairLinePathRenderer::PtArray* lines,
|
||||
GrAAHairLinePathRenderer::PtArray* quads,
|
||||
GrAAHairLinePathRenderer::PtArray* conics,
|
||||
GrAAHairLinePathRenderer::IntArray* quadSubdivCnts,
|
||||
GrAAHairLinePathRenderer::FloatArray* conicWeights) {
|
||||
SkPath::Iter iter(path, false);
|
||||
|
||||
int totalQuadCount = 0;
|
||||
@ -469,8 +472,7 @@ void set_uv_quad(const SkPoint qpts[3], BezierVertex verts[kQuadNumVertices]) {
|
||||
}
|
||||
|
||||
void bloat_quad(const SkPoint qpts[3], const SkMatrix* toDevice,
|
||||
const SkMatrix* toSrc, BezierVertex verts[kQuadNumVertices],
|
||||
SkRect* devBounds) {
|
||||
const SkMatrix* toSrc, BezierVertex verts[kQuadNumVertices]) {
|
||||
SkASSERT(!toDevice == !toSrc);
|
||||
// original quad is specified by tri a,b,c
|
||||
SkPoint a = qpts[0];
|
||||
@ -535,7 +537,6 @@ void bloat_quad(const SkPoint qpts[3], const SkMatrix* toDevice,
|
||||
c1.fPos -= cbN;
|
||||
|
||||
intersect_lines(a0.fPos, abN, c0.fPos, cbN, &b0.fPos);
|
||||
devBounds->growToInclude(&verts[0].fPos, sizeof(BezierVertex), kQuadNumVertices);
|
||||
|
||||
if (toSrc) {
|
||||
toSrc->mapPointsWithStride(&verts[0].fPos, sizeof(BezierVertex), kQuadNumVertices);
|
||||
@ -567,9 +568,8 @@ void add_conics(const SkPoint p[3],
|
||||
const SkScalar weight,
|
||||
const SkMatrix* toDevice,
|
||||
const SkMatrix* toSrc,
|
||||
BezierVertex** vert,
|
||||
SkRect* devBounds) {
|
||||
bloat_quad(p, toDevice, toSrc, *vert, devBounds);
|
||||
BezierVertex** vert) {
|
||||
bloat_quad(p, toDevice, toSrc, *vert);
|
||||
set_conic_coeffs(p, *vert, weight);
|
||||
*vert += kQuadNumVertices;
|
||||
}
|
||||
@ -578,16 +578,15 @@ void add_quads(const SkPoint p[3],
|
||||
int subdiv,
|
||||
const SkMatrix* toDevice,
|
||||
const SkMatrix* toSrc,
|
||||
BezierVertex** vert,
|
||||
SkRect* devBounds) {
|
||||
BezierVertex** vert) {
|
||||
SkASSERT(subdiv >= 0);
|
||||
if (subdiv) {
|
||||
SkPoint newP[5];
|
||||
SkChopQuadAtHalf(p, newP);
|
||||
add_quads(newP + 0, subdiv-1, toDevice, toSrc, vert, devBounds);
|
||||
add_quads(newP + 2, subdiv-1, toDevice, toSrc, vert, devBounds);
|
||||
add_quads(newP + 0, subdiv-1, toDevice, toSrc, vert);
|
||||
add_quads(newP + 2, subdiv-1, toDevice, toSrc, vert);
|
||||
} else {
|
||||
bloat_quad(p, toDevice, toSrc, *vert, devBounds);
|
||||
bloat_quad(p, toDevice, toSrc, *vert);
|
||||
set_uv_quad(p, *vert);
|
||||
*vert += kQuadNumVertices;
|
||||
}
|
||||
@ -642,106 +641,6 @@ void add_line(const SkPoint p[2],
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool GrAAHairLinePathRenderer::createLineGeom(GrDrawTarget* target,
|
||||
GrPipelineBuilder* pipelineBuilder,
|
||||
const SkMatrix& viewMatrix,
|
||||
uint8_t coverage,
|
||||
size_t vertexStride,
|
||||
GrDrawTarget::AutoReleaseGeometry* arg,
|
||||
SkRect* devBounds,
|
||||
const SkPath& path,
|
||||
const PtArray& lines,
|
||||
int lineCnt) {
|
||||
int vertCnt = kLineSegNumVertices * lineCnt;
|
||||
|
||||
SkASSERT(vertexStride == sizeof(LineVertex));
|
||||
if (!arg->set(target, vertCnt, vertexStride, 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
LineVertex* verts = reinterpret_cast<LineVertex*>(arg->vertices());
|
||||
|
||||
const SkMatrix* toSrc = NULL;
|
||||
SkMatrix ivm;
|
||||
|
||||
if (viewMatrix.hasPerspective()) {
|
||||
if (viewMatrix.invert(&ivm)) {
|
||||
toSrc = &ivm;
|
||||
}
|
||||
}
|
||||
devBounds->set(lines.begin(), lines.count());
|
||||
for (int i = 0; i < lineCnt; ++i) {
|
||||
add_line(&lines[2*i], toSrc, coverage, &verts);
|
||||
}
|
||||
// All the verts computed by add_line are within sqrt(1^2 + 0.5^2) of the end points.
|
||||
static const SkScalar kSqrtOfOneAndAQuarter = 1.118f;
|
||||
// Add a little extra to account for vector normalization precision.
|
||||
static const SkScalar kOutset = kSqrtOfOneAndAQuarter + SK_Scalar1 / 20;
|
||||
devBounds->outset(kOutset, kOutset);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GrAAHairLinePathRenderer::createBezierGeom(GrDrawTarget* target,
|
||||
GrPipelineBuilder* pipelineBuilder,
|
||||
const SkMatrix& viewMatrix,
|
||||
GrDrawTarget::AutoReleaseGeometry* arg,
|
||||
SkRect* devBounds,
|
||||
const SkPath& path,
|
||||
const PtArray& quads,
|
||||
int quadCnt,
|
||||
const PtArray& conics,
|
||||
int conicCnt,
|
||||
const IntArray& qSubdivs,
|
||||
const FloatArray& cWeights,
|
||||
size_t vertexStride) {
|
||||
int vertCnt = kQuadNumVertices * quadCnt + kQuadNumVertices * conicCnt;
|
||||
|
||||
if (!arg->set(target, vertCnt, vertexStride, 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
BezierVertex* verts = reinterpret_cast<BezierVertex*>(arg->vertices());
|
||||
|
||||
const SkMatrix* toDevice = NULL;
|
||||
const SkMatrix* toSrc = NULL;
|
||||
SkMatrix ivm;
|
||||
|
||||
if (viewMatrix.hasPerspective()) {
|
||||
if (viewMatrix.invert(&ivm)) {
|
||||
toDevice = &viewMatrix;
|
||||
toSrc = &ivm;
|
||||
}
|
||||
}
|
||||
|
||||
// Seed the dev bounds with some pts known to be inside. Each quad and conic grows the bounding
|
||||
// box to include its vertices.
|
||||
SkPoint seedPts[2];
|
||||
if (quadCnt) {
|
||||
seedPts[0] = quads[0];
|
||||
seedPts[1] = quads[2];
|
||||
} else if (conicCnt) {
|
||||
seedPts[0] = conics[0];
|
||||
seedPts[1] = conics[2];
|
||||
}
|
||||
if (toDevice) {
|
||||
toDevice->mapPoints(seedPts, 2);
|
||||
}
|
||||
devBounds->set(seedPts[0], seedPts[1]);
|
||||
|
||||
int unsubdivQuadCnt = quads.count() / 3;
|
||||
for (int i = 0; i < unsubdivQuadCnt; ++i) {
|
||||
SkASSERT(qSubdivs[i] >= 0);
|
||||
add_quads(&quads[3*i], qSubdivs[i], toDevice, toSrc, &verts, devBounds);
|
||||
}
|
||||
|
||||
// Start Conics
|
||||
for (int i = 0; i < conicCnt; ++i) {
|
||||
add_conics(&conics[3*i], cWeights[i], toDevice, toSrc, &verts, devBounds);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GrAAHairLinePathRenderer::canDrawPath(const GrDrawTarget* target,
|
||||
const GrPipelineBuilder* pipelineBuilder,
|
||||
const SkMatrix& viewMatrix,
|
||||
@ -800,13 +699,444 @@ bool check_bounds(const SkMatrix& viewMatrix, const SkRect& devBounds, void* ver
|
||||
return true;
|
||||
}
|
||||
|
||||
class AAHairlineBatch : public GrBatch {
|
||||
public:
|
||||
struct Geometry {
|
||||
GrColor fColor;
|
||||
uint8_t fCoverage;
|
||||
SkMatrix fViewMatrix;
|
||||
SkPath fPath;
|
||||
SkDEBUGCODE(SkRect fDevBounds;)
|
||||
SkIRect fDevClipBounds;
|
||||
};
|
||||
|
||||
// TODO Batch itself should not hold on to index buffers. Instead, these should live in the
|
||||
// cache.
|
||||
static GrBatch* Create(const Geometry& geometry, const GrIndexBuffer* linesIndexBuffer,
|
||||
const GrIndexBuffer* quadsIndexBuffer) {
|
||||
return SkNEW_ARGS(AAHairlineBatch, (geometry, linesIndexBuffer, quadsIndexBuffer));
|
||||
}
|
||||
|
||||
const char* name() const SK_OVERRIDE { return "AAHairlineBatch"; }
|
||||
|
||||
void getInvariantOutputColor(GrInitInvariantOutput* out) const SK_OVERRIDE {
|
||||
// When this is called on a batch, there is only one geometry bundle
|
||||
out->setKnownFourComponents(fGeoData[0].fColor);
|
||||
}
|
||||
void getInvariantOutputCoverage(GrInitInvariantOutput* out) const SK_OVERRIDE {
|
||||
out->setUnknownSingleComponent();
|
||||
}
|
||||
|
||||
void initBatchOpt(const GrBatchOpt& batchOpt) {
|
||||
fBatchOpt = batchOpt;
|
||||
}
|
||||
|
||||
void initBatchTracker(const GrPipelineInfo& init) SK_OVERRIDE {
|
||||
// Handle any color overrides
|
||||
if (init.fColorIgnored) {
|
||||
fGeoData[0].fColor = GrColor_ILLEGAL;
|
||||
} else if (GrColor_ILLEGAL != init.fOverrideColor) {
|
||||
fGeoData[0].fColor = init.fOverrideColor;
|
||||
}
|
||||
|
||||
// setup batch properties
|
||||
fBatch.fColorIgnored = init.fColorIgnored;
|
||||
fBatch.fColor = fGeoData[0].fColor;
|
||||
fBatch.fUsesLocalCoords = init.fUsesLocalCoords;
|
||||
fBatch.fCoverageIgnored = init.fCoverageIgnored;
|
||||
fBatch.fCoverage = fGeoData[0].fCoverage;
|
||||
SkDEBUGCODE(fBatch.fDevBounds = fGeoData[0].fDevBounds;)
|
||||
}
|
||||
|
||||
void generateGeometry(GrBatchTarget* batchTarget, const GrPipeline* pipeline) SK_OVERRIDE {
|
||||
int instanceCount = fGeoData.count();
|
||||
for (int i = 0; i < instanceCount; i++) {
|
||||
const Geometry& args = fGeoData[i];
|
||||
|
||||
// createGeom transforms the geometry to device space when the matrix does not have
|
||||
// perspective.
|
||||
SkMatrix vm = args.fViewMatrix;
|
||||
SkMatrix invert = SkMatrix::I();
|
||||
if (!args.fViewMatrix.hasPerspective()) {
|
||||
vm = SkMatrix::I();
|
||||
if (!args.fViewMatrix.invert(&invert)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
int lineCount;
|
||||
int quadCount;
|
||||
int conicCount;
|
||||
PREALLOC_PTARRAY(128) lines;
|
||||
PREALLOC_PTARRAY(128) quads;
|
||||
PREALLOC_PTARRAY(128) conics;
|
||||
IntArray qSubdivs;
|
||||
FloatArray cWeights;
|
||||
quadCount = gather_lines_and_quads(args.fPath, args.fViewMatrix, args.fDevClipBounds,
|
||||
&lines, &quads, &conics, &qSubdivs, &cWeights);
|
||||
|
||||
lineCount = lines.count() / 2;
|
||||
conicCount = conics.count() / 3;
|
||||
|
||||
// do lines first
|
||||
if (lineCount) {
|
||||
this->generateLines(batchTarget, pipeline, args, vm, invert, lines, lineCount);
|
||||
}
|
||||
|
||||
if (quadCount || conicCount) {
|
||||
this->generateQuadsAndConics(batchTarget,
|
||||
pipeline,
|
||||
args,
|
||||
quads,
|
||||
quadCount,
|
||||
conics,
|
||||
conicCount,
|
||||
qSubdivs,
|
||||
cWeights,
|
||||
vm,
|
||||
invert);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
|
||||
|
||||
private:
|
||||
typedef SkTArray<SkPoint, true> PtArray;
|
||||
typedef SkTArray<int, true> IntArray;
|
||||
typedef SkTArray<float, true> FloatArray;
|
||||
|
||||
AAHairlineBatch(const Geometry& geometry, const GrIndexBuffer* linesIndexBuffer,
|
||||
const GrIndexBuffer* quadsIndexBuffer)
|
||||
: fLinesIndexBuffer(linesIndexBuffer)
|
||||
, fQuadsIndexBuffer(quadsIndexBuffer) {
|
||||
SkASSERT(linesIndexBuffer && quadsIndexBuffer);
|
||||
this->initClassID<AAHairlineBatch>();
|
||||
fGeoData.push_back(geometry);
|
||||
}
|
||||
|
||||
bool onCombineIfPossible(GrBatch* t) SK_OVERRIDE {
|
||||
AAHairlineBatch* that = t->cast<AAHairlineBatch>();
|
||||
|
||||
// We go to identity if we don't have perspective
|
||||
if (this->viewMatrix().hasPerspective() &&
|
||||
!this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO we can actually batch hairlines if they are the same color in a kind of bulk method
|
||||
// but we haven't implemented this yet
|
||||
// TODO investigate going to vertex color and coverage?
|
||||
if (this->coverage() != that->coverage()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this->color() != that->color()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SkASSERT(this->usesLocalCoords() == that->usesLocalCoords());
|
||||
if (this->usesLocalCoords() && !this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin());
|
||||
return true;
|
||||
}
|
||||
|
||||
GrColor color() const { return fBatch.fColor; }
|
||||
uint8_t coverage() const { return fBatch.fCoverage; }
|
||||
bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; }
|
||||
const SkMatrix& viewMatrix() const { return fGeoData[0].fViewMatrix; }
|
||||
|
||||
void generateLines(GrBatchTarget* batchTarget,
|
||||
const GrPipeline* pipeline,
|
||||
const Geometry& args,
|
||||
const SkMatrix& viewMatrix,
|
||||
const SkMatrix& invert,
|
||||
const PtArray& lines,
|
||||
int lineCnt) {
|
||||
uint32_t gpFlags = GrDefaultGeoProcFactory::kPosition_GPType |
|
||||
GrDefaultGeoProcFactory::kCoverage_GPType;
|
||||
SkAutoTUnref<const GrGeometryProcessor> gp(GrDefaultGeoProcFactory::Create(gpFlags,
|
||||
args.fColor,
|
||||
viewMatrix,
|
||||
invert,
|
||||
false,
|
||||
args.fCoverage));
|
||||
|
||||
batchTarget->initDraw(gp, pipeline);
|
||||
|
||||
// TODO remove this when batch is everywhere
|
||||
GrPipelineInfo init;
|
||||
init.fColorIgnored = fBatch.fColorIgnored;
|
||||
init.fOverrideColor = GrColor_ILLEGAL;
|
||||
init.fCoverageIgnored = fBatch.fCoverageIgnored;
|
||||
init.fUsesLocalCoords = this->usesLocalCoords();
|
||||
gp->initBatchTracker(batchTarget->currentBatchTracker(), init);
|
||||
|
||||
const GrVertexBuffer* vertexBuffer;
|
||||
int firstVertex;
|
||||
|
||||
size_t vertexStride = gp->getVertexStride();
|
||||
int vertexCount = kLineSegNumVertices * lineCnt;
|
||||
void *vertices = batchTarget->vertexPool()->makeSpace(vertexStride,
|
||||
vertexCount,
|
||||
&vertexBuffer,
|
||||
&firstVertex);
|
||||
|
||||
SkASSERT(gp->getVertexStride() == sizeof(LineVertex));
|
||||
|
||||
// generate lines
|
||||
const SkMatrix* toSrc = NULL;
|
||||
if (args.fViewMatrix.hasPerspective()) {
|
||||
SkMatrix perspectiveInvert;
|
||||
if (!args.fViewMatrix.invert(&perspectiveInvert)) {
|
||||
return;
|
||||
}
|
||||
toSrc = &perspectiveInvert;
|
||||
}
|
||||
|
||||
LineVertex* verts = reinterpret_cast<LineVertex*>(vertices);
|
||||
for (int i = 0; i < lineCnt; ++i) {
|
||||
add_line(&lines[2*i], toSrc, args.fCoverage, &verts);
|
||||
}
|
||||
|
||||
// Check devBounds
|
||||
SkASSERT(check_bounds<LineVertex>(viewMatrix.hasPerspective() ? viewMatrix : SkMatrix::I(),
|
||||
args.fDevBounds,
|
||||
vertices,
|
||||
kLineSegNumVertices * lineCnt));
|
||||
|
||||
{
|
||||
GrDrawTarget::DrawInfo info;
|
||||
info.setVertexBuffer(vertexBuffer);
|
||||
info.setIndexBuffer(fLinesIndexBuffer);
|
||||
info.setPrimitiveType(kTriangles_GrPrimitiveType);
|
||||
info.setStartIndex(0);
|
||||
|
||||
int lines = 0;
|
||||
while (lines < lineCnt) {
|
||||
int n = SkTMin(lineCnt - lines, kLineSegsNumInIdxBuffer);
|
||||
|
||||
info.setStartVertex(kLineSegNumVertices*lines + firstVertex);
|
||||
info.setVertexCount(kLineSegNumVertices*n);
|
||||
info.setIndexCount(kIdxsPerLineSeg*n);
|
||||
batchTarget->draw(info);
|
||||
|
||||
lines += n;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void generateQuadsAndConics(GrBatchTarget* batchTarget,
|
||||
const GrPipeline* pipeline,
|
||||
const Geometry& args,
|
||||
const PREALLOC_PTARRAY(128)& quads,
|
||||
int quadCount,
|
||||
const PREALLOC_PTARRAY(128)& conics,
|
||||
int conicCount,
|
||||
const IntArray& qSubdivs,
|
||||
const FloatArray& cWeights,
|
||||
const SkMatrix& vm,
|
||||
const SkMatrix& invert) {
|
||||
const GrVertexBuffer* vertexBuffer;
|
||||
int firstVertex;
|
||||
|
||||
size_t vertexStride = sizeof(BezierVertex);
|
||||
int vertexCount = kQuadNumVertices * quadCount + kQuadNumVertices * conicCount;
|
||||
void *vertices = batchTarget->vertexPool()->makeSpace(vertexStride,
|
||||
vertexCount,
|
||||
&vertexBuffer,
|
||||
&firstVertex);
|
||||
|
||||
if (!this->createBezierGeom(vertices,
|
||||
args.fViewMatrix,
|
||||
args.fPath,
|
||||
quads,
|
||||
quadCount,
|
||||
conics,
|
||||
conicCount,
|
||||
qSubdivs,
|
||||
cWeights,
|
||||
vertexStride)) {
|
||||
SkDebugf("Couldn't create bezier geometry\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// Check devBounds
|
||||
SkASSERT(check_bounds<BezierVertex>(vm,
|
||||
args.fDevBounds,
|
||||
vertices,
|
||||
kQuadNumVertices * quadCount +
|
||||
kQuadNumVertices * conicCount));
|
||||
|
||||
if (quadCount > 0) {
|
||||
SkAutoTUnref<GrGeometryProcessor> hairQuadProcessor(
|
||||
GrQuadEffect::Create(args.fColor,
|
||||
vm,
|
||||
kHairlineAA_GrProcessorEdgeType,
|
||||
batchTarget->caps(),
|
||||
invert,
|
||||
args.fCoverage));
|
||||
|
||||
batchTarget->initDraw(hairQuadProcessor, pipeline);
|
||||
|
||||
// TODO remove this when batch is everywhere
|
||||
GrPipelineInfo init;
|
||||
init.fColorIgnored = fBatch.fColorIgnored;
|
||||
init.fOverrideColor = GrColor_ILLEGAL;
|
||||
init.fCoverageIgnored = fBatch.fCoverageIgnored;
|
||||
init.fUsesLocalCoords = this->usesLocalCoords();
|
||||
hairQuadProcessor->initBatchTracker(batchTarget->currentBatchTracker(), init);
|
||||
|
||||
this->drawBeziers(batchTarget,
|
||||
hairQuadProcessor,
|
||||
pipeline,
|
||||
vertexBuffer,
|
||||
firstVertex,
|
||||
quadCount);
|
||||
}
|
||||
|
||||
if (conicCount > 0) {
|
||||
SkAutoTUnref<GrGeometryProcessor> hairConicProcessor(
|
||||
GrConicEffect::Create(args.fColor,
|
||||
vm,
|
||||
kHairlineAA_GrProcessorEdgeType,
|
||||
batchTarget->caps(),
|
||||
invert,
|
||||
args.fCoverage));
|
||||
|
||||
batchTarget->initDraw(hairConicProcessor, pipeline);
|
||||
|
||||
// TODO remove this when batch is everywhere
|
||||
GrPipelineInfo init;
|
||||
init.fColorIgnored = fBatch.fColorIgnored;
|
||||
init.fOverrideColor = GrColor_ILLEGAL;
|
||||
init.fCoverageIgnored = fBatch.fCoverageIgnored;
|
||||
init.fUsesLocalCoords = this->usesLocalCoords();
|
||||
hairConicProcessor->initBatchTracker(batchTarget->currentBatchTracker(), init);
|
||||
|
||||
this->drawConics(batchTarget,
|
||||
hairConicProcessor,
|
||||
pipeline,
|
||||
vertexBuffer,
|
||||
firstVertex,
|
||||
conicCount,
|
||||
quadCount);
|
||||
}
|
||||
}
|
||||
|
||||
bool createBezierGeom(void* vertices,
|
||||
const SkMatrix& viewMatrix,
|
||||
const SkPath& path,
|
||||
const PtArray& quads,
|
||||
int quadCnt,
|
||||
const PtArray& conics,
|
||||
int conicCnt,
|
||||
const IntArray& qSubdivs,
|
||||
const FloatArray& cWeights,
|
||||
size_t vertexStride) {
|
||||
BezierVertex* verts = reinterpret_cast<BezierVertex*>(vertices);
|
||||
|
||||
const SkMatrix* toDevice = NULL;
|
||||
const SkMatrix* toSrc = NULL;
|
||||
SkMatrix ivm;
|
||||
|
||||
if (viewMatrix.hasPerspective()) {
|
||||
if (viewMatrix.invert(&ivm)) {
|
||||
toDevice = &viewMatrix;
|
||||
toSrc = &ivm;
|
||||
}
|
||||
}
|
||||
|
||||
int unsubdivQuadCnt = quads.count() / 3;
|
||||
for (int i = 0; i < unsubdivQuadCnt; ++i) {
|
||||
SkASSERT(qSubdivs[i] >= 0);
|
||||
add_quads(&quads[3*i], qSubdivs[i], toDevice, toSrc, &verts);
|
||||
}
|
||||
|
||||
// Start Conics
|
||||
for (int i = 0; i < conicCnt; ++i) {
|
||||
add_conics(&conics[3*i], cWeights[i], toDevice, toSrc, &verts);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void drawBeziers(GrBatchTarget* batchTarget,
|
||||
const GrGeometryProcessor* hairQuadProcessor,
|
||||
const GrPipeline* pipeline,
|
||||
const GrVertexBuffer* vertexBuffer,
|
||||
int firstVertex,
|
||||
int quadCount) {
|
||||
GrDrawTarget::DrawInfo info;
|
||||
info.setVertexBuffer(vertexBuffer);
|
||||
info.setIndexBuffer(fQuadsIndexBuffer);
|
||||
info.setPrimitiveType(kTriangles_GrPrimitiveType);
|
||||
info.setStartIndex(0);
|
||||
|
||||
int quads = 0;
|
||||
while (quads < quadCount) {
|
||||
int n = SkTMin(quadCount - quads, kQuadsNumInIdxBuffer);
|
||||
|
||||
info.setStartVertex(kQuadNumVertices*quads + firstVertex);
|
||||
info.setVertexCount(kQuadNumVertices*n);
|
||||
info.setIndexCount(kIdxsPerQuad*n);
|
||||
batchTarget->draw(info);
|
||||
|
||||
quads += n;
|
||||
}
|
||||
}
|
||||
|
||||
void drawConics(GrBatchTarget* batchTarget,
|
||||
const GrGeometryProcessor* hairConicProcessor,
|
||||
const GrPipeline* pipeline,
|
||||
const GrVertexBuffer* vertexBuffer,
|
||||
int firstVertex,
|
||||
int conicCount,
|
||||
int quadCount) {
|
||||
GrDrawTarget::DrawInfo info;
|
||||
info.setVertexBuffer(vertexBuffer);
|
||||
info.setIndexBuffer(fQuadsIndexBuffer);
|
||||
info.setPrimitiveType(kTriangles_GrPrimitiveType);
|
||||
info.setStartIndex(0);
|
||||
|
||||
int conics = 0;
|
||||
while (conics < conicCount) {
|
||||
int n = SkTMin(conicCount - conics, kQuadsNumInIdxBuffer);
|
||||
|
||||
info.setStartVertex(kQuadNumVertices*(quadCount + conics) + firstVertex);
|
||||
info.setVertexCount(kQuadNumVertices*n);
|
||||
info.setIndexCount(kIdxsPerQuad*n);
|
||||
batchTarget->draw(info);
|
||||
|
||||
conics += n;
|
||||
}
|
||||
}
|
||||
|
||||
struct BatchTracker {
|
||||
GrColor fColor;
|
||||
uint8_t fCoverage;
|
||||
SkRect fDevBounds;
|
||||
bool fUsesLocalCoords;
|
||||
bool fColorIgnored;
|
||||
bool fCoverageIgnored;
|
||||
};
|
||||
|
||||
GrBatchOpt fBatchOpt;
|
||||
BatchTracker fBatch;
|
||||
SkSTArray<1, Geometry, true> fGeoData;
|
||||
const GrIndexBuffer* fLinesIndexBuffer;
|
||||
const GrIndexBuffer* fQuadsIndexBuffer;
|
||||
};
|
||||
|
||||
bool GrAAHairLinePathRenderer::onDrawPath(GrDrawTarget* target,
|
||||
GrPipelineBuilder* pipelineBuilder,
|
||||
GrColor color,
|
||||
const SkMatrix& viewMatrix,
|
||||
const SkPath& path,
|
||||
const SkStrokeRec& stroke,
|
||||
bool antiAlias) {
|
||||
bool) {
|
||||
SkScalar hairlineCoverage;
|
||||
uint8_t newCoverage = 0xff;
|
||||
if (IsStrokeHairlineOrEquivalent(stroke, viewMatrix, &hairlineCoverage)) {
|
||||
@ -816,163 +1146,22 @@ bool GrAAHairLinePathRenderer::onDrawPath(GrDrawTarget* target,
|
||||
SkIRect devClipBounds;
|
||||
target->getClip()->getConservativeBounds(pipelineBuilder->getRenderTarget(), &devClipBounds);
|
||||
|
||||
int lineCnt;
|
||||
int quadCnt;
|
||||
int conicCnt;
|
||||
PREALLOC_PTARRAY(128) lines;
|
||||
PREALLOC_PTARRAY(128) quads;
|
||||
PREALLOC_PTARRAY(128) conics;
|
||||
IntArray qSubdivs;
|
||||
FloatArray cWeights;
|
||||
quadCnt = generate_lines_and_quads(path, viewMatrix, devClipBounds,
|
||||
&lines, &quads, &conics, &qSubdivs, &cWeights);
|
||||
lineCnt = lines.count() / 2;
|
||||
conicCnt = conics.count() / 3;
|
||||
// This outset was determined experimentally by running skps and gms. It probably could be a
|
||||
// bit tighter
|
||||
SkRect devRect = path.getBounds();
|
||||
devRect.outset(7, 7);
|
||||
viewMatrix.mapRect(&devRect);
|
||||
|
||||
// createGeom transforms the geometry to device space when the matrix does not have
|
||||
// perspective.
|
||||
SkMatrix vm = viewMatrix;
|
||||
SkMatrix invert = SkMatrix::I();
|
||||
if (!viewMatrix.hasPerspective()) {
|
||||
vm = SkMatrix::I();
|
||||
if (!viewMatrix.invert(&invert)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
AAHairlineBatch::Geometry geometry;
|
||||
geometry.fColor = color;
|
||||
geometry.fCoverage = newCoverage;
|
||||
geometry.fViewMatrix = viewMatrix;
|
||||
geometry.fPath = path;
|
||||
SkDEBUGCODE(geometry.fDevBounds = devRect;)
|
||||
geometry.fDevClipBounds = devClipBounds;
|
||||
|
||||
// do lines first
|
||||
if (lineCnt) {
|
||||
GrDrawTarget::AutoReleaseGeometry arg;
|
||||
SkRect devBounds;
|
||||
|
||||
GrPipelineBuilder::AutoRestoreEffects are(pipelineBuilder);
|
||||
uint32_t gpFlags = GrDefaultGeoProcFactory::kPosition_GPType |
|
||||
GrDefaultGeoProcFactory::kCoverage_GPType;
|
||||
SkAutoTUnref<const GrGeometryProcessor> gp(GrDefaultGeoProcFactory::Create(gpFlags,
|
||||
color,
|
||||
vm,
|
||||
invert,
|
||||
false,
|
||||
newCoverage));
|
||||
|
||||
if (!this->createLineGeom(target,
|
||||
pipelineBuilder,
|
||||
viewMatrix,
|
||||
newCoverage,
|
||||
gp->getVertexStride(),
|
||||
&arg,
|
||||
&devBounds,
|
||||
path,
|
||||
lines,
|
||||
lineCnt)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check devBounds
|
||||
SkASSERT(check_bounds<LineVertex>(viewMatrix.hasPerspective() ? viewMatrix : SkMatrix::I(),
|
||||
devBounds,
|
||||
arg.vertices(),
|
||||
kLineSegNumVertices * lineCnt));
|
||||
|
||||
{
|
||||
target->setIndexSourceToBuffer(fLinesIndexBuffer);
|
||||
int lines = 0;
|
||||
while (lines < lineCnt) {
|
||||
int n = SkTMin(lineCnt - lines, kLineSegsNumInIdxBuffer);
|
||||
target->drawIndexed(pipelineBuilder,
|
||||
gp,
|
||||
kTriangles_GrPrimitiveType,
|
||||
kLineSegNumVertices*lines, // startV
|
||||
0, // startI
|
||||
kLineSegNumVertices*n, // vCount
|
||||
kIdxsPerLineSeg*n, // iCount
|
||||
&devBounds);
|
||||
lines += n;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// then quadratics/conics
|
||||
if (quadCnt || conicCnt) {
|
||||
GrDrawTarget::AutoReleaseGeometry arg;
|
||||
SkRect devBounds;
|
||||
|
||||
if (!this->createBezierGeom(target,
|
||||
pipelineBuilder,
|
||||
viewMatrix,
|
||||
&arg,
|
||||
&devBounds,
|
||||
path,
|
||||
quads,
|
||||
quadCnt,
|
||||
conics,
|
||||
conicCnt,
|
||||
qSubdivs,
|
||||
cWeights,
|
||||
sizeof(BezierVertex))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check devBounds
|
||||
SkASSERT(check_bounds<BezierVertex>(viewMatrix.hasPerspective() ? viewMatrix :
|
||||
SkMatrix::I(),
|
||||
devBounds,
|
||||
arg.vertices(),
|
||||
kQuadNumVertices * quadCnt +
|
||||
kQuadNumVertices * conicCnt));
|
||||
|
||||
if (quadCnt > 0) {
|
||||
SkAutoTUnref<GrGeometryProcessor> hairQuadProcessor(
|
||||
GrQuadEffect::Create(color,
|
||||
vm,
|
||||
kHairlineAA_GrProcessorEdgeType,
|
||||
*target->caps(),
|
||||
invert,
|
||||
newCoverage));
|
||||
SkASSERT(hairQuadProcessor);
|
||||
GrPipelineBuilder::AutoRestoreEffects are(pipelineBuilder);
|
||||
target->setIndexSourceToBuffer(fQuadsIndexBuffer);
|
||||
|
||||
int quads = 0;
|
||||
while (quads < quadCnt) {
|
||||
int n = SkTMin(quadCnt - quads, kQuadsNumInIdxBuffer);
|
||||
target->drawIndexed(pipelineBuilder,
|
||||
hairQuadProcessor,
|
||||
kTriangles_GrPrimitiveType,
|
||||
kQuadNumVertices*quads, // startV
|
||||
0, // startI
|
||||
kQuadNumVertices*n, // vCount
|
||||
kIdxsPerQuad*n, // iCount
|
||||
&devBounds);
|
||||
quads += n;
|
||||
}
|
||||
}
|
||||
|
||||
if (conicCnt > 0) {
|
||||
SkAutoTUnref<GrGeometryProcessor> hairConicProcessor(
|
||||
GrConicEffect::Create(color, vm, kHairlineAA_GrProcessorEdgeType,
|
||||
*target->caps(), invert, newCoverage));
|
||||
SkASSERT(hairConicProcessor);
|
||||
GrPipelineBuilder::AutoRestoreEffects are(pipelineBuilder);
|
||||
target->setIndexSourceToBuffer(fQuadsIndexBuffer);
|
||||
|
||||
int conics = 0;
|
||||
while (conics < conicCnt) {
|
||||
int n = SkTMin(conicCnt - conics, kQuadsNumInIdxBuffer);
|
||||
target->drawIndexed(pipelineBuilder,
|
||||
hairConicProcessor,
|
||||
kTriangles_GrPrimitiveType,
|
||||
kQuadNumVertices*(quadCnt + conics), // startV
|
||||
0, // startI
|
||||
kQuadNumVertices*n, // vCount
|
||||
kIdxsPerQuad*n, // iCount
|
||||
&devBounds);
|
||||
conics += n;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
target->resetIndexSource();
|
||||
GrBatch* batch = AAHairlineBatch::Create(geometry, fLinesIndexBuffer, fQuadsIndexBuffer);
|
||||
target->drawBatch(pipelineBuilder, batch, &devRect);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -42,31 +42,6 @@ private:
|
||||
const GrIndexBuffer* fLinesIndexBuffer,
|
||||
const GrIndexBuffer* fQuadsIndexBuffer);
|
||||
|
||||
bool createLineGeom(GrDrawTarget* target,
|
||||
GrPipelineBuilder*,
|
||||
const SkMatrix& viewMatrix,
|
||||
uint8_t coverage,
|
||||
size_t vertexStride,
|
||||
GrDrawTarget::AutoReleaseGeometry* arg,
|
||||
SkRect* devBounds,
|
||||
const SkPath& path,
|
||||
const PtArray& lines,
|
||||
int lineCnt);
|
||||
|
||||
bool createBezierGeom(GrDrawTarget* target,
|
||||
GrPipelineBuilder*,
|
||||
const SkMatrix& viewMatrix,
|
||||
GrDrawTarget::AutoReleaseGeometry* arg,
|
||||
SkRect* devBounds,
|
||||
const SkPath& path,
|
||||
const PtArray& quads,
|
||||
int quadCnt,
|
||||
const PtArray& conics,
|
||||
int conicCnt,
|
||||
const IntArray& qSubdivs,
|
||||
const FloatArray& cWeights,
|
||||
size_t vertexStride);
|
||||
|
||||
const GrIndexBuffer* fLinesIndexBuffer;
|
||||
const GrIndexBuffer* fQuadsIndexBuffer;
|
||||
|
||||
|
@ -208,10 +208,7 @@ private:
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this->usesLocalCoords() != that->usesLocalCoords()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SkASSERT(this->usesLocalCoords() == that->usesLocalCoords());
|
||||
// We apply the viewmatrix to the rect points on the cpu. However, if the pipeline uses
|
||||
// local coords then we won't be able to batch. We could actually upload the viewmatrix
|
||||
// using vertex attributes in these cases, but haven't investigated that
|
||||
|
@ -46,7 +46,7 @@ struct GrBatchOpt {
|
||||
class GrBatch : public SkRefCnt {
|
||||
public:
|
||||
SK_DECLARE_INST_COUNT(GrBatch)
|
||||
GrBatch() { SkDEBUGCODE(fUsed = false;) }
|
||||
GrBatch() : fNumberOfDraws(0) { SkDEBUGCODE(fUsed = false;) }
|
||||
virtual ~GrBatch() {}
|
||||
|
||||
virtual const char* name() const = 0;
|
||||
@ -75,6 +75,10 @@ public:
|
||||
|
||||
virtual void generateGeometry(GrBatchTarget*, const GrPipeline*) = 0;
|
||||
|
||||
// TODO this goes away when batches are everywhere
|
||||
void setNumberOfDraws(int numberOfDraws) { fNumberOfDraws = numberOfDraws; }
|
||||
int numberOfDraws() const { return fNumberOfDraws; }
|
||||
|
||||
void* operator new(size_t size);
|
||||
void operator delete(void* target);
|
||||
|
||||
@ -126,6 +130,8 @@ private:
|
||||
|
||||
SkDEBUGCODE(bool fUsed;)
|
||||
|
||||
int fNumberOfDraws;
|
||||
|
||||
typedef SkRefCnt INHERITED;
|
||||
};
|
||||
|
||||
|
@ -32,17 +32,20 @@ void GrBatchTarget::flush() {
|
||||
fFlushBuffer.reset();
|
||||
}*/
|
||||
|
||||
void GrBatchTarget::flushNext() {
|
||||
fIter.next();
|
||||
GrProgramDesc desc;
|
||||
BufferedFlush* bf = fIter.get();
|
||||
const GrPipeline* pipeline = bf->fPipeline;
|
||||
const GrPrimitiveProcessor* primProc = bf->fPrimitiveProcessor.get();
|
||||
fGpu->buildProgramDesc(&desc, *primProc, *pipeline, pipeline->descInfo(),
|
||||
bf->fBatchTracker);
|
||||
void GrBatchTarget::flushNext(int n) {
|
||||
for (; n > 0; n--) {
|
||||
SkDEBUGCODE(bool verify =) fIter.next();
|
||||
SkASSERT(verify);
|
||||
GrProgramDesc desc;
|
||||
BufferedFlush* bf = fIter.get();
|
||||
const GrPipeline* pipeline = bf->fPipeline;
|
||||
const GrPrimitiveProcessor* primProc = bf->fPrimitiveProcessor.get();
|
||||
fGpu->buildProgramDesc(&desc, *primProc, *pipeline, pipeline->descInfo(),
|
||||
bf->fBatchTracker);
|
||||
|
||||
GrGpu::DrawArgs args(primProc, pipeline, &desc, &bf->fBatchTracker);
|
||||
for (int i = 0; i < bf->fDraws.count(); i++) {
|
||||
fGpu->draw(args, bf->fDraws[i]);
|
||||
GrGpu::DrawArgs args(primProc, pipeline, &desc, &bf->fBatchTracker);
|
||||
for (int i = 0; i < bf->fDraws.count(); i++) {
|
||||
fGpu->draw(args, bf->fDraws[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -17,6 +17,9 @@
|
||||
* that render their batch.
|
||||
*/
|
||||
|
||||
class GrIndexBufferAllocPool;
|
||||
class GrVertexBufferAllocPool;
|
||||
|
||||
class GrBatchTarget : public SkNoncopyable {
|
||||
public:
|
||||
GrBatchTarget(GrGpu* gpu,
|
||||
@ -26,11 +29,13 @@ public:
|
||||
, fVertexPool(vpool)
|
||||
, fIndexPool(ipool)
|
||||
, fFlushBuffer(kFlushBufferInitialSizeInBytes)
|
||||
, fIter(fFlushBuffer) {}
|
||||
, fIter(fFlushBuffer)
|
||||
, fNumberOfDraws(0) {}
|
||||
|
||||
typedef GrDrawTarget::DrawInfo DrawInfo;
|
||||
void initDraw(const GrPrimitiveProcessor* primProc, const GrPipeline* pipeline) {
|
||||
GrNEW_APPEND_TO_RECORDER(fFlushBuffer, BufferedFlush, (primProc, pipeline));
|
||||
fNumberOfDraws++;
|
||||
}
|
||||
|
||||
void draw(const GrDrawTarget::DrawInfo& draw) {
|
||||
@ -39,8 +44,10 @@ public:
|
||||
|
||||
// TODO this is temporary until batch is everywhere
|
||||
//void flush();
|
||||
void resetNumberOfDraws() { fNumberOfDraws = 0; }
|
||||
int numberOfDraws() const { return fNumberOfDraws; }
|
||||
void preFlush() { fIter = FlushBuffer::Iter(fFlushBuffer); }
|
||||
void flushNext();
|
||||
void flushNext(int n);
|
||||
void postFlush() { SkASSERT(!fIter.next()); fFlushBuffer.reset(); }
|
||||
|
||||
// TODO This goes away when everything uses batch
|
||||
@ -49,6 +56,8 @@ public:
|
||||
return &fFlushBuffer.back().fBatchTracker;
|
||||
}
|
||||
|
||||
const GrDrawTargetCaps& caps() const { return *fGpu->caps(); }
|
||||
|
||||
GrVertexBufferAllocPool* vertexPool() { return fVertexPool; }
|
||||
GrIndexBufferAllocPool* indexPool() { return fIndexPool; }
|
||||
|
||||
@ -62,8 +71,7 @@ private:
|
||||
struct BufferedFlush {
|
||||
BufferedFlush(const GrPrimitiveProcessor* primProc, const GrPipeline* pipeline)
|
||||
: fPrimitiveProcessor(primProc)
|
||||
, fPipeline(pipeline)
|
||||
, fDraws(kDrawRecorderInitialSizeInBytes) {}
|
||||
, fPipeline(pipeline) {}
|
||||
typedef GrPendingProgramElement<const GrPrimitiveProcessor> ProgramPrimitiveProcessor;
|
||||
ProgramPrimitiveProcessor fPrimitiveProcessor;
|
||||
const GrPipeline* fPipeline;
|
||||
@ -73,7 +81,6 @@ private:
|
||||
|
||||
enum {
|
||||
kFlushBufferInitialSizeInBytes = 8 * sizeof(BufferedFlush),
|
||||
kDrawRecorderInitialSizeInBytes = 8 * sizeof(DrawInfo),
|
||||
};
|
||||
|
||||
typedef GrTRecorder<BufferedFlush, TBufferAlign> FlushBuffer;
|
||||
@ -81,6 +88,7 @@ private:
|
||||
FlushBuffer fFlushBuffer;
|
||||
// TODO this is temporary
|
||||
FlushBuffer::Iter fIter;
|
||||
int fNumberOfDraws;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -473,7 +473,8 @@ void GrInOrderDrawBuffer::onFlush() {
|
||||
|
||||
// TODO temporary hack
|
||||
if (kDrawBatch_Cmd == strip_trace_bit(iter->fType)) {
|
||||
fBatchTarget.flushNext();
|
||||
DrawBatch* db = reinterpret_cast<DrawBatch*>(iter.get());
|
||||
fBatchTarget.flushNext(db->fBatch->numberOfDraws());
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -646,7 +647,9 @@ void GrInOrderDrawBuffer::recordTraceMarkersIfNecessary() {
|
||||
|
||||
void GrInOrderDrawBuffer::closeBatch() {
|
||||
if (fDrawBatch) {
|
||||
fBatchTarget.resetNumberOfDraws();
|
||||
fDrawBatch->execute(this, fPrevState);
|
||||
fDrawBatch->fBatch->setNumberOfDraws(fBatchTarget.numberOfDraws());
|
||||
fDrawBatch = NULL;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user