/* * Copyright 2014 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ // This test only works with the GPU backend. #include "gm.h" #if SK_SUPPORT_GPU #include "GrBatchTarget.h" #include "GrBufferAllocPool.h" #include "GrContext.h" #include "GrDefaultGeoProcFactory.h" #include "GrPathUtils.h" #include "GrTest.h" #include "GrTestBatch.h" #include "SkColorPriv.h" #include "SkDevice.h" #include "SkGeometry.h" #include "SkTLList.h" #include "effects/GrConvexPolyEffect.h" namespace skiagm { class ConvexPolyTestBatch : public GrTestBatch { public: struct Geometry : public GrTestBatch::Geometry { SkRect fBounds; }; const char* name() const SK_OVERRIDE { return "ConvexPolyTestBatch"; } static GrBatch* Create(const GrGeometryProcessor* gp, const Geometry& geo) { return SkNEW_ARGS(ConvexPolyTestBatch, (gp, geo)); } private: ConvexPolyTestBatch(const GrGeometryProcessor* gp, const Geometry& geo) : INHERITED(gp) , fGeometry(geo) { } Geometry* geoData(int index) SK_OVERRIDE { SkASSERT(0 == index); return &fGeometry; } void onGenerateGeometry(GrBatchTarget* batchTarget, const GrPipeline* pipeline) SK_OVERRIDE { size_t vertexStride = this->geometryProcessor()->getVertexStride(); const GrVertexBuffer* vertexBuffer; int firstVertex; void* vertices = batchTarget->vertexPool()->makeSpace(vertexStride, kVertsPerCubic, &vertexBuffer, &firstVertex); SkASSERT(vertexStride == sizeof(SkPoint)); SkPoint* verts = reinterpret_cast(vertices); // Make sure any artifacts around the exterior of path are visible by using overly // conservative bounding geometry. fGeometry.fBounds.outset(5.f, 5.f); fGeometry.fBounds.toQuad(verts); GrDrawTarget::DrawInfo drawInfo; drawInfo.setPrimitiveType(kTriangleFan_GrPrimitiveType); drawInfo.setVertexBuffer(vertexBuffer); drawInfo.setStartVertex(firstVertex); drawInfo.setVertexCount(kVertsPerCubic); drawInfo.setStartIndex(0); drawInfo.setIndexCount(kIndicesPerCubic); drawInfo.setIndexBuffer(batchTarget->quadIndexBuffer()); batchTarget->draw(drawInfo); } Geometry fGeometry; static const int kVertsPerCubic = 4; static const int kIndicesPerCubic = 6; typedef GrTestBatch INHERITED; }; /** * This GM directly exercises a GrProcessor that draws convex polygons. */ class ConvexPolyEffect : public GM { public: ConvexPolyEffect() { this->setBGColor(0xFFFFFFFF); } protected: SkString onShortName() SK_OVERRIDE { return SkString("convex_poly_effect"); } SkISize onISize() SK_OVERRIDE { return SkISize::Make(720, 800); } void onOnceBeforeDraw() SK_OVERRIDE { SkPath tri; tri.moveTo(5.f, 5.f); tri.lineTo(100.f, 20.f); tri.lineTo(15.f, 100.f); fPaths.addToTail(tri); fPaths.addToTail(SkPath())->reverseAddPath(tri); tri.close(); fPaths.addToTail(tri); SkPath ngon; static const SkScalar kRadius = 50.f; const SkPoint center = { kRadius, kRadius }; for (int i = 0; i < GrConvexPolyEffect::kMaxEdges; ++i) { SkScalar angle = 2 * SK_ScalarPI * i / GrConvexPolyEffect::kMaxEdges; SkPoint point; point.fY = SkScalarSinCos(angle, &point.fX); point.scale(kRadius); point = center + point; if (0 == i) { ngon.moveTo(point); } else { ngon.lineTo(point); } } fPaths.addToTail(ngon); SkMatrix scaleM; scaleM.setScale(1.1f, 0.4f); ngon.transform(scaleM); fPaths.addToTail(ngon); // integer edges fRects.addToTail(SkRect::MakeLTRB(5.f, 1.f, 30.f, 25.f)); // half-integer edges fRects.addToTail(SkRect::MakeLTRB(5.5f, 0.5f, 29.5f, 24.5f)); // vertically/horizontally thin rects that cover pixel centers fRects.addToTail(SkRect::MakeLTRB(5.25f, 0.5f, 5.75f, 24.5f)); fRects.addToTail(SkRect::MakeLTRB(5.5f, 0.5f, 29.5f, 0.75f)); // vertically/horizontally thin rects that don't cover pixel centers fRects.addToTail(SkRect::MakeLTRB(5.55f, 0.5f, 5.75f, 24.5f)); fRects.addToTail(SkRect::MakeLTRB(5.5f, .05f, 29.5f, .25f)); // small in x and y fRects.addToTail(SkRect::MakeLTRB(5.05f, .55f, 5.45f, .85f)); // inverted in x and y fRects.addToTail(SkRect::MakeLTRB(100.f, 50.5f, 5.f, 0.5f)); } void onDraw(SkCanvas* canvas) SK_OVERRIDE { GrRenderTarget* rt = canvas->internal_private_accessTopLayerRenderTarget(); if (NULL == rt) { this->drawGpuOnlyMessage(canvas); return; } GrContext* context = rt->getContext(); if (NULL == context) { return; } SkAutoTUnref gp( GrDefaultGeoProcFactory::Create(GrDefaultGeoProcFactory::kPosition_GPType, 0xff000000)); SkScalar y = 0; for (SkTLList::Iter iter(fPaths, SkTLList::Iter::kHead_IterStart); iter.get(); iter.next()) { const SkPath* path = iter.get(); SkScalar x = 0; for (int et = 0; et < kGrProcessorEdgeTypeCnt; ++et) { GrTestTarget tt; context->getTestTarget(&tt); if (NULL == tt.target()) { SkDEBUGFAIL("Couldn't get Gr test target."); return; } SkMatrix m; SkPath p; m.setTranslate(x, y); path->transform(m, &p); GrPrimitiveEdgeType edgeType = (GrPrimitiveEdgeType) et; SkAutoTUnref fp(GrConvexPolyEffect::Create(edgeType, p)); if (!fp) { continue; } GrPipelineBuilder pipelineBuilder; pipelineBuilder.addCoverageProcessor(fp); pipelineBuilder.setRenderTarget(rt); ConvexPolyTestBatch::Geometry geometry; geometry.fColor = gp->color(); geometry.fBounds = p.getBounds(); SkAutoTUnref batch(ConvexPolyTestBatch::Create(gp, geometry)); tt.target()->drawBatch(&pipelineBuilder, batch, NULL); x += SkScalarCeilToScalar(path->getBounds().width() + 10.f); } // Draw AA and non AA paths using normal API for reference. canvas->save(); canvas->translate(x, y); SkPaint paint; canvas->drawPath(*path, paint); canvas->translate(path->getBounds().width() + 10.f, 0); paint.setAntiAlias(true); canvas->drawPath(*path, paint); canvas->restore(); y += SkScalarCeilToScalar(path->getBounds().height() + 20.f); } for (SkTLList::Iter iter(fRects, SkTLList::Iter::kHead_IterStart); iter.get(); iter.next()) { SkScalar x = 0; for (int et = 0; et < kGrProcessorEdgeTypeCnt; ++et) { GrTestTarget tt; context->getTestTarget(&tt); if (NULL == tt.target()) { SkDEBUGFAIL("Couldn't get Gr test target."); return; } SkRect rect = *iter.get(); rect.offset(x, y); GrPrimitiveEdgeType edgeType = (GrPrimitiveEdgeType) et; SkAutoTUnref fp(GrConvexPolyEffect::Create(edgeType, rect)); if (!fp) { continue; } GrPipelineBuilder pipelineBuilder; pipelineBuilder.addCoverageProcessor(fp); pipelineBuilder.setRenderTarget(rt); ConvexPolyTestBatch::Geometry geometry; geometry.fColor = gp->color(); geometry.fBounds = rect; SkAutoTUnref batch(ConvexPolyTestBatch::Create(gp, geometry)); tt.target()->drawBatch(&pipelineBuilder, batch, NULL); x += SkScalarCeilToScalar(rect.width() + 10.f); } // Draw rect without and with AA using normal API for reference canvas->save(); canvas->translate(x, y); SkPaint paint; canvas->drawRect(*iter.get(), paint); x += SkScalarCeilToScalar(iter.get()->width() + 10.f); paint.setAntiAlias(true); canvas->drawRect(*iter.get(), paint); canvas->restore(); y += SkScalarCeilToScalar(iter.get()->height() + 20.f); } } private: SkTLList fPaths; SkTLList fRects; typedef GM INHERITED; }; DEF_GM( return SkNEW(ConvexPolyEffect); ) } #endif