joshualitt 2015-02-03 06:56:44 -08:00 committed by Commit bot
parent 532faa9021
commit 658d55cd61
7 changed files with 503 additions and 322 deletions

View File

@ -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;
}

View File

@ -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;

View File

@ -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

View File

@ -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;
};

View File

@ -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]);
}
}
}

View File

@ -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

View File

@ -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;
}
}