| Index: src/gpu/GrContext.cpp
|
| diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp
|
| index 3ed0b6baa26fc37c9483c44b0fa9b30aee85dd7b..550d7ff7c19a4f4c7d9a65cb66c1abe1250c7f03 100755
|
| --- a/src/gpu/GrContext.cpp
|
| +++ b/src/gpu/GrContext.cpp
|
| @@ -17,6 +17,7 @@
|
| #include "GrCaps.h"
|
| #include "GrContextOptions.h"
|
| #include "GrDefaultGeoProcFactory.h"
|
| +#include "GrDrawContext.h"
|
| #include "GrGpuResource.h"
|
| #include "GrGpuResourcePriv.h"
|
| #include "GrGpu.h"
|
| @@ -53,23 +54,61 @@
|
| #include "effects/GrSingleTextureEffect.h"
|
|
|
| #define ASSERT_OWNED_RESOURCE(R) SkASSERT(!(R) || (R)->getContext() == this)
|
| -#define RETURN_IF_ABANDONED if (!fDrawBuffer) { return; }
|
| -#define RETURN_FALSE_IF_ABANDONED if (!fDrawBuffer) { return false; }
|
| -#define RETURN_NULL_IF_ABANDONED if (!fDrawBuffer) { return NULL; }
|
| +#define RETURN_IF_ABANDONED if (fDrawingMgr.abandoned()) { return; }
|
| +#define RETURN_FALSE_IF_ABANDONED if (fDrawingMgr.abandoned()) { return false; }
|
| +#define RETURN_NULL_IF_ABANDONED if (fDrawingMgr.abandoned()) { return NULL; }
|
|
|
| -class GrContext::AutoCheckFlush {
|
| -public:
|
| - AutoCheckFlush(GrContext* context) : fContext(context) { SkASSERT(context); }
|
|
|
| - ~AutoCheckFlush() {
|
| - if (fContext->fFlushToReduceCacheSize) {
|
| - fContext->flush();
|
| - }
|
| +////////////////////////////////////////////////////////////////////////////////
|
| +
|
| +void GrContext::DrawingMgr::init(GrContext* context) {
|
| +#ifdef IMMEDIATE_MODE
|
| + fDrawTarget = SkNEW_ARGS(GrImmediateDrawTarget, (context));
|
| +#else
|
| + fDrawTarget = SkNEW_ARGS(GrInOrderDrawBuffer, (context));
|
| +#endif
|
| +
|
| + fDrawContext = SkNEW_ARGS(GrDrawContext, (context, fDrawTarget));
|
| +}
|
| +
|
| +GrContext::DrawingMgr::~DrawingMgr() {
|
| + SkSafeUnref(fDrawTarget);
|
| + SkSafeUnref(fDrawContext);
|
| +}
|
| +
|
| +void GrContext::DrawingMgr::abandon() {
|
| + SkSafeSetNull(fDrawTarget);
|
| + fDrawContext->fDrawTarget.reset(NULL);
|
| + SkSafeSetNull(fDrawContext);
|
| +}
|
| +
|
| +void GrContext::DrawingMgr::purgeResources() {
|
| + if (fDrawTarget) {
|
| + fDrawTarget->purgeResources();
|
| + }
|
| +}
|
| +
|
| +void GrContext::DrawingMgr::reset() {
|
| + if (fDrawTarget) {
|
| + fDrawTarget->reset();
|
| }
|
| +}
|
| +
|
| +void GrContext::DrawingMgr::flush() {
|
| + if (fDrawTarget) {
|
| + fDrawTarget->flush();
|
| + }
|
| +}
|
| +
|
| +GrDrawContext* GrContext::DrawingMgr::drawContext() {
|
| + if (this->abandoned()) {
|
| + return NULL;
|
| + }
|
| + return fDrawContext;
|
| +}
|
| +
|
| +////////////////////////////////////////////////////////////////////////////////
|
|
|
| -private:
|
| - GrContext* fContext;
|
| -};
|
|
|
| GrContext* GrContext::Create(GrBackend backend, GrBackendContext backendContext) {
|
| GrContextOptions defaultOptions;
|
| @@ -104,19 +143,16 @@ GrContext::GrContext() : fUniqueID(next_id()) {
|
| fPathRendererChain = NULL;
|
| fSoftwarePathRenderer = NULL;
|
| fBatchFontCache = NULL;
|
| - fDrawBuffer = NULL;
|
| fFlushToReduceCacheSize = false;
|
| - fAARectRenderer = NULL;
|
| - fOvalRenderer = NULL;
|
| fMaxTextureSizeOverride = 1 << 20;
|
| }
|
|
|
| bool GrContext::init(GrBackend backend, GrBackendContext backendContext,
|
| const GrContextOptions& options) {
|
| - SkASSERT(NULL == fGpu);
|
| + SkASSERT(!fGpu);
|
|
|
| fGpu = GrGpu::Create(backend, backendContext, options, this);
|
| - if (NULL == fGpu) {
|
| + if (!fGpu) {
|
| return false;
|
| }
|
| this->initCommon();
|
| @@ -130,16 +166,9 @@ void GrContext::initCommon() {
|
|
|
| fLayerCache.reset(SkNEW_ARGS(GrLayerCache, (this)));
|
|
|
| - fAARectRenderer = SkNEW(GrAARectRenderer);
|
| - fOvalRenderer = SkNEW(GrOvalRenderer);
|
| -
|
| fDidTestPMConversions = false;
|
|
|
| -#ifdef IMMEDIATE_MODE
|
| - fDrawBuffer = SkNEW_ARGS(GrImmediateDrawTarget, (this));
|
| -#else
|
| - fDrawBuffer = SkNEW_ARGS(GrInOrderDrawBuffer, (this));
|
| -#endif
|
| + fDrawingMgr.init(this);
|
|
|
| // GrBatchFontCache will eventually replace GrFontCache
|
| fBatchFontCache = SkNEW_ARGS(GrBatchFontCache, (this));
|
| @@ -148,7 +177,7 @@ void GrContext::initCommon() {
|
| }
|
|
|
| GrContext::~GrContext() {
|
| - if (NULL == fGpu) {
|
| + if (!fGpu) {
|
| return;
|
| }
|
|
|
| @@ -161,10 +190,6 @@ GrContext::~GrContext() {
|
| SkDELETE(fResourceProvider);
|
| SkDELETE(fResourceCache);
|
| SkDELETE(fBatchFontCache);
|
| - SkDELETE(fDrawBuffer);
|
| -
|
| - fAARectRenderer->unref();
|
| - fOvalRenderer->unref();
|
|
|
| fGpu->unref();
|
| SkSafeUnref(fPathRendererChain);
|
| @@ -184,8 +209,7 @@ void GrContext::abandonContext() {
|
| SkSafeSetNull(fPathRendererChain);
|
| SkSafeSetNull(fSoftwarePathRenderer);
|
|
|
| - SkDELETE(fDrawBuffer);
|
| - fDrawBuffer = NULL;
|
| + fDrawingMgr.abandon();
|
|
|
| fBatchFontCache->freeAll();
|
| fLayerCache->freeAll();
|
| @@ -199,9 +223,7 @@ void GrContext::resetContext(uint32_t state) {
|
| void GrContext::freeGpuResources() {
|
| this->flush();
|
|
|
| - if (fDrawBuffer) {
|
| - fDrawBuffer->purgeResources();
|
| - }
|
| + fDrawingMgr.purgeResources();
|
|
|
| fBatchFontCache->freeAll();
|
| fLayerCache->freeAll();
|
| @@ -238,6 +260,10 @@ GrTextContext* GrContext::createTextContext(GrRenderTarget* renderTarget,
|
|
|
| ////////////////////////////////////////////////////////////////////////////////
|
|
|
| +bool GrContext::shaderDerivativeSupport() const {
|
| + return fGpu->caps()->shaderCaps()->shaderDerivativeSupport();
|
| +}
|
| +
|
| bool GrContext::isConfigTexturable(GrPixelConfig config) const {
|
| return fGpu->caps()->isConfigTexturable(config);
|
| }
|
| @@ -278,1093 +304,15 @@ int GrContext::getMaxSampleCount() const {
|
| return fGpu->caps()->maxSampleCount();
|
| }
|
|
|
| -///////////////////////////////////////////////////////////////////////////////
|
| -
|
| -void GrContext::clear(const SkIRect* rect,
|
| - const GrColor color,
|
| - bool canIgnoreRect,
|
| - GrRenderTarget* renderTarget) {
|
| - RETURN_IF_ABANDONED
|
| - ASSERT_OWNED_RESOURCE(renderTarget);
|
| - SkASSERT(renderTarget);
|
| -
|
| - AutoCheckFlush acf(this);
|
| - GR_CREATE_TRACE_MARKER_CONTEXT("GrContext::clear", this);
|
| - GrDrawTarget* target = this->prepareToDraw();
|
| - if (NULL == target) {
|
| - return;
|
| - }
|
| - target->clear(rect, color, canIgnoreRect, renderTarget);
|
| -}
|
| -
|
| -void GrContext::drawPaint(GrRenderTarget* rt,
|
| - const GrClip& clip,
|
| - const GrPaint& origPaint,
|
| - const SkMatrix& viewMatrix) {
|
| - RETURN_IF_ABANDONED
|
| - // set rect to be big enough to fill the space, but not super-huge, so we
|
| - // don't overflow fixed-point implementations
|
| - SkRect r;
|
| - r.setLTRB(0, 0,
|
| - SkIntToScalar(rt->width()),
|
| - SkIntToScalar(rt->height()));
|
| - SkTCopyOnFirstWrite<GrPaint> paint(origPaint);
|
| -
|
| - // by definition this fills the entire clip, no need for AA
|
| - if (paint->isAntiAlias()) {
|
| - paint.writable()->setAntiAlias(false);
|
| - }
|
| -
|
| - bool isPerspective = viewMatrix.hasPerspective();
|
| -
|
| - // We attempt to map r by the inverse matrix and draw that. mapRect will
|
| - // map the four corners and bound them with a new rect. This will not
|
| - // produce a correct result for some perspective matrices.
|
| - if (!isPerspective) {
|
| - SkMatrix inverse;
|
| - if (!viewMatrix.invert(&inverse)) {
|
| - SkDebugf("Could not invert matrix\n");
|
| - return;
|
| - }
|
| - inverse.mapRect(&r);
|
| - this->drawRect(rt, clip, *paint, viewMatrix, r);
|
| - } else {
|
| - SkMatrix localMatrix;
|
| - if (!viewMatrix.invert(&localMatrix)) {
|
| - SkDebugf("Could not invert matrix\n");
|
| - return;
|
| - }
|
| -
|
| - AutoCheckFlush acf(this);
|
| - GrPipelineBuilder pipelineBuilder;
|
| - GrDrawTarget* target = this->prepareToDraw(&pipelineBuilder, rt, clip, paint, &acf);
|
| - if (NULL == target) {
|
| - return;
|
| - }
|
| -
|
| - GR_CREATE_TRACE_MARKER("GrContext::drawPaintWithPerspective", target);
|
| - target->drawRect(&pipelineBuilder,
|
| - paint->getColor(),
|
| - SkMatrix::I(),
|
| - r,
|
| - NULL,
|
| - &localMatrix);
|
| - }
|
| -}
|
| -
|
| -////////////////////////////////////////////////////////////////////////////////
|
| -
|
| -static inline bool is_irect(const SkRect& r) {
|
| - return SkScalarIsInt(r.fLeft) && SkScalarIsInt(r.fTop) &&
|
| - SkScalarIsInt(r.fRight) && SkScalarIsInt(r.fBottom);
|
| -}
|
| -
|
| -static bool apply_aa_to_rect(GrDrawTarget* target,
|
| - GrPipelineBuilder* pipelineBuilder,
|
| - SkRect* devBoundRect,
|
| - const SkRect& rect,
|
| - SkScalar strokeWidth,
|
| - const SkMatrix& combinedMatrix,
|
| - GrColor color) {
|
| - if (pipelineBuilder->getRenderTarget()->isMultisampled()) {
|
| - return false;
|
| - }
|
| -
|
| -#if defined(SHADER_AA_FILL_RECT) || !defined(IGNORE_ROT_AA_RECT_OPT)
|
| - if (strokeWidth >= 0) {
|
| -#endif
|
| - if (!combinedMatrix.preservesAxisAlignment()) {
|
| - return false;
|
| - }
|
| -
|
| -#if defined(SHADER_AA_FILL_RECT) || !defined(IGNORE_ROT_AA_RECT_OPT)
|
| - } else {
|
| - if (!combinedMatrix.preservesRightAngles()) {
|
| - return false;
|
| - }
|
| - }
|
| -#endif
|
| -
|
| - combinedMatrix.mapRect(devBoundRect, rect);
|
| - if (!combinedMatrix.rectStaysRect()) {
|
| - return true;
|
| - }
|
| -
|
| - if (strokeWidth < 0) {
|
| - return !is_irect(*devBoundRect);
|
| - }
|
| -
|
| - return true;
|
| -}
|
| -
|
| -static inline bool rect_contains_inclusive(const SkRect& rect, const SkPoint& point) {
|
| - return point.fX >= rect.fLeft && point.fX <= rect.fRight &&
|
| - point.fY >= rect.fTop && point.fY <= rect.fBottom;
|
| -}
|
| -
|
| -class StrokeRectBatch : public GrBatch {
|
| -public:
|
| - struct Geometry {
|
| - GrColor fColor;
|
| - SkMatrix fViewMatrix;
|
| - SkRect fRect;
|
| - SkScalar fStrokeWidth;
|
| - };
|
| -
|
| - static GrBatch* Create(const Geometry& geometry, bool snapToPixelCenters) {
|
| - return SkNEW_ARGS(StrokeRectBatch, (geometry, snapToPixelCenters));
|
| - }
|
| -
|
| - const char* name() const override { return "StrokeRectBatch"; }
|
| -
|
| - void getInvariantOutputColor(GrInitInvariantOutput* out) const override {
|
| - // When this is called on a batch, there is only one geometry bundle
|
| - out->setKnownFourComponents(fGeoData[0].fColor);
|
| - }
|
| -
|
| - void getInvariantOutputCoverage(GrInitInvariantOutput* out) const override {
|
| - out->setKnownSingleComponent(0xff);
|
| - }
|
| -
|
| - void initBatchTracker(const GrPipelineInfo& init) 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;
|
| - }
|
| -
|
| - void generateGeometry(GrBatchTarget* batchTarget, const GrPipeline* pipeline) override {
|
| - SkAutoTUnref<const GrGeometryProcessor> gp(
|
| - GrDefaultGeoProcFactory::Create(GrDefaultGeoProcFactory::kPosition_GPType,
|
| - this->color(),
|
| - this->usesLocalCoords(),
|
| - this->coverageIgnored(),
|
| - this->viewMatrix(),
|
| - SkMatrix::I()));
|
| -
|
| - batchTarget->initDraw(gp, pipeline);
|
| -
|
| - size_t vertexStride = gp->getVertexStride();
|
| -
|
| - SkASSERT(vertexStride == sizeof(GrDefaultGeoProcFactory::PositionAttr));
|
| -
|
| - Geometry& args = fGeoData[0];
|
| -
|
| - int vertexCount = kVertsPerHairlineRect;
|
| - if (args.fStrokeWidth > 0) {
|
| - vertexCount = kVertsPerStrokeRect;
|
| - }
|
| -
|
| - const GrVertexBuffer* vertexBuffer;
|
| - int firstVertex;
|
| -
|
| - void* verts = batchTarget->makeVertSpace(vertexStride, vertexCount,
|
| - &vertexBuffer, &firstVertex);
|
| -
|
| - if (!verts) {
|
| - SkDebugf("Could not allocate vertices\n");
|
| - return;
|
| - }
|
| -
|
| - SkPoint* vertex = reinterpret_cast<SkPoint*>(verts);
|
| -
|
| - GrPrimitiveType primType;
|
| -
|
| - if (args.fStrokeWidth > 0) {;
|
| - primType = kTriangleStrip_GrPrimitiveType;
|
| - args.fRect.sort();
|
| - this->setStrokeRectStrip(vertex, args.fRect, args.fStrokeWidth);
|
| - } else {
|
| - // hairline
|
| - primType = kLineStrip_GrPrimitiveType;
|
| - vertex[0].set(args.fRect.fLeft, args.fRect.fTop);
|
| - vertex[1].set(args.fRect.fRight, args.fRect.fTop);
|
| - vertex[2].set(args.fRect.fRight, args.fRect.fBottom);
|
| - vertex[3].set(args.fRect.fLeft, args.fRect.fBottom);
|
| - vertex[4].set(args.fRect.fLeft, args.fRect.fTop);
|
| - }
|
| -
|
| - GrVertices vertices;
|
| - vertices.init(primType, vertexBuffer, firstVertex, vertexCount);
|
| - batchTarget->draw(vertices);
|
| - }
|
| -
|
| - SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
|
| -
|
| -private:
|
| - StrokeRectBatch(const Geometry& geometry, bool snapToPixelCenters) {
|
| - this->initClassID<StrokeRectBatch>();
|
| -
|
| - fBatch.fHairline = geometry.fStrokeWidth == 0;
|
| -
|
| - fGeoData.push_back(geometry);
|
| -
|
| - // setup bounds
|
| - fBounds = geometry.fRect;
|
| - SkScalar rad = SkScalarHalf(geometry.fStrokeWidth);
|
| - fBounds.outset(rad, rad);
|
| - geometry.fViewMatrix.mapRect(&fBounds);
|
| -
|
| - // If our caller snaps to pixel centers then we have to round out the bounds
|
| - if (snapToPixelCenters) {
|
| - fBounds.roundOut();
|
| - }
|
| - }
|
| -
|
| - /* create a triangle strip that strokes the specified rect. There are 8
|
| - unique vertices, but we repeat the last 2 to close up. Alternatively we
|
| - could use an indices array, and then only send 8 verts, but not sure that
|
| - would be faster.
|
| - */
|
| - void setStrokeRectStrip(SkPoint verts[10], const SkRect& rect, SkScalar width) {
|
| - const SkScalar rad = SkScalarHalf(width);
|
| - // TODO we should be able to enable this assert, but we'd have to filter these draws
|
| - // this is a bug
|
| - //SkASSERT(rad < rect.width() / 2 && rad < rect.height() / 2);
|
| -
|
| - verts[0].set(rect.fLeft + rad, rect.fTop + rad);
|
| - verts[1].set(rect.fLeft - rad, rect.fTop - rad);
|
| - verts[2].set(rect.fRight - rad, rect.fTop + rad);
|
| - verts[3].set(rect.fRight + rad, rect.fTop - rad);
|
| - verts[4].set(rect.fRight - rad, rect.fBottom - rad);
|
| - verts[5].set(rect.fRight + rad, rect.fBottom + rad);
|
| - verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
|
| - verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
|
| - verts[8] = verts[0];
|
| - verts[9] = verts[1];
|
| - }
|
| -
|
| -
|
| - GrColor color() const { return fBatch.fColor; }
|
| - bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; }
|
| - bool colorIgnored() const { return fBatch.fColorIgnored; }
|
| - const SkMatrix& viewMatrix() const { return fGeoData[0].fViewMatrix; }
|
| - bool hairline() const { return fBatch.fHairline; }
|
| - bool coverageIgnored() const { return fBatch.fCoverageIgnored; }
|
| -
|
| - bool onCombineIfPossible(GrBatch* t) override {
|
| - // StrokeRectBatch* that = t->cast<StrokeRectBatch>();
|
| -
|
| - // NonAA stroke rects cannot batch right now
|
| - // TODO make these batchable
|
| - return false;
|
| - }
|
| -
|
| - struct BatchTracker {
|
| - GrColor fColor;
|
| - bool fUsesLocalCoords;
|
| - bool fColorIgnored;
|
| - bool fCoverageIgnored;
|
| - bool fHairline;
|
| - };
|
| -
|
| - const static int kVertsPerHairlineRect = 5;
|
| - const static int kVertsPerStrokeRect = 10;
|
| -
|
| - BatchTracker fBatch;
|
| - SkSTArray<1, Geometry, true> fGeoData;
|
| -};
|
| -
|
| -void GrContext::drawRect(GrRenderTarget* rt,
|
| - const GrClip& clip,
|
| - const GrPaint& paint,
|
| - const SkMatrix& viewMatrix,
|
| - const SkRect& rect,
|
| - const GrStrokeInfo* strokeInfo) {
|
| - RETURN_IF_ABANDONED
|
| - if (strokeInfo && strokeInfo->isDashed()) {
|
| - SkPath path;
|
| - path.setIsVolatile(true);
|
| - path.addRect(rect);
|
| - this->drawPath(rt, clip, paint, viewMatrix, path, *strokeInfo);
|
| - return;
|
| - }
|
| -
|
| - AutoCheckFlush acf(this);
|
| - GrPipelineBuilder pipelineBuilder;
|
| - GrDrawTarget* target = this->prepareToDraw(&pipelineBuilder, rt, clip, &paint, &acf);
|
| - if (NULL == target) {
|
| - return;
|
| - }
|
| -
|
| - GR_CREATE_TRACE_MARKER("GrContext::drawRect", target);
|
| - SkScalar width = NULL == strokeInfo ? -1 : strokeInfo->getWidth();
|
| -
|
| - // Check if this is a full RT draw and can be replaced with a clear. We don't bother checking
|
| - // cases where the RT is fully inside a stroke.
|
| - if (width < 0) {
|
| - SkRect rtRect;
|
| - pipelineBuilder.getRenderTarget()->getBoundsRect(&rtRect);
|
| - SkRect clipSpaceRTRect = rtRect;
|
| - bool checkClip = GrClip::kWideOpen_ClipType != clip.clipType();
|
| - if (checkClip) {
|
| - clipSpaceRTRect.offset(SkIntToScalar(clip.origin().fX),
|
| - SkIntToScalar(clip.origin().fY));
|
| - }
|
| - // Does the clip contain the entire RT?
|
| - if (!checkClip || clip.quickContains(clipSpaceRTRect)) {
|
| - SkMatrix invM;
|
| - if (!viewMatrix.invert(&invM)) {
|
| - return;
|
| - }
|
| - // Does the rect bound the RT?
|
| - SkPoint srcSpaceRTQuad[4];
|
| - invM.mapRectToQuad(srcSpaceRTQuad, rtRect);
|
| - if (rect_contains_inclusive(rect, srcSpaceRTQuad[0]) &&
|
| - rect_contains_inclusive(rect, srcSpaceRTQuad[1]) &&
|
| - rect_contains_inclusive(rect, srcSpaceRTQuad[2]) &&
|
| - rect_contains_inclusive(rect, srcSpaceRTQuad[3])) {
|
| - // Will it blend?
|
| - GrColor clearColor;
|
| - if (paint.isOpaqueAndConstantColor(&clearColor)) {
|
| - target->clear(NULL, clearColor, true, rt);
|
| - return;
|
| - }
|
| - }
|
| - }
|
| - }
|
| -
|
| - GrColor color = paint.getColor();
|
| - SkRect devBoundRect;
|
| - bool needAA = paint.isAntiAlias() && !pipelineBuilder.getRenderTarget()->isMultisampled();
|
| - bool doAA = needAA && apply_aa_to_rect(target, &pipelineBuilder, &devBoundRect, rect, width,
|
| - viewMatrix, color);
|
| -
|
| - if (doAA) {
|
| - if (width >= 0) {
|
| - fAARectRenderer->strokeAARect(target,
|
| - &pipelineBuilder,
|
| - color,
|
| - viewMatrix,
|
| - rect,
|
| - devBoundRect,
|
| - *strokeInfo);
|
| - } else {
|
| - // filled AA rect
|
| - fAARectRenderer->fillAARect(target,
|
| - &pipelineBuilder,
|
| - color,
|
| - viewMatrix,
|
| - rect,
|
| - devBoundRect);
|
| - }
|
| - return;
|
| - }
|
| -
|
| - if (width >= 0) {
|
| - StrokeRectBatch::Geometry geometry;
|
| - geometry.fViewMatrix = viewMatrix;
|
| - geometry.fColor = color;
|
| - geometry.fRect = rect;
|
| - geometry.fStrokeWidth = width;
|
| -
|
| - // Non-AA hairlines are snapped to pixel centers to make which pixels are hit deterministic
|
| - bool snapToPixelCenters = (0 == width && !rt->isMultisampled());
|
| - SkAutoTUnref<GrBatch> batch(StrokeRectBatch::Create(geometry, snapToPixelCenters));
|
| -
|
| - // Depending on sub-pixel coordinates and the particular GPU, we may lose a corner of
|
| - // hairline rects. We jam all the vertices to pixel centers to avoid this, but not when MSAA
|
| - // is enabled because it can cause ugly artifacts.
|
| - pipelineBuilder.setState(GrPipelineBuilder::kSnapVerticesToPixelCenters_Flag,
|
| - snapToPixelCenters);
|
| - target->drawBatch(&pipelineBuilder, batch);
|
| - } else {
|
| - // filled BW rect
|
| - target->drawSimpleRect(&pipelineBuilder, color, viewMatrix, rect);
|
| - }
|
| -}
|
| -
|
| -void GrContext::drawNonAARectToRect(GrRenderTarget* rt,
|
| - const GrClip& clip,
|
| - const GrPaint& paint,
|
| - const SkMatrix& viewMatrix,
|
| - const SkRect& rectToDraw,
|
| - const SkRect& localRect,
|
| - const SkMatrix* localMatrix) {
|
| - RETURN_IF_ABANDONED
|
| - AutoCheckFlush acf(this);
|
| - GrPipelineBuilder pipelineBuilder;
|
| - GrDrawTarget* target = this->prepareToDraw(&pipelineBuilder, rt, clip, &paint, &acf);
|
| - if (NULL == target) {
|
| - return;
|
| - }
|
| -
|
| - GR_CREATE_TRACE_MARKER("GrContext::drawRectToRect", target);
|
| -
|
| - target->drawRect(&pipelineBuilder,
|
| - paint.getColor(),
|
| - viewMatrix,
|
| - rectToDraw,
|
| - &localRect,
|
| - localMatrix);
|
| -}
|
| -
|
| -static const GrGeometryProcessor* set_vertex_attributes(bool hasLocalCoords,
|
| - bool hasColors,
|
| - int* colorOffset,
|
| - int* texOffset,
|
| - GrColor color,
|
| - const SkMatrix& viewMatrix,
|
| - bool coverageIgnored) {
|
| - *texOffset = -1;
|
| - *colorOffset = -1;
|
| - uint32_t flags = GrDefaultGeoProcFactory::kPosition_GPType;
|
| - if (hasLocalCoords && hasColors) {
|
| - *colorOffset = sizeof(SkPoint);
|
| - *texOffset = sizeof(SkPoint) + sizeof(GrColor);
|
| - flags |= GrDefaultGeoProcFactory::kColor_GPType |
|
| - GrDefaultGeoProcFactory::kLocalCoord_GPType;
|
| - } else if (hasLocalCoords) {
|
| - *texOffset = sizeof(SkPoint);
|
| - flags |= GrDefaultGeoProcFactory::kLocalCoord_GPType;
|
| - } else if (hasColors) {
|
| - *colorOffset = sizeof(SkPoint);
|
| - flags |= GrDefaultGeoProcFactory::kColor_GPType;
|
| - }
|
| - return GrDefaultGeoProcFactory::Create(flags, color, hasLocalCoords, coverageIgnored,
|
| - viewMatrix, SkMatrix::I());
|
| -}
|
| -
|
| -class DrawVerticesBatch : public GrBatch {
|
| -public:
|
| - struct Geometry {
|
| - GrColor fColor;
|
| - SkTDArray<SkPoint> fPositions;
|
| - SkTDArray<uint16_t> fIndices;
|
| - SkTDArray<GrColor> fColors;
|
| - SkTDArray<SkPoint> fLocalCoords;
|
| - };
|
| -
|
| - static GrBatch* Create(const Geometry& geometry, GrPrimitiveType primitiveType,
|
| - const SkMatrix& viewMatrix,
|
| - const SkPoint* positions, int vertexCount,
|
| - const uint16_t* indices, int indexCount,
|
| - const GrColor* colors, const SkPoint* localCoords,
|
| - const SkRect& bounds) {
|
| - return SkNEW_ARGS(DrawVerticesBatch, (geometry, primitiveType, viewMatrix, positions,
|
| - vertexCount, indices, indexCount, colors,
|
| - localCoords, bounds));
|
| - }
|
| -
|
| - const char* name() const override { return "DrawVerticesBatch"; }
|
| -
|
| - void getInvariantOutputColor(GrInitInvariantOutput* out) const override {
|
| - // When this is called on a batch, there is only one geometry bundle
|
| - if (this->hasColors()) {
|
| - out->setUnknownFourComponents();
|
| - } else {
|
| - out->setKnownFourComponents(fGeoData[0].fColor);
|
| - }
|
| - }
|
| -
|
| - void getInvariantOutputCoverage(GrInitInvariantOutput* out) const override {
|
| - out->setKnownSingleComponent(0xff);
|
| - }
|
| -
|
| - void initBatchTracker(const GrPipelineInfo& init) 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;
|
| - }
|
| -
|
| - void generateGeometry(GrBatchTarget* batchTarget, const GrPipeline* pipeline) override {
|
| - int colorOffset = -1, texOffset = -1;
|
| - SkAutoTUnref<const GrGeometryProcessor> gp(
|
| - set_vertex_attributes(this->hasLocalCoords(), this->hasColors(), &colorOffset,
|
| - &texOffset, this->color(), this->viewMatrix(),
|
| - this->coverageIgnored()));
|
| -
|
| - batchTarget->initDraw(gp, pipeline);
|
| -
|
| - size_t vertexStride = gp->getVertexStride();
|
| -
|
| - SkASSERT(vertexStride == sizeof(SkPoint) + (this->hasLocalCoords() ? sizeof(SkPoint) : 0)
|
| - + (this->hasColors() ? sizeof(GrColor) : 0));
|
| -
|
| - int instanceCount = fGeoData.count();
|
| -
|
| - const GrVertexBuffer* vertexBuffer;
|
| - int firstVertex;
|
| -
|
| - void* verts = batchTarget->makeVertSpace(vertexStride, this->vertexCount(),
|
| - &vertexBuffer, &firstVertex);
|
| -
|
| - if (!verts) {
|
| - SkDebugf("Could not allocate vertices\n");
|
| - return;
|
| - }
|
| -
|
| - const GrIndexBuffer* indexBuffer = NULL;
|
| - int firstIndex = 0;
|
| -
|
| - uint16_t* indices = NULL;
|
| - if (this->hasIndices()) {
|
| - indices = batchTarget->makeIndexSpace(this->indexCount(), &indexBuffer, &firstIndex);
|
| -
|
| - if (!indices) {
|
| - SkDebugf("Could not allocate indices\n");
|
| - return;
|
| - }
|
| - }
|
| -
|
| - int indexOffset = 0;
|
| - int vertexOffset = 0;
|
| - for (int i = 0; i < instanceCount; i++) {
|
| - const Geometry& args = fGeoData[i];
|
| -
|
| - // TODO we can actually cache this interleaved and then just memcopy
|
| - if (this->hasIndices()) {
|
| - for (int j = 0; j < args.fIndices.count(); ++j, ++indexOffset) {
|
| - *(indices + indexOffset) = args.fIndices[j] + vertexOffset;
|
| - }
|
| - }
|
| -
|
| - for (int j = 0; j < args.fPositions.count(); ++j) {
|
| - *((SkPoint*)verts) = args.fPositions[j];
|
| - if (this->hasColors()) {
|
| - *(GrColor*)((intptr_t)verts + colorOffset) = args.fColors[j];
|
| - }
|
| - if (this->hasLocalCoords()) {
|
| - *(SkPoint*)((intptr_t)verts + texOffset) = args.fLocalCoords[j];
|
| - }
|
| - verts = (void*)((intptr_t)verts + vertexStride);
|
| - vertexOffset++;
|
| - }
|
| - }
|
| -
|
| - GrVertices vertices;
|
| - if (this->hasIndices()) {
|
| - vertices.initIndexed(this->primitiveType(), vertexBuffer, indexBuffer, firstVertex,
|
| - firstIndex, this->vertexCount(), this->indexCount());
|
| -
|
| - } else {
|
| - vertices.init(this->primitiveType(), vertexBuffer, firstVertex, this->vertexCount());
|
| - }
|
| - batchTarget->draw(vertices);
|
| - }
|
| -
|
| - SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
|
| -
|
| -private:
|
| - DrawVerticesBatch(const Geometry& geometry, GrPrimitiveType primitiveType,
|
| - const SkMatrix& viewMatrix,
|
| - const SkPoint* positions, int vertexCount,
|
| - const uint16_t* indices, int indexCount,
|
| - const GrColor* colors, const SkPoint* localCoords, const SkRect& bounds) {
|
| - this->initClassID<DrawVerticesBatch>();
|
| - SkASSERT(positions);
|
| -
|
| - fBatch.fViewMatrix = viewMatrix;
|
| - Geometry& installedGeo = fGeoData.push_back(geometry);
|
| -
|
| - installedGeo.fPositions.append(vertexCount, positions);
|
| - if (indices) {
|
| - installedGeo.fIndices.append(indexCount, indices);
|
| - fBatch.fHasIndices = true;
|
| - } else {
|
| - fBatch.fHasIndices = false;
|
| - }
|
| -
|
| - if (colors) {
|
| - installedGeo.fColors.append(vertexCount, colors);
|
| - fBatch.fHasColors = true;
|
| - } else {
|
| - fBatch.fHasColors = false;
|
| - }
|
| -
|
| - if (localCoords) {
|
| - installedGeo.fLocalCoords.append(vertexCount, localCoords);
|
| - fBatch.fHasLocalCoords = true;
|
| - } else {
|
| - fBatch.fHasLocalCoords = false;
|
| - }
|
| - fBatch.fVertexCount = vertexCount;
|
| - fBatch.fIndexCount = indexCount;
|
| - fBatch.fPrimitiveType = primitiveType;
|
| -
|
| - this->setBounds(bounds);
|
| - }
|
| -
|
| - GrPrimitiveType primitiveType() const { return fBatch.fPrimitiveType; }
|
| - bool batchablePrimitiveType() const {
|
| - return kTriangles_GrPrimitiveType == fBatch.fPrimitiveType ||
|
| - kLines_GrPrimitiveType == fBatch.fPrimitiveType ||
|
| - kPoints_GrPrimitiveType == fBatch.fPrimitiveType;
|
| - }
|
| - GrColor color() const { return fBatch.fColor; }
|
| - bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; }
|
| - bool colorIgnored() const { return fBatch.fColorIgnored; }
|
| - const SkMatrix& viewMatrix() const { return fBatch.fViewMatrix; }
|
| - bool hasColors() const { return fBatch.fHasColors; }
|
| - bool hasIndices() const { return fBatch.fHasIndices; }
|
| - bool hasLocalCoords() const { return fBatch.fHasLocalCoords; }
|
| - int vertexCount() const { return fBatch.fVertexCount; }
|
| - int indexCount() const { return fBatch.fIndexCount; }
|
| - bool coverageIgnored() const { return fBatch.fCoverageIgnored; }
|
| -
|
| - bool onCombineIfPossible(GrBatch* t) override {
|
| - DrawVerticesBatch* that = t->cast<DrawVerticesBatch>();
|
| -
|
| - if (!this->batchablePrimitiveType() || this->primitiveType() != that->primitiveType()) {
|
| - return false;
|
| - }
|
| -
|
| - SkASSERT(this->usesLocalCoords() == that->usesLocalCoords());
|
| -
|
| - // We currently use a uniform viewmatrix for this batch
|
| - if (!this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
|
| - return false;
|
| - }
|
| -
|
| - if (this->hasColors() != that->hasColors()) {
|
| - return false;
|
| - }
|
| -
|
| - if (this->hasIndices() != that->hasIndices()) {
|
| - return false;
|
| - }
|
| -
|
| - if (this->hasLocalCoords() != that->hasLocalCoords()) {
|
| - return false;
|
| - }
|
| -
|
| - if (!this->hasColors() && this->color() != that->color()) {
|
| - return false;
|
| - }
|
| -
|
| - if (this->color() != that->color()) {
|
| - fBatch.fColor = GrColor_ILLEGAL;
|
| - }
|
| - fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin());
|
| - fBatch.fVertexCount += that->vertexCount();
|
| - fBatch.fIndexCount += that->indexCount();
|
| -
|
| - this->joinBounds(that->bounds());
|
| - return true;
|
| - }
|
| -
|
| - struct BatchTracker {
|
| - GrPrimitiveType fPrimitiveType;
|
| - SkMatrix fViewMatrix;
|
| - GrColor fColor;
|
| - bool fUsesLocalCoords;
|
| - bool fColorIgnored;
|
| - bool fCoverageIgnored;
|
| - bool fHasColors;
|
| - bool fHasIndices;
|
| - bool fHasLocalCoords;
|
| - int fVertexCount;
|
| - int fIndexCount;
|
| - };
|
| -
|
| - BatchTracker fBatch;
|
| - SkSTArray<1, Geometry, true> fGeoData;
|
| -};
|
| -
|
| -void GrContext::drawVertices(GrRenderTarget* rt,
|
| - const GrClip& clip,
|
| - const GrPaint& paint,
|
| - const SkMatrix& viewMatrix,
|
| - GrPrimitiveType primitiveType,
|
| - int vertexCount,
|
| - const SkPoint positions[],
|
| - const SkPoint texCoords[],
|
| - const GrColor colors[],
|
| - const uint16_t indices[],
|
| - int indexCount) {
|
| - RETURN_IF_ABANDONED
|
| - AutoCheckFlush acf(this);
|
| - GrPipelineBuilder pipelineBuilder;
|
| -
|
| - GrDrawTarget* target = this->prepareToDraw(&pipelineBuilder, rt, clip, &paint, &acf);
|
| - if (NULL == target) {
|
| - return;
|
| - }
|
| -
|
| - GR_CREATE_TRACE_MARKER("GrContext::drawVertices", target);
|
| -
|
| - // TODO clients should give us bounds
|
| - SkRect bounds;
|
| - if (!bounds.setBoundsCheck(positions, vertexCount)) {
|
| - SkDebugf("drawVertices call empty bounds\n");
|
| - return;
|
| - }
|
| -
|
| - viewMatrix.mapRect(&bounds);
|
| -
|
| - // If we don't have AA then we outset for a half pixel in each direction to account for
|
| - // snapping
|
| - if (!paint.isAntiAlias()) {
|
| - bounds.outset(0.5f, 0.5f);
|
| - }
|
| -
|
| - DrawVerticesBatch::Geometry geometry;
|
| - geometry.fColor = paint.getColor();
|
| - SkAutoTUnref<GrBatch> batch(DrawVerticesBatch::Create(geometry, primitiveType, viewMatrix,
|
| - positions, vertexCount, indices,
|
| - indexCount, colors, texCoords,
|
| - bounds));
|
| -
|
| - target->drawBatch(&pipelineBuilder, batch);
|
| -}
|
| -
|
| -///////////////////////////////////////////////////////////////////////////////
|
| -
|
| -void GrContext::drawRRect(GrRenderTarget*rt,
|
| - const GrClip& clip,
|
| - const GrPaint& paint,
|
| - const SkMatrix& viewMatrix,
|
| - const SkRRect& rrect,
|
| - const GrStrokeInfo& strokeInfo) {
|
| - RETURN_IF_ABANDONED
|
| - if (rrect.isEmpty()) {
|
| - return;
|
| - }
|
| -
|
| - if (strokeInfo.isDashed()) {
|
| - SkPath path;
|
| - path.setIsVolatile(true);
|
| - path.addRRect(rrect);
|
| - this->drawPath(rt, clip, paint, viewMatrix, path, strokeInfo);
|
| - return;
|
| - }
|
| -
|
| - AutoCheckFlush acf(this);
|
| - GrPipelineBuilder pipelineBuilder;
|
| - GrDrawTarget* target = this->prepareToDraw(&pipelineBuilder, rt, clip, &paint, &acf);
|
| - if (NULL == target) {
|
| - return;
|
| - }
|
| -
|
| - GR_CREATE_TRACE_MARKER("GrContext::drawRRect", target);
|
| -
|
| - GrColor color = paint.getColor();
|
| - if (!fOvalRenderer->drawRRect(target,
|
| - &pipelineBuilder,
|
| - color,
|
| - viewMatrix,
|
| - paint.isAntiAlias(),
|
| - rrect,
|
| - strokeInfo)) {
|
| - SkPath path;
|
| - path.setIsVolatile(true);
|
| - path.addRRect(rrect);
|
| - this->internalDrawPath(target, &pipelineBuilder, viewMatrix, color, paint.isAntiAlias(),
|
| - path, strokeInfo);
|
| - }
|
| -}
|
| -
|
| -///////////////////////////////////////////////////////////////////////////////
|
| -
|
| -void GrContext::drawDRRect(GrRenderTarget* rt,
|
| - const GrClip& clip,
|
| - const GrPaint& paint,
|
| - const SkMatrix& viewMatrix,
|
| - const SkRRect& outer,
|
| - const SkRRect& inner) {
|
| - RETURN_IF_ABANDONED
|
| - if (outer.isEmpty()) {
|
| - return;
|
| - }
|
| -
|
| - AutoCheckFlush acf(this);
|
| - GrPipelineBuilder pipelineBuilder;
|
| - GrDrawTarget* target = this->prepareToDraw(&pipelineBuilder, rt, clip, &paint, &acf);
|
| -
|
| - GR_CREATE_TRACE_MARKER("GrContext::drawDRRect", target);
|
| -
|
| - GrColor color = paint.getColor();
|
| - if (!fOvalRenderer->drawDRRect(target,
|
| - &pipelineBuilder,
|
| - color,
|
| - viewMatrix,
|
| - paint.isAntiAlias(),
|
| - outer,
|
| - inner)) {
|
| - SkPath path;
|
| - path.setIsVolatile(true);
|
| - path.addRRect(inner);
|
| - path.addRRect(outer);
|
| - path.setFillType(SkPath::kEvenOdd_FillType);
|
| - GrStrokeInfo fillRec(SkStrokeRec::kFill_InitStyle);
|
| - this->internalDrawPath(target, &pipelineBuilder, viewMatrix, color, paint.isAntiAlias(),
|
| - path, fillRec);
|
| - }
|
| -}
|
| -
|
| -///////////////////////////////////////////////////////////////////////////////
|
| -
|
| -void GrContext::drawOval(GrRenderTarget* rt,
|
| - const GrClip& clip,
|
| - const GrPaint& paint,
|
| - const SkMatrix& viewMatrix,
|
| - const SkRect& oval,
|
| - const GrStrokeInfo& strokeInfo) {
|
| - RETURN_IF_ABANDONED
|
| - if (oval.isEmpty()) {
|
| - return;
|
| - }
|
| -
|
| - if (strokeInfo.isDashed()) {
|
| - SkPath path;
|
| - path.setIsVolatile(true);
|
| - path.addOval(oval);
|
| - this->drawPath(rt, clip, paint, viewMatrix, path, strokeInfo);
|
| - return;
|
| - }
|
| -
|
| - AutoCheckFlush acf(this);
|
| - GrPipelineBuilder pipelineBuilder;
|
| - GrDrawTarget* target = this->prepareToDraw(&pipelineBuilder, rt, clip, &paint, &acf);
|
| - if (NULL == target) {
|
| - return;
|
| - }
|
| -
|
| - GR_CREATE_TRACE_MARKER("GrContext::drawOval", target);
|
| -
|
| - GrColor color = paint.getColor();
|
| - if (!fOvalRenderer->drawOval(target,
|
| - &pipelineBuilder,
|
| - color,
|
| - viewMatrix,
|
| - paint.isAntiAlias(),
|
| - oval,
|
| - strokeInfo)) {
|
| - SkPath path;
|
| - path.setIsVolatile(true);
|
| - path.addOval(oval);
|
| - this->internalDrawPath(target, &pipelineBuilder, viewMatrix, color, paint.isAntiAlias(),
|
| - path, strokeInfo);
|
| - }
|
| -}
|
| -
|
| -// Can 'path' be drawn as a pair of filled nested rectangles?
|
| -static bool is_nested_rects(GrDrawTarget* target,
|
| - GrPipelineBuilder* pipelineBuilder,
|
| - GrColor color,
|
| - const SkMatrix& viewMatrix,
|
| - const SkPath& path,
|
| - const SkStrokeRec& stroke,
|
| - SkRect rects[2]) {
|
| - SkASSERT(stroke.isFillStyle());
|
| -
|
| - if (path.isInverseFillType()) {
|
| - return false;
|
| - }
|
| -
|
| - // TODO: this restriction could be lifted if we were willing to apply
|
| - // the matrix to all the points individually rather than just to the rect
|
| - if (!viewMatrix.preservesAxisAlignment()) {
|
| - return false;
|
| - }
|
| -
|
| - SkPath::Direction dirs[2];
|
| - if (!path.isNestedFillRects(rects, dirs)) {
|
| - return false;
|
| - }
|
| -
|
| - if (SkPath::kWinding_FillType == path.getFillType() && dirs[0] == dirs[1]) {
|
| - // The two rects need to be wound opposite to each other
|
| - return false;
|
| - }
|
| -
|
| - // Right now, nested rects where the margin is not the same width
|
| - // all around do not render correctly
|
| - const SkScalar* outer = rects[0].asScalars();
|
| - const SkScalar* inner = rects[1].asScalars();
|
| -
|
| - bool allEq = true;
|
| -
|
| - SkScalar margin = SkScalarAbs(outer[0] - inner[0]);
|
| - bool allGoE1 = margin >= SK_Scalar1;
|
| -
|
| - for (int i = 1; i < 4; ++i) {
|
| - SkScalar temp = SkScalarAbs(outer[i] - inner[i]);
|
| - if (temp < SK_Scalar1) {
|
| - allGoE1 = false;
|
| - }
|
| - if (!SkScalarNearlyEqual(margin, temp)) {
|
| - allEq = false;
|
| - }
|
| - }
|
| -
|
| - return allEq || allGoE1;
|
| -}
|
| -
|
| -void GrContext::drawPath(GrRenderTarget* rt,
|
| - const GrClip& clip,
|
| - const GrPaint& paint,
|
| - const SkMatrix& viewMatrix,
|
| - const SkPath& path,
|
| - const GrStrokeInfo& strokeInfo) {
|
| - RETURN_IF_ABANDONED
|
| - if (path.isEmpty()) {
|
| - if (path.isInverseFillType()) {
|
| - this->drawPaint(rt, clip, paint, viewMatrix);
|
| - }
|
| - return;
|
| - }
|
| -
|
| - GrColor color = paint.getColor();
|
| -
|
| - // Note that internalDrawPath may sw-rasterize the path into a scratch texture.
|
| - // Scratch textures can be recycled after they are returned to the texture
|
| - // cache. This presents a potential hazard for buffered drawing. However,
|
| - // the writePixels that uploads to the scratch will perform a flush so we're
|
| - // OK.
|
| - AutoCheckFlush acf(this);
|
| - GrPipelineBuilder pipelineBuilder;
|
| - GrDrawTarget* target = this->prepareToDraw(&pipelineBuilder, rt, clip, &paint, &acf);
|
| - if (NULL == target) {
|
| - return;
|
| - }
|
| -
|
| - GR_CREATE_TRACE_MARKER1("GrContext::drawPath", target, "Is Convex", path.isConvex());
|
| -
|
| - if (!strokeInfo.isDashed()) {
|
| - bool useCoverageAA = paint.isAntiAlias() &&
|
| - !pipelineBuilder.getRenderTarget()->isMultisampled();
|
| -
|
| - if (useCoverageAA && strokeInfo.getWidth() < 0 && !path.isConvex()) {
|
| - // Concave AA paths are expensive - try to avoid them for special cases
|
| - SkRect rects[2];
|
| -
|
| - if (is_nested_rects(target, &pipelineBuilder, color, viewMatrix, path, strokeInfo,
|
| - rects)) {
|
| - fAARectRenderer->fillAANestedRects(target, &pipelineBuilder, color, viewMatrix,
|
| - rects);
|
| - return;
|
| - }
|
| - }
|
| - SkRect ovalRect;
|
| - bool isOval = path.isOval(&ovalRect);
|
| -
|
| - if (isOval && !path.isInverseFillType()) {
|
| - if (fOvalRenderer->drawOval(target,
|
| - &pipelineBuilder,
|
| - color,
|
| - viewMatrix,
|
| - paint.isAntiAlias(),
|
| - ovalRect,
|
| - strokeInfo)) {
|
| - return;
|
| - }
|
| - }
|
| - }
|
| - this->internalDrawPath(target, &pipelineBuilder, viewMatrix, color, paint.isAntiAlias(),
|
| - path, strokeInfo);
|
| -}
|
| -
|
| -void GrContext::internalDrawPath(GrDrawTarget* target,
|
| - GrPipelineBuilder* pipelineBuilder,
|
| - const SkMatrix& viewMatrix,
|
| - GrColor color,
|
| - bool useAA,
|
| - const SkPath& path,
|
| - const GrStrokeInfo& strokeInfo) {
|
| - RETURN_IF_ABANDONED
|
| - SkASSERT(!path.isEmpty());
|
| -
|
| - GR_CREATE_TRACE_MARKER("GrContext::internalDrawPath", target);
|
| -
|
| -
|
| - // An Assumption here is that path renderer would use some form of tweaking
|
| - // the src color (either the input alpha or in the frag shader) to implement
|
| - // aa. If we have some future driver-mojo path AA that can do the right
|
| - // thing WRT to the blend then we'll need some query on the PR.
|
| - bool useCoverageAA = useAA &&
|
| - !pipelineBuilder->getRenderTarget()->isMultisampled();
|
| -
|
| -
|
| - GrPathRendererChain::DrawType type =
|
| - useCoverageAA ? GrPathRendererChain::kColorAntiAlias_DrawType :
|
| - GrPathRendererChain::kColor_DrawType;
|
| -
|
| - const SkPath* pathPtr = &path;
|
| - SkTLazy<SkPath> tmpPath;
|
| - const GrStrokeInfo* strokeInfoPtr = &strokeInfo;
|
| -
|
| - // Try a 1st time without stroking the path and without allowing the SW renderer
|
| - GrPathRenderer* pr = this->getPathRenderer(target, pipelineBuilder, viewMatrix, *pathPtr,
|
| - *strokeInfoPtr, false, type);
|
| -
|
| - GrStrokeInfo dashlessStrokeInfo(strokeInfo, false);
|
| - if (NULL == pr && strokeInfo.isDashed()) {
|
| - // It didn't work above, so try again with dashed stroke converted to a dashless stroke.
|
| - if (!strokeInfo.applyDashToPath(tmpPath.init(), &dashlessStrokeInfo, *pathPtr)) {
|
| - return;
|
| - }
|
| - pathPtr = tmpPath.get();
|
| - if (pathPtr->isEmpty()) {
|
| - return;
|
| - }
|
| - strokeInfoPtr = &dashlessStrokeInfo;
|
| - pr = this->getPathRenderer(target, pipelineBuilder, viewMatrix, *pathPtr, *strokeInfoPtr,
|
| - false, type);
|
| - }
|
| -
|
| - if (NULL == pr) {
|
| - if (!GrPathRenderer::IsStrokeHairlineOrEquivalent(*strokeInfoPtr, viewMatrix, NULL) &&
|
| - !strokeInfoPtr->isFillStyle()) {
|
| - // It didn't work above, so try again with stroke converted to a fill.
|
| - if (!tmpPath.isValid()) {
|
| - tmpPath.init();
|
| - }
|
| - dashlessStrokeInfo.setResScale(SkScalarAbs(viewMatrix.getMaxScale()));
|
| - if (!dashlessStrokeInfo.applyToPath(tmpPath.get(), *pathPtr)) {
|
| - return;
|
| - }
|
| - pathPtr = tmpPath.get();
|
| - if (pathPtr->isEmpty()) {
|
| - return;
|
| - }
|
| - dashlessStrokeInfo.setFillStyle();
|
| - strokeInfoPtr = &dashlessStrokeInfo;
|
| - }
|
| -
|
| - // This time, allow SW renderer
|
| - pr = this->getPathRenderer(target, pipelineBuilder, viewMatrix, *pathPtr, *strokeInfoPtr,
|
| - true, type);
|
| - }
|
| -
|
| - if (NULL == pr) {
|
| -#ifdef SK_DEBUG
|
| - SkDebugf("Unable to find path renderer compatible with path.\n");
|
| -#endif
|
| - return;
|
| - }
|
| -
|
| - pr->drawPath(target, pipelineBuilder, color, viewMatrix, *pathPtr, *strokeInfoPtr, useCoverageAA);
|
| -}
|
| -
|
| ////////////////////////////////////////////////////////////////////////////////
|
|
|
| void GrContext::flush(int flagsBitfield) {
|
| - if (NULL == fDrawBuffer) {
|
| - return;
|
| - }
|
| + RETURN_IF_ABANDONED
|
|
|
| if (kDiscard_FlushBit & flagsBitfield) {
|
| - fDrawBuffer->reset();
|
| + fDrawingMgr.reset();
|
| } else {
|
| - fDrawBuffer->flush();
|
| + fDrawingMgr.flush();
|
| }
|
| fResourceCache->notifyFlushOccurred();
|
| fFlushToReduceCacheSize = false;
|
| @@ -1412,7 +360,7 @@ bool GrContext::writeSurfacePixels(GrSurface* surface,
|
|
|
| // If we didn't do a direct texture write then we upload the pixels to a texture and draw.
|
| GrRenderTarget* renderTarget = surface->asRenderTarget();
|
| - if (NULL == renderTarget) {
|
| + if (!renderTarget) {
|
| return false;
|
| }
|
|
|
| @@ -1451,7 +399,7 @@ bool GrContext::writeSurfacePixels(GrSurface* surface,
|
| }
|
| fp.reset(this->createUPMToPMEffect(texture, swapRAndB, textureMatrix));
|
| // handle the unpremul step on the CPU if we couldn't create an effect to do it.
|
| - if (NULL == fp) {
|
| + if (!fp) {
|
| size_t tmpRowBytes = 4 * width;
|
| tmpPixels.reset(width * height);
|
| if (!sw_convert_to_premul(srcConfig, width, height, rowBytes, buffer, tmpRowBytes,
|
| @@ -1462,7 +410,7 @@ bool GrContext::writeSurfacePixels(GrSurface* surface,
|
| buffer = tmpPixels.get();
|
| }
|
| }
|
| - if (NULL == fp) {
|
| + if (!fp) {
|
| fp.reset(GrConfigConversionEffect::Create(texture,
|
| swapRAndB,
|
| GrConfigConversionEffect::kNone_PMConversion,
|
| @@ -1483,25 +431,18 @@ bool GrContext::writeSurfacePixels(GrSurface* surface,
|
| SkMatrix matrix;
|
| matrix.setTranslate(SkIntToScalar(left), SkIntToScalar(top));
|
|
|
| - // This function can be called in the midst of drawing another object (e.g., when uploading a
|
| - // SW-rasterized clip while issuing a draw). So we push the current geometry state before
|
| - // drawing a rect to the render target.
|
| - // The bracket ensures we pop the stack if we wind up flushing below.
|
| - {
|
| - GrDrawTarget* drawTarget = this->prepareToDraw();
|
| - if (!drawTarget) {
|
| - return false;
|
| - }
|
| -
|
| - GrPipelineBuilder pipelineBuilder;
|
| - pipelineBuilder.addColorProcessor(fp);
|
| - pipelineBuilder.setRenderTarget(renderTarget);
|
| - drawTarget->drawSimpleRect(&pipelineBuilder,
|
| - GrColor_WHITE,
|
| - matrix,
|
| - SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height)));
|
| + GrDrawContext* drawContext = this->drawContext();
|
| + if (!drawContext) {
|
| + return false;
|
| }
|
|
|
| + GrPaint paint;
|
| + paint.addColorProcessor(fp);
|
| +
|
| + SkRect rect = SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height));
|
| +
|
| + drawContext->drawRect(renderTarget, GrClip::WideOpen(), paint, matrix, rect, NULL);
|
| +
|
| if (kFlushWrites_PixelOp & pixelOpsFlags) {
|
| this->flushSurfaceWrites(surface);
|
| }
|
| @@ -1614,16 +555,19 @@ bool GrContext::readRenderTargetPixels(GrRenderTarget* target,
|
| // clear to the caller that a draw operation (i.e., drawSimpleRect)
|
| // can be invoked in this method
|
| {
|
| - GrPipelineBuilder pipelineBuilder;
|
| - SkASSERT(fp);
|
| - pipelineBuilder.addColorProcessor(fp);
|
| + GrDrawContext* drawContext = this->drawContext();
|
| + if (!drawContext) {
|
| + return false;
|
| + }
|
| +
|
| + GrPaint paint;
|
| + paint.addColorProcessor(fp);
|
|
|
| - pipelineBuilder.setRenderTarget(tempTexture->asRenderTarget());
|
| SkRect rect = SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height));
|
| - fDrawBuffer->drawSimpleRect(&pipelineBuilder,
|
| - GrColor_WHITE,
|
| - SkMatrix::I(),
|
| - rect);
|
| +
|
| + drawContext->drawRect(tempTexture->asRenderTarget(), GrClip::WideOpen(), paint,
|
| + SkMatrix::I(), rect, NULL);
|
| +
|
| // we want to read back from the scratch's origin
|
| left = 0;
|
| top = 0;
|
| @@ -1673,22 +617,10 @@ void GrContext::prepareSurfaceForExternalRead(GrSurface* surface) {
|
| }
|
| }
|
|
|
| -void GrContext::discardRenderTarget(GrRenderTarget* renderTarget) {
|
| - RETURN_IF_ABANDONED
|
| - SkASSERT(renderTarget);
|
| - ASSERT_OWNED_RESOURCE(renderTarget);
|
| - AutoCheckFlush acf(this);
|
| - GrDrawTarget* target = this->prepareToDraw();
|
| - if (NULL == target) {
|
| - return;
|
| - }
|
| - target->discard(renderTarget);
|
| -}
|
| -
|
| void GrContext::copySurface(GrSurface* dst, GrSurface* src, const SkIRect& srcRect,
|
| const SkIPoint& dstPoint, uint32_t pixelOpsFlags) {
|
| RETURN_IF_ABANDONED
|
| - if (NULL == src || NULL == dst) {
|
| + if (!src || !dst) {
|
| return;
|
| }
|
| ASSERT_OWNED_RESOURCE(src);
|
| @@ -1696,12 +628,16 @@ void GrContext::copySurface(GrSurface* dst, GrSurface* src, const SkIRect& srcRe
|
|
|
| // Since we're going to the draw target and not GPU, no need to check kNoFlush
|
| // here.
|
| + if (!dst->asRenderTarget()) {
|
| + return;
|
| + }
|
|
|
| - GrDrawTarget* target = this->prepareToDraw();
|
| - if (NULL == target) {
|
| + GrDrawContext* drawContext = this->drawContext();
|
| + if (!drawContext) {
|
| return;
|
| }
|
| - target->copySurface(dst, src, srcRect, dstPoint);
|
| +
|
| + drawContext->copySurface(dst->asRenderTarget(), src, srcRect, dstPoint);
|
|
|
| if (kFlushWrites_PixelOp & pixelOpsFlags) {
|
| this->flush();
|
| @@ -1715,28 +651,6 @@ void GrContext::flushSurfaceWrites(GrSurface* surface) {
|
| }
|
| }
|
|
|
| -GrDrawTarget* GrContext::prepareToDraw(GrPipelineBuilder* pipelineBuilder,
|
| - GrRenderTarget* rt,
|
| - const GrClip& clip,
|
| - const GrPaint* paint,
|
| - const AutoCheckFlush* acf) {
|
| - if (NULL == fGpu || NULL == fDrawBuffer) {
|
| - return NULL;
|
| - }
|
| -
|
| - ASSERT_OWNED_RESOURCE(rt);
|
| - SkASSERT(rt && paint && acf);
|
| - pipelineBuilder->setFromPaint(*paint, rt, clip);
|
| - return fDrawBuffer;
|
| -}
|
| -
|
| -GrDrawTarget* GrContext::prepareToDraw() {
|
| - if (NULL == fGpu) {
|
| - return NULL;
|
| - }
|
| - return fDrawBuffer;
|
| -}
|
| -
|
| /*
|
| * This method finds a path renderer that can draw the specified path on
|
| * the provided target.
|
| @@ -1752,7 +666,7 @@ GrPathRenderer* GrContext::getPathRenderer(const GrDrawTarget* target,
|
| GrPathRendererChain::DrawType drawType,
|
| GrPathRendererChain::StencilSupport* stencilSupport) {
|
|
|
| - if (NULL == fPathRendererChain) {
|
| + if (!fPathRendererChain) {
|
| fPathRendererChain = SkNEW_ARGS(GrPathRendererChain, (this));
|
| }
|
|
|
| @@ -1764,8 +678,8 @@ GrPathRenderer* GrContext::getPathRenderer(const GrDrawTarget* target,
|
| drawType,
|
| stencilSupport);
|
|
|
| - if (NULL == pr && allowSW) {
|
| - if (NULL == fSoftwarePathRenderer) {
|
| + if (!pr && allowSW) {
|
| + if (!fSoftwarePathRenderer) {
|
| fSoftwarePathRenderer = SkNEW_ARGS(GrSoftwarePathRenderer, (this));
|
| }
|
| pr = fSoftwarePathRenderer;
|
| @@ -1796,10 +710,6 @@ int GrContext::getRecommendedSampleCount(GrPixelConfig config,
|
| chosenSampleCount : 0;
|
| }
|
|
|
| -GrDrawTarget* GrContext::getTextTarget() {
|
| - return this->prepareToDraw();
|
| -}
|
| -
|
| namespace {
|
| void test_pm_conversions(GrContext* ctx, int* pmToUPMValue, int* upmToPMValue) {
|
| GrConfigConversionEffect::PMConversion pmToUPM;
|
| @@ -1861,141 +771,9 @@ void GrContext::setResourceCacheLimits(int maxTextures, size_t maxTextureBytes)
|
|
|
| void GrContext::addGpuTraceMarker(const GrGpuTraceMarker* marker) {
|
| fGpu->addGpuTraceMarker(marker);
|
| - if (fDrawBuffer) {
|
| - fDrawBuffer->addGpuTraceMarker(marker);
|
| - }
|
| }
|
|
|
| void GrContext::removeGpuTraceMarker(const GrGpuTraceMarker* marker) {
|
| fGpu->removeGpuTraceMarker(marker);
|
| - if (fDrawBuffer) {
|
| - fDrawBuffer->removeGpuTraceMarker(marker);
|
| - }
|
| -}
|
| -
|
| -///////////////////////////////////////////////////////////////////////////////////////////////////
|
| -
|
| -#ifdef GR_TEST_UTILS
|
| -
|
| -BATCH_TEST_DEFINE(StrokeRectBatch) {
|
| - StrokeRectBatch::Geometry geometry;
|
| - geometry.fViewMatrix = GrTest::TestMatrix(random);
|
| - geometry.fColor = GrRandomColor(random);
|
| - geometry.fRect = GrTest::TestRect(random);
|
| - geometry.fStrokeWidth = random->nextBool() ? 0.0f : 1.0f;
|
| -
|
| - return StrokeRectBatch::Create(geometry, random->nextBool());
|
| -}
|
| -
|
| -static uint32_t seed_vertices(GrPrimitiveType type) {
|
| - switch (type) {
|
| - case kTriangles_GrPrimitiveType:
|
| - case kTriangleStrip_GrPrimitiveType:
|
| - case kTriangleFan_GrPrimitiveType:
|
| - return 3;
|
| - case kPoints_GrPrimitiveType:
|
| - return 1;
|
| - case kLines_GrPrimitiveType:
|
| - case kLineStrip_GrPrimitiveType:
|
| - return 2;
|
| - }
|
| - SkFAIL("Incomplete switch\n");
|
| - return 0;
|
| -}
|
| -
|
| -static uint32_t primitive_vertices(GrPrimitiveType type) {
|
| - switch (type) {
|
| - case kTriangles_GrPrimitiveType:
|
| - return 3;
|
| - case kLines_GrPrimitiveType:
|
| - return 2;
|
| - case kTriangleStrip_GrPrimitiveType:
|
| - case kTriangleFan_GrPrimitiveType:
|
| - case kPoints_GrPrimitiveType:
|
| - case kLineStrip_GrPrimitiveType:
|
| - return 1;
|
| - }
|
| - SkFAIL("Incomplete switch\n");
|
| - return 0;
|
| -}
|
| -
|
| -static SkPoint random_point(SkRandom* random, SkScalar min, SkScalar max) {
|
| - SkPoint p;
|
| - p.fX = random->nextRangeScalar(min, max);
|
| - p.fY = random->nextRangeScalar(min, max);
|
| - return p;
|
| -}
|
| -
|
| -static void randomize_params(size_t count, size_t maxVertex, SkScalar min, SkScalar max,
|
| - SkRandom* random,
|
| - SkTArray<SkPoint>* positions,
|
| - SkTArray<SkPoint>* texCoords, bool hasTexCoords,
|
| - SkTArray<GrColor>* colors, bool hasColors,
|
| - SkTArray<uint16_t>* indices, bool hasIndices) {
|
| - for (uint32_t v = 0; v < count; v++) {
|
| - positions->push_back(random_point(random, min, max));
|
| - if (hasTexCoords) {
|
| - texCoords->push_back(random_point(random, min, max));
|
| - }
|
| - if (hasColors) {
|
| - colors->push_back(GrRandomColor(random));
|
| - }
|
| - if (hasIndices) {
|
| - SkASSERT(maxVertex <= SK_MaxU16);
|
| - indices->push_back(random->nextULessThan((uint16_t)maxVertex));
|
| - }
|
| - }
|
| -}
|
| -
|
| -BATCH_TEST_DEFINE(VerticesBatch) {
|
| - GrPrimitiveType type = GrPrimitiveType(random->nextULessThan(kLast_GrPrimitiveType + 1));
|
| - uint32_t primitiveCount = random->nextRangeU(1, 100);
|
| -
|
| - // TODO make 'sensible' indexbuffers
|
| - SkTArray<SkPoint> positions;
|
| - SkTArray<SkPoint> texCoords;
|
| - SkTArray<GrColor> colors;
|
| - SkTArray<uint16_t> indices;
|
| -
|
| - bool hasTexCoords = random->nextBool();
|
| - bool hasIndices = random->nextBool();
|
| - bool hasColors = random->nextBool();
|
| -
|
| - uint32_t vertexCount = seed_vertices(type) + (primitiveCount - 1) * primitive_vertices(type);
|
| -
|
| - static const SkScalar kMinVertExtent = -100.f;
|
| - static const SkScalar kMaxVertExtent = 100.f;
|
| - randomize_params(seed_vertices(type), vertexCount, kMinVertExtent, kMaxVertExtent,
|
| - random,
|
| - &positions,
|
| - &texCoords, hasTexCoords,
|
| - &colors, hasColors,
|
| - &indices, hasIndices);
|
| -
|
| - for (uint32_t i = 1; i < primitiveCount; i++) {
|
| - randomize_params(primitive_vertices(type), vertexCount, kMinVertExtent, kMaxVertExtent,
|
| - random,
|
| - &positions,
|
| - &texCoords, hasTexCoords,
|
| - &colors, hasColors,
|
| - &indices, hasIndices);
|
| - }
|
| -
|
| - SkMatrix viewMatrix = GrTest::TestMatrix(random);
|
| - SkRect bounds;
|
| - SkDEBUGCODE(bool result = ) bounds.setBoundsCheck(positions.begin(), vertexCount);
|
| - SkASSERT(result);
|
| -
|
| - viewMatrix.mapRect(&bounds);
|
| -
|
| - DrawVerticesBatch::Geometry geometry;
|
| - geometry.fColor = GrRandomColor(random);
|
| - return DrawVerticesBatch::Create(geometry, type, viewMatrix,
|
| - positions.begin(), vertexCount,
|
| - indices.begin(), hasIndices ? vertexCount : 0,
|
| - colors.begin(),
|
| - texCoords.begin(),
|
| - bounds);
|
| }
|
|
|
| -#endif
|
|
|