#if SK_SUPPORT_GPU
#include "GrContext.h"
+#include "GrDrawContext.h"
#include "SkColorPriv.h"
#include "effects/GrPorterDuffXferProcessor.h"
#include "effects/GrSimpleTextureEffect.h"
void onDraw(SkCanvas* canvas) override {
GrRenderTarget* target = canvas->internal_private_accessTopLayerRenderTarget();
GrContext* ctx = canvas->getGrContext();
- if (ctx && target) {
+ GrDrawContext* drawContext = ctx ? ctx->drawContext() : NULL;
+ if (drawContext && target) {
SkAutoTArray<SkPMColor> gTextureData((2 * S) * (2 * S));
static const int stride = 2 * S;
static const SkPMColor gray = SkPackARGB32(0x40, 0x40, 0x40, 0x40);
tm.postIDiv(2*S, 2*S);
paint.addColorTextureProcessor(texture, tm);
- ctx->drawRect(target, clip, paint, vm, SkRect::MakeWH(2*S, 2*S));
+ drawContext->drawRect(target, clip, paint, vm, SkRect::MakeWH(2*S, 2*S));
// now update the lower right of the texture in first pass
// or upper right in second pass
texture->writePixels(S, (i ? 0 : S), S, S,
texture->config(), gTextureData.get(),
4 * stride);
- ctx->drawRect(target, clip, paint, vm, SkRect::MakeWH(2*S, 2*S));
+ drawContext->drawRect(target, clip, paint, vm, SkRect::MakeWH(2*S, 2*S));
}
} else {
this->drawGpuOnlyMessage(canvas);
'<(skia_include_path)/gpu/GrContextOptions.h',
'<(skia_include_path)/gpu/GrContext.h',
'<(skia_include_path)/gpu/GrCoordTransform.h',
+ '<(skia_include_path)/gpu/GrDrawContext.h',
'<(skia_include_path)/gpu/GrFragmentProcessor.h',
'<(skia_include_path)/gpu/GrFragmentStage.h',
'<(skia_include_path)/gpu/GrGpuResource.h',
'<(skia_src_path)/gpu/GrDefaultGeoProcFactory.h',
'<(skia_src_path)/gpu/GrDefaultPathRenderer.cpp',
'<(skia_src_path)/gpu/GrDefaultPathRenderer.h',
+ '<(skia_src_path)/gpu/GrDrawContext.cpp',
'<(skia_src_path)/gpu/GrDrawTarget.cpp',
'<(skia_src_path)/gpu/GrDrawTarget.h',
'<(skia_src_path)/gpu/GrFontAtlasSizes.h',
class GrAARectRenderer;
class GrBatchFontCache;
struct GrContextOptions;
+class GrDrawContext;
class GrDrawTarget;
class GrFragmentProcessor;
class GrGpu;
/// Texture and Render Target Queries
/**
+ * Are shader derivatives supported?
+ */
+ bool shaderDerivativeSupport() const;
+
+ /**
* Can the provided configuration act as a texture?
*/
bool isConfigTexturable(GrPixelConfig) const;
*/
int getRecommendedSampleCount(GrPixelConfig config, SkScalar dpi) const;
- ///////////////////////////////////////////////////////////////////////////
- // Draws
-
/**
- * Clear the entire or rect of the render target, ignoring any clips.
- * @param rect the rect to clear or the whole thing if rect is NULL.
- * @param color the color to clear to.
- * @param canIgnoreRect allows partial clears to be converted to whole
- * clears on platforms for which that is cheap
- * @param target The render target to clear.
- */
- void clear(const SkIRect* rect, GrColor color, bool canIgnoreRect, GrRenderTarget* target);
-
- /**
- * Draw everywhere (respecting the clip) with the paint.
- */
- void drawPaint(GrRenderTarget*, const GrClip&, const GrPaint&, const SkMatrix& viewMatrix);
-
- /**
- * Draw the rect using a paint.
- * @param paint describes how to color pixels.
- * @param viewMatrix transformation matrix
- * @param strokeInfo the stroke information (width, join, cap), and.
- * the dash information (intervals, count, phase).
- * If strokeInfo == NULL, then the rect is filled.
- * Otherwise, if stroke width == 0, then the stroke
- * is always a single pixel thick, else the rect is
- * mitered/beveled stroked based on stroke width.
- * The rects coords are used to access the paint (through texture matrix)
- */
- void drawRect(GrRenderTarget*,
- const GrClip&,
- const GrPaint& paint,
- const SkMatrix& viewMatrix,
- const SkRect&,
- const GrStrokeInfo* strokeInfo = NULL);
-
- /**
- * Maps a rectangle of shader coordinates to a rectangle and draws that rectangle
- *
- * @param paint describes how to color pixels.
- * @param viewMatrix transformation matrix which applies to rectToDraw
- * @param rectToDraw the rectangle to draw
- * @param localRect the rectangle of shader coordinates applied to rectToDraw
- * @param localMatrix an optional matrix to transform the shader coordinates before applying
- * to rectToDraw
- */
- void drawNonAARectToRect(GrRenderTarget*,
- const GrClip&,
- const GrPaint& paint,
- const SkMatrix& viewMatrix,
- const SkRect& rectToDraw,
- const SkRect& localRect,
- const SkMatrix* localMatrix = NULL);
-
- /**
- * Draws a non-AA rect with paint and a localMatrix
- */
- void drawNonAARectWithLocalMatrix(GrRenderTarget* rt,
- const GrClip& clip,
- const GrPaint& paint,
- const SkMatrix& viewMatrix,
- const SkRect& rect,
- const SkMatrix& localMatrix) {
- this->drawNonAARectToRect(rt, clip, paint, viewMatrix, rect, rect, &localMatrix);
- }
-
- /**
- * Draw a roundrect using a paint.
- *
- * @param paint describes how to color pixels.
- * @param viewMatrix transformation matrix
- * @param rrect the roundrect to draw
- * @param strokeInfo the stroke information (width, join, cap) and
- * the dash information (intervals, count, phase).
- */
- void drawRRect(GrRenderTarget*,
- const GrClip&,
- const GrPaint&,
- const SkMatrix& viewMatrix,
- const SkRRect& rrect,
- const GrStrokeInfo&);
-
- /**
- * Shortcut for drawing an SkPath consisting of nested rrects using a paint.
- * Does not support stroking. The result is undefined if outer does not contain
- * inner.
+ * Returns a helper object to orchestrate draws.
*
- * @param paint describes how to color pixels.
- * @param viewMatrix transformation matrix
- * @param outer the outer roundrect
- * @param inner the inner roundrect
- */
- void drawDRRect(GrRenderTarget*,
- const GrClip&,
- const GrPaint&,
- const SkMatrix& viewMatrix,
- const SkRRect& outer,
- const SkRRect& inner);
-
-
- /**
- * Draws a path.
- *
- * @param paint describes how to color pixels.
- * @param viewMatrix transformation matrix
- * @param path the path to draw
- * @param strokeInfo the stroke information (width, join, cap) and
- * the dash information (intervals, count, phase).
+ * @return a draw context
*/
- void drawPath(GrRenderTarget*,
- const GrClip&,
- const GrPaint&,
- const SkMatrix& viewMatrix,
- const SkPath&,
- const GrStrokeInfo&);
-
- /**
- * Draws vertices with a paint.
- *
- * @param paint describes how to color pixels.
- * @param viewMatrix transformation matrix
- * @param primitiveType primitives type to draw.
- * @param vertexCount number of vertices.
- * @param positions array of vertex positions, required.
- * @param texCoords optional array of texture coordinates used
- * to access the paint.
- * @param colors optional array of per-vertex colors, supercedes
- * the paint's color field.
- * @param indices optional array of indices. If NULL vertices
- * are drawn non-indexed.
- * @param indexCount if indices is non-null then this is the
- * number of indices.
- */
- void drawVertices(GrRenderTarget*,
- const GrClip&,
- const GrPaint& paint,
- const SkMatrix& viewMatrix,
- GrPrimitiveType primitiveType,
- int vertexCount,
- const SkPoint positions[],
- const SkPoint texs[],
- const GrColor colors[],
- const uint16_t indices[],
- int indexCount);
-
- /**
- * Draws an oval.
- *
- * @param paint describes how to color pixels.
- * @param viewMatrix transformation matrix
- * @param oval the bounding rect of the oval.
- * @param strokeInfo the stroke information (width, join, cap) and
- * the dash information (intervals, count, phase).
- */
- void drawOval(GrRenderTarget*,
- const GrClip&,
- const GrPaint& paint,
- const SkMatrix& viewMatrix,
- const SkRect& oval,
- const GrStrokeInfo& strokeInfo);
+ GrDrawContext* drawContext() {
+ return fDrawingMgr.drawContext();
+ }
///////////////////////////////////////////////////////////////////////////
// Misc.
*/
void flush(int flagsBitfield = 0);
+ void flushIfNecessary() {
+ if (fFlushToReduceCacheSize) {
+ this->flush();
+ }
+ }
+
/**
* These flags can be used with the read/write pixels functions below.
*/
void prepareSurfaceForExternalRead(GrSurface*);
/**
- * Provides a perfomance hint that the render target's contents are allowed
- * to become undefined.
- */
- void discardRenderTarget(GrRenderTarget*);
-
- /**
* An ID associated with this context, guaranteed to be unique.
*/
uint32_t uniqueID() { return fUniqueID; }
GrBatchFontCache* getBatchFontCache() { return fBatchFontCache; }
GrLayerCache* getLayerCache() { return fLayerCache.get(); }
GrTextBlobCache* getTextBlobCache() { return fTextBlobCache; }
- GrDrawTarget* getTextTarget();
- GrAARectRenderer* getAARectRenderer() { return fAARectRenderer; }
+ bool abandoned() const { return fDrawingMgr.abandoned(); }
GrResourceProvider* resourceProvider() { return fResourceProvider; }
const GrResourceProvider* resourceProvider() const { return fResourceProvider; }
GrResourceCache* getResourceCache() { return fResourceCache; }
GrPathRendererChain* fPathRendererChain;
GrSoftwarePathRenderer* fSoftwarePathRenderer;
- GrDrawTarget* fDrawBuffer;
-
// Set by OverbudgetCB() to request that GrContext flush before exiting a draw.
bool fFlushToReduceCacheSize;
- GrAARectRenderer* fAARectRenderer;
- GrOvalRenderer* fOvalRenderer;
-
bool fDidTestPMConversions;
int fPMToUPMConversion;
int fUPMToPMConversion;
GrContext(); // init must be called after the constructor.
bool init(GrBackend, GrBackendContext, const GrContextOptions& options);
+
+ // Currently the DrawingMgr just wraps the single GrDrawTarget in a single
+ // GrDrawContext and hands it out. In the future this class will allocate
+ // a new GrDrawContext for each GrRenderTarget/GrDrawTarget and manage
+ // the DAG.
+ class DrawingMgr {
+ public:
+ DrawingMgr()
+ : fDrawTarget(NULL)
+ , fDrawContext(NULL) {
+ }
+
+ ~DrawingMgr();
+
+ void init(GrContext* context);
+
+ void abandon();
+ bool abandoned() const { return NULL == fDrawTarget; }
+
+ void purgeResources();
+ void reset();
+ void flush();
+
+ // Callers should take a ref if they rely on the GrDrawContext sticking around.
+ // NULL will be returned if the context has been abandoned.
+ GrDrawContext* drawContext();
+
+ private:
+ friend class GrContext; // for access to fDrawTarget for testing
+
+ GrDrawTarget* fDrawTarget;
+
+ GrDrawContext* fDrawContext;
+ };
+
+ DrawingMgr fDrawingMgr;
+
void initMockContext();
void initCommon();
- class AutoCheckFlush;
- // Sets the paint and returns the target to draw into.
- GrDrawTarget* prepareToDraw(GrPipelineBuilder*,
- GrRenderTarget* rt,
- const GrClip&,
- const GrPaint* paint,
- const AutoCheckFlush*);
-
- // A simpler version of the above which just returns the draw target. Clip is *NOT* set
- GrDrawTarget* prepareToDraw();
-
- void internalDrawPath(GrDrawTarget*,
- GrPipelineBuilder*,
- const SkMatrix& viewMatrix,
- GrColor,
- bool useAA,
- const SkPath&,
- const GrStrokeInfo&);
-
/**
* Creates a new text rendering context that is optimal for the
* render target and the context. Caller assumes the ownership
--- /dev/null
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrDrawContext_DEFINED
+#define GrDrawContext_DEFINED
+
+#include "GrColor.h"
+#include "SkRefCnt.h"
+
+class GrBatch;
+class GrClip;
+class GrContext;
+class GrDrawTarget;
+class GrPaint;
+class GrPathProcessor;
+class GrPathRange;
+class GrPipelineBuilder;
+class GrRenderTarget;
+class GrStrokeInfo;
+class GrSurface;
+struct SkIPoint;
+struct SkIRect;
+class SkMatrix;
+class SkPath;
+struct SkPoint;
+struct SkRect;
+class SkRRect;
+
+
+/*
+ * A helper object to orchestrate draws
+ */
+class SK_API GrDrawContext : public SkRefCnt {
+public:
+ SK_DECLARE_INST_COUNT(GrDrawContext)
+
+ void copySurface(GrRenderTarget* dst, GrSurface* src,
+ const SkIRect& srcRect, const SkIPoint& dstPoint);
+
+ // drawText and drawPaths are thanks to the GrAtlasTextContext and the
+ // GrStencilAndCoverTextContext respectively
+ // TODO: remove these two
+ void drawText(GrPipelineBuilder* pipelineBuilder, GrBatch* batch);
+
+ void drawPaths(GrPipelineBuilder* pipelineBuilder,
+ const GrPathProcessor* pathProc,
+ const GrPathRange* pathRange,
+ const void* indices,
+ int /*GrDrawTarget::PathIndexType*/ indexType,
+ const float transformValues[],
+ int /*GrDrawTarget::PathTransformType*/ transformType,
+ int count,
+ int /*GrPathRendering::FillType*/ fill);
+
+ /**
+ * Provides a perfomance hint that the render target's contents are allowed
+ * to become undefined.
+ */
+ void discard(GrRenderTarget*);
+
+ /**
+ * Clear the entire or rect of the render target, ignoring any clips.
+ * @param target The render target to clear.
+ * @param rect the rect to clear or the whole thing if rect is NULL.
+ * @param color the color to clear to.
+ * @param canIgnoreRect allows partial clears to be converted to whole
+ * clears on platforms for which that is cheap
+ */
+ void clear(GrRenderTarget*, const SkIRect* rect, GrColor color, bool canIgnoreRect);
+
+ /**
+ * Draw everywhere (respecting the clip) with the paint.
+ */
+ void drawPaint(GrRenderTarget*, const GrClip&, const GrPaint&, const SkMatrix& viewMatrix);
+
+ /**
+ * Draw the rect using a paint.
+ * @param paint describes how to color pixels.
+ * @param viewMatrix transformation matrix
+ * @param strokeInfo the stroke information (width, join, cap), and.
+ * the dash information (intervals, count, phase).
+ * If strokeInfo == NULL, then the rect is filled.
+ * Otherwise, if stroke width == 0, then the stroke
+ * is always a single pixel thick, else the rect is
+ * mitered/beveled stroked based on stroke width.
+ * The rects coords are used to access the paint (through texture matrix)
+ */
+ void drawRect(GrRenderTarget*,
+ const GrClip&,
+ const GrPaint& paint,
+ const SkMatrix& viewMatrix,
+ const SkRect&,
+ const GrStrokeInfo* strokeInfo = NULL);
+
+ /**
+ * Maps a rectangle of shader coordinates to a rectangle and draws that rectangle
+ *
+ * @param paint describes how to color pixels.
+ * @param viewMatrix transformation matrix which applies to rectToDraw
+ * @param rectToDraw the rectangle to draw
+ * @param localRect the rectangle of shader coordinates applied to rectToDraw
+ * @param localMatrix an optional matrix to transform the shader coordinates before applying
+ * to rectToDraw
+ */
+ void drawNonAARectToRect(GrRenderTarget*,
+ const GrClip&,
+ const GrPaint& paint,
+ const SkMatrix& viewMatrix,
+ const SkRect& rectToDraw,
+ const SkRect& localRect,
+ const SkMatrix* localMatrix = NULL);
+
+ /**
+ * Draws a non-AA rect with paint and a localMatrix
+ */
+ void drawNonAARectWithLocalMatrix(GrRenderTarget* rt,
+ const GrClip& clip,
+ const GrPaint& paint,
+ const SkMatrix& viewMatrix,
+ const SkRect& rect,
+ const SkMatrix& localMatrix) {
+ this->drawNonAARectToRect(rt, clip, paint, viewMatrix, rect, rect, &localMatrix);
+ }
+
+ /**
+ * Draw a roundrect using a paint.
+ *
+ * @param paint describes how to color pixels.
+ * @param viewMatrix transformation matrix
+ * @param rrect the roundrect to draw
+ * @param strokeInfo the stroke information (width, join, cap) and
+ * the dash information (intervals, count, phase).
+ */
+ void drawRRect(GrRenderTarget*,
+ const GrClip&,
+ const GrPaint&,
+ const SkMatrix& viewMatrix,
+ const SkRRect& rrect,
+ const GrStrokeInfo&);
+
+ /**
+ * Shortcut for drawing an SkPath consisting of nested rrects using a paint.
+ * Does not support stroking. The result is undefined if outer does not contain
+ * inner.
+ *
+ * @param paint describes how to color pixels.
+ * @param viewMatrix transformation matrix
+ * @param outer the outer roundrect
+ * @param inner the inner roundrect
+ */
+ void drawDRRect(GrRenderTarget*,
+ const GrClip&,
+ const GrPaint&,
+ const SkMatrix& viewMatrix,
+ const SkRRect& outer,
+ const SkRRect& inner);
+
+
+ /**
+ * Draws a path.
+ *
+ * @param paint describes how to color pixels.
+ * @param viewMatrix transformation matrix
+ * @param path the path to draw
+ * @param strokeInfo the stroke information (width, join, cap) and
+ * the dash information (intervals, count, phase).
+ */
+ void drawPath(GrRenderTarget*,
+ const GrClip&,
+ const GrPaint&,
+ const SkMatrix& viewMatrix,
+ const SkPath&,
+ const GrStrokeInfo&);
+
+ /**
+ * Draws vertices with a paint.
+ *
+ * @param paint describes how to color pixels.
+ * @param viewMatrix transformation matrix
+ * @param primitiveType primitives type to draw.
+ * @param vertexCount number of vertices.
+ * @param positions array of vertex positions, required.
+ * @param texCoords optional array of texture coordinates used
+ * to access the paint.
+ * @param colors optional array of per-vertex colors, supercedes
+ * the paint's color field.
+ * @param indices optional array of indices. If NULL vertices
+ * are drawn non-indexed.
+ * @param indexCount if indices is non-null then this is the
+ * number of indices.
+ */
+ void drawVertices(GrRenderTarget*,
+ const GrClip&,
+ const GrPaint& paint,
+ const SkMatrix& viewMatrix,
+ GrPrimitiveType primitiveType,
+ int vertexCount,
+ const SkPoint positions[],
+ const SkPoint texs[],
+ const GrColor colors[],
+ const uint16_t indices[],
+ int indexCount);
+
+ /**
+ * Draws an oval.
+ *
+ * @param paint describes how to color pixels.
+ * @param viewMatrix transformation matrix
+ * @param oval the bounding rect of the oval.
+ * @param strokeInfo the stroke information (width, join, cap) and
+ * the dash information (intervals, count, phase).
+ */
+ void drawOval(GrRenderTarget*,
+ const GrClip&,
+ const GrPaint& paint,
+ const SkMatrix& viewMatrix,
+ const SkRect& oval,
+ const GrStrokeInfo& strokeInfo);
+
+
+private:
+ friend class GrContext; // for ctor
+
+ GrDrawContext(GrContext* context, GrDrawTarget* drawTarget);
+
+ // Sets the paint. Returns true on success; false on failure.
+ bool prepareToDraw(GrPipelineBuilder*,
+ GrRenderTarget* rt,
+ const GrClip&,
+ const GrPaint* paint);
+
+ // A simpler version of the above which just returns true on success; false on failure.
+ // Clip is *NOT* set
+ bool prepareToDraw(GrRenderTarget* rt);
+
+ void internalDrawPath(GrDrawTarget*,
+ GrPipelineBuilder*,
+ const SkMatrix& viewMatrix,
+ GrColor,
+ bool useAA,
+ const SkPath&,
+ const GrStrokeInfo&);
+
+ GrContext* fContext; // owning context -> no ref
+ SkAutoTUnref<GrDrawTarget> fDrawTarget;
+};
+
+#endif
#include "SkValidationUtils.h"
#if SK_SUPPORT_GPU
#include "GrContext.h"
+#include "GrDrawContext.h"
#include "SkGrPixelRef.h"
#include "SkGr.h"
#endif
SkASSERT(fp);
GrPaint paint;
paint.addColorProcessor(fp)->unref();
- context->drawNonAARectToRect(dst->asRenderTarget(), clip, paint, SkMatrix::I(), dstRect,
- srcRect);
- WrapTexture(dst, bounds.width(), bounds.height(), result);
- return true;
+ GrDrawContext* drawContext = context->drawContext();
+ if (drawContext) {
+ drawContext->drawNonAARectToRect(dst->asRenderTarget(), clip, paint, SkMatrix::I(),
+ dstRect, srcRect);
+
+ WrapTexture(dst, bounds.width(), bounds.height(), result);
+ return true;
+ }
}
#endif
return false;
#include "SkReadBuffer.h"
#include "SkWriteBuffer.h"
#include "SkRegion.h"
+#if SK_SUPPORT_GPU
+#include "GrDrawContext.h"
+#endif
class SK_API SkAlphaThresholdFilterImpl : public SkImageFilter {
public:
return false;
}
- {
+ GrDrawContext* drawContext = context->drawContext();
+ if (drawContext) {
GrPaint grPaint;
grPaint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode);
SkRegion::Iterator iter(fRegion);
- context->clear(NULL, 0x0, true, maskTexture->asRenderTarget());
+ drawContext->clear(maskTexture->asRenderTarget(), NULL, 0x0, true);
while (!iter.done()) {
SkRect rect = SkRect::Make(iter.rect());
- context->drawRect(maskTexture->asRenderTarget(), GrClip::WideOpen(), grPaint,
- in_matrix, rect);
+ drawContext->drawRect(maskTexture->asRenderTarget(), GrClip::WideOpen(), grPaint,
+ in_matrix, rect);
iter.next();
}
}
#if SK_SUPPORT_GPU
#include "GrContext.h"
+#include "GrDrawContext.h"
#include "GrTexture.h"
#include "GrFragmentProcessor.h"
#include "GrInvariantOutput.h"
if (!viewMatrix.invert(&inverse)) {
return false;
}
- context->drawNonAARectWithLocalMatrix(rt, clip, *grp, SkMatrix::I(), rect, inverse);
- return true;
+
+ GrDrawContext* drawContext = context->drawContext();
+ if (drawContext) {
+ drawContext->drawNonAARectWithLocalMatrix(rt, clip, *grp, SkMatrix::I(), rect, inverse);
+ return true;
+ }
+
+ return false;
}
class GrRRectBlurEffect : public GrFragmentProcessor {
if (!viewMatrix.invert(&inverse)) {
return false;
}
- context->drawNonAARectWithLocalMatrix(rt, clip, *grp, SkMatrix::I(), proxy_rect, inverse);
- return true;
+
+ GrDrawContext* drawContext = context->drawContext();
+ if (drawContext) {
+ drawContext->drawNonAARectWithLocalMatrix(rt, clip, *grp, SkMatrix::I(),
+ proxy_rect, inverse);
+ return true;
+ }
+
+ return false;
}
bool SkBlurMaskFilterImpl::canFilterMaskGPU(const SkRect& srcBounds,
// = 0 * src + (1 - src) * dst
paint.setCoverageSetOpXPFactory(SkRegion::kDifference_Op);
}
- context->drawRect((*result)->asRenderTarget(), GrClip::WideOpen(), paint, SkMatrix::I(),
- clipRect);
+
+ GrDrawContext* drawContext = context->drawContext();
+ if (!drawContext) {
+ return false;
+ }
+
+ drawContext->drawRect((*result)->asRenderTarget(), GrClip::WideOpen(),
+ paint, SkMatrix::I(), clipRect);
}
return true;
#include "SkColorPriv.h"
#if SK_SUPPORT_GPU
#include "GrContext.h"
+#include "GrDrawContext.h"
#include "GrCoordTransform.h"
#include "GrInvariantOutput.h"
#include "effects/GrTextureDomain.h"
SkMatrix matrix;
matrix.setTranslate(-SkIntToScalar(colorBounds.x()),
-SkIntToScalar(colorBounds.y()));
- context->drawRect(dst->asRenderTarget(), GrClip::WideOpen(), paint, matrix,
- SkRect::Make(colorBounds));
+
+ GrDrawContext* drawContext = context->drawContext();
+ if (!drawContext) {
+ return false;
+ }
+
+ drawContext->drawRect(dst->asRenderTarget(), GrClip::WideOpen(), paint, matrix,
+ SkRect::Make(colorBounds));
offset->fX = bounds.left();
offset->fY = bounds.top();
WrapTexture(dst, bounds.width(), bounds.height(), result);
#include "effects/GrConvolutionEffect.h"
#include "effects/GrMatrixConvolutionEffect.h"
#include "GrContext.h"
+#include "GrDrawContext.h"
#endif
namespace SkGpuBlurUtils {
return sigma;
}
-static void convolve_gaussian_1d(GrContext* context,
+static void convolve_gaussian_1d(GrDrawContext* drawContext,
GrRenderTarget* rt,
const GrClip& clip,
const SkRect& srcRect,
SkAutoTUnref<GrFragmentProcessor> conv(GrConvolutionEffect::CreateGaussian(
texture, direction, radius, sigma, useBounds, bounds));
paint.addColorProcessor(conv);
- context->drawNonAARectToRect(rt, clip, paint, SkMatrix::I(), dstRect, srcRect);
+ drawContext->drawNonAARectToRect(rt, clip, paint, SkMatrix::I(), dstRect, srcRect);
}
-static void convolve_gaussian_2d(GrContext* context,
+static void convolve_gaussian_2d(GrDrawContext* drawContext,
GrRenderTarget* rt,
const GrClip& clip,
const SkRect& srcRect,
useBounds ? GrTextureDomain::kClamp_Mode : GrTextureDomain::kIgnore_Mode,
true, sigmaX, sigmaY));
paint.addColorProcessor(conv);
- context->drawNonAARectToRect(rt, clip, paint, SkMatrix::I(), dstRect, srcRect);
+ drawContext->drawNonAARectToRect(rt, clip, paint, SkMatrix::I(), dstRect, srcRect);
}
-static void convolve_gaussian(GrContext* context,
+static void convolve_gaussian(GrDrawContext* drawContext,
GrRenderTarget* rt,
const GrClip& clip,
const SkRect& srcRect,
bool cropToSrcRect) {
float bounds[2] = { 0.0f, 1.0f };
if (!cropToSrcRect) {
- convolve_gaussian_1d(context, rt, clip, srcRect, dstRect, texture,
+ convolve_gaussian_1d(drawContext, rt, clip, srcRect, dstRect, texture,
direction, radius, sigma, false, bounds);
return;
}
}
if (radius >= size * SK_ScalarHalf) {
// Blur radius covers srcRect; use bounds over entire draw
- convolve_gaussian_1d(context, rt, clip, srcRect, dstRect, texture,
+ convolve_gaussian_1d(drawContext, rt, clip, srcRect, dstRect, texture,
direction, radius, sigma, true, bounds);
} else {
// Draw upper and lower margins with bounds; middle without.
- convolve_gaussian_1d(context, rt, clip, lowerSrcRect, lowerDstRect, texture,
+ convolve_gaussian_1d(drawContext, rt, clip, lowerSrcRect, lowerDstRect, texture,
direction, radius, sigma, true, bounds);
- convolve_gaussian_1d(context, rt, clip, upperSrcRect, upperDstRect, texture,
+ convolve_gaussian_1d(drawContext, rt, clip, upperSrcRect, upperDstRect, texture,
direction, radius, sigma, true, bounds);
- convolve_gaussian_1d(context, rt, clip, middleSrcRect, middleDstRect, texture,
+ convolve_gaussian_1d(drawContext, rt, clip, middleSrcRect, middleDstRect, texture,
direction, radius, sigma, false, bounds);
}
}
return NULL;
}
+ GrDrawContext* drawContext = context->drawContext();
+ if (!drawContext) {
+ return NULL;
+ }
+
for (int i = 1; i < scaleFactorX || i < scaleFactorY; i *= 2) {
GrPaint paint;
SkMatrix matrix;
}
scale_rect(&dstRect, i < scaleFactorX ? 0.5f : 1.0f,
i < scaleFactorY ? 0.5f : 1.0f);
- context->drawNonAARectToRect(dstTexture->asRenderTarget(), clip, paint, SkMatrix::I(),
- dstRect, srcRect);
+ drawContext->drawNonAARectToRect(dstTexture->asRenderTarget(), clip, paint, SkMatrix::I(),
+ dstRect, srcRect);
srcRect = dstRect;
srcTexture = dstTexture;
SkTSwap(dstTexture, tempTexture);
// We shouldn't be scaling because this is a small size blur
SkASSERT((scaleFactorX == scaleFactorY) == 1);
SkRect dstRect = SkRect::MakeWH(srcRect.width(), srcRect.height());
- convolve_gaussian_2d(context, dstTexture->asRenderTarget(), clip, srcRect, dstRect,
+ convolve_gaussian_2d(drawContext, dstTexture->asRenderTarget(), clip, srcRect, dstRect,
srcTexture, radiusX, radiusY, sigmaX, sigmaY, cropToRect, srcIRect);
srcTexture = dstTexture;
srcRect = dstRect;
// X convolution from reading garbage.
clearRect = SkIRect::MakeXYWH(srcIRect.fRight, srcIRect.fTop,
radiusX, srcIRect.height());
- context->clear(&clearRect, 0x0, false, srcTexture->asRenderTarget());
+ drawContext->clear(srcTexture->asRenderTarget(), &clearRect, 0x0, false);
}
SkRect dstRect = SkRect::MakeWH(srcRect.width(), srcRect.height());
- convolve_gaussian(context, dstTexture->asRenderTarget(), clip, srcRect, dstRect,
+ convolve_gaussian(drawContext, dstTexture->asRenderTarget(), clip, srcRect, dstRect,
srcTexture, Gr1DKernelEffect::kX_Direction, radiusX, sigmaX,
cropToRect);
srcTexture = dstTexture;
// convolution from reading garbage.
clearRect = SkIRect::MakeXYWH(srcIRect.fLeft, srcIRect.fBottom,
srcIRect.width(), radiusY);
- context->clear(&clearRect, 0x0, false, srcTexture->asRenderTarget());
+ drawContext->clear(srcTexture->asRenderTarget(), &clearRect, 0x0, false);
}
SkRect dstRect = SkRect::MakeWH(srcRect.width(), srcRect.height());
- convolve_gaussian(context, dstTexture->asRenderTarget(), clip, srcRect,
+ convolve_gaussian(drawContext, dstTexture->asRenderTarget(), clip, srcRect,
dstRect, srcTexture, Gr1DKernelEffect::kY_Direction, radiusY, sigmaY,
cropToRect);
srcTexture = dstTexture;
// upsampling.
clearRect = SkIRect::MakeXYWH(srcIRect.fLeft, srcIRect.fBottom,
srcIRect.width() + 1, 1);
- context->clear(&clearRect, 0x0, false, srcTexture->asRenderTarget());
+ drawContext->clear(srcTexture->asRenderTarget(), &clearRect, 0x0, false);
clearRect = SkIRect::MakeXYWH(srcIRect.fRight, srcIRect.fTop,
1, srcIRect.height());
- context->clear(&clearRect, 0x0, false, srcTexture->asRenderTarget());
+ drawContext->clear(srcTexture->asRenderTarget(), &clearRect, 0x0, false);
SkMatrix matrix;
matrix.setIDiv(srcTexture->width(), srcTexture->height());
SkRect dstRect(srcRect);
scale_rect(&dstRect, (float) scaleFactorX, (float) scaleFactorY);
- context->drawNonAARectToRect(dstTexture->asRenderTarget(), clip, paint,
- SkMatrix::I(), dstRect, srcRect);
+ drawContext->drawNonAARectToRect(dstTexture->asRenderTarget(), clip, paint,
+ SkMatrix::I(), dstRect, srcRect);
srcRect = dstRect;
srcTexture = dstTexture;
SkTSwap(dstTexture, tempTexture);
#include "SkTypes.h"
#if SK_SUPPORT_GPU
+#include "GrDrawContext.h"
#include "GrFragmentProcessor.h"
#include "GrInvariantOutput.h"
#include "effects/GrSingleTextureEffect.h"
#endif
private:
#if SK_SUPPORT_GPU
- void drawRect(GrContext* context,
+ void drawRect(GrDrawContext* drawContext,
GrTexture* src,
GrTexture* dst,
const SkMatrix& matrix,
};
#if SK_SUPPORT_GPU
-void SkLightingImageFilterInternal::drawRect(GrContext* context,
+void SkLightingImageFilterInternal::drawRect(GrDrawContext* drawContext,
GrTexture* src,
GrTexture* dst,
const SkMatrix& matrix,
GrFragmentProcessor* fp = this->getFragmentProcessor(src, matrix, bounds, boundaryMode);
GrPaint paint;
paint.addColorProcessor(fp)->unref();
- context->drawNonAARectToRect(dst->asRenderTarget(), clip, paint, SkMatrix::I(),
- dstRect, srcRect);
+ drawContext->drawNonAARectToRect(dst->asRenderTarget(), clip, paint, SkMatrix::I(),
+ dstRect, srcRect);
}
bool SkLightingImageFilterInternal::filterImageGPU(Proxy* proxy,
SkRect bottomLeft = SkRect::MakeXYWH(0, dstRect.height() - 1, 1, 1);
SkRect bottom = SkRect::MakeXYWH(1, dstRect.height() - 1, dstRect.width() - 2, 1);
SkRect bottomRight = SkRect::MakeXYWH(dstRect.width() - 1, dstRect.height() - 1, 1, 1);
- this->drawRect(context, srcTexture, dst, matrix, clip, topLeft, kTopLeft_BoundaryMode, bounds);
- this->drawRect(context, srcTexture, dst, matrix, clip, top, kTop_BoundaryMode, bounds);
- this->drawRect(context, srcTexture, dst, matrix, clip, topRight, kTopRight_BoundaryMode,
+
+ GrDrawContext* drawContext = context->drawContext();
+ if (!drawContext) {
+ return false;
+ }
+
+ this->drawRect(drawContext, srcTexture, dst, matrix, clip, topLeft, kTopLeft_BoundaryMode,
bounds);
- this->drawRect(context, srcTexture, dst, matrix, clip, left, kLeft_BoundaryMode, bounds);
- this->drawRect(context, srcTexture, dst, matrix, clip, interior, kInterior_BoundaryMode,
+ this->drawRect(drawContext, srcTexture, dst, matrix, clip, top, kTop_BoundaryMode, bounds);
+ this->drawRect(drawContext, srcTexture, dst, matrix, clip, topRight, kTopRight_BoundaryMode,
bounds);
- this->drawRect(context, srcTexture, dst, matrix, clip, right, kRight_BoundaryMode, bounds);
- this->drawRect(context, srcTexture, dst, matrix, clip, bottomLeft, kBottomLeft_BoundaryMode,
+ this->drawRect(drawContext, srcTexture, dst, matrix, clip, left, kLeft_BoundaryMode, bounds);
+ this->drawRect(drawContext, srcTexture, dst, matrix, clip, interior, kInterior_BoundaryMode,
bounds);
- this->drawRect(context, srcTexture, dst, matrix, clip, bottom, kBottom_BoundaryMode, bounds);
- this->drawRect(context, srcTexture, dst, matrix, clip, bottomRight, kBottomRight_BoundaryMode,
+ this->drawRect(drawContext, srcTexture, dst, matrix, clip, right, kRight_BoundaryMode, bounds);
+ this->drawRect(drawContext, srcTexture, dst, matrix, clip, bottomLeft, kBottomLeft_BoundaryMode,
bounds);
+ this->drawRect(drawContext, srcTexture, dst, matrix, clip, bottom, kBottom_BoundaryMode, bounds);
+ this->drawRect(drawContext, srcTexture, dst, matrix, clip, bottomRight,
+ kBottomRight_BoundaryMode, bounds);
WrapTexture(dst, bounds.width(), bounds.height(), result);
return true;
}
#include "SkMorphology_opts.h"
#if SK_SUPPORT_GPU
#include "GrContext.h"
+#include "GrDrawContext.h"
#include "GrInvariantOutput.h"
#include "GrTexture.h"
#include "effects/Gr1DKernelEffect.h"
namespace {
-void apply_morphology_rect(GrContext* context,
+void apply_morphology_rect(GrDrawContext* drawContext,
GrRenderTarget* rt,
const GrClip& clip,
GrTexture* texture,
radius,
morphType,
bounds))->unref();
- context->drawNonAARectToRect(rt, clip, paint, SkMatrix::I(), SkRect::Make(dstRect),
- SkRect::Make(srcRect));
+ drawContext->drawNonAARectToRect(rt, clip, paint, SkMatrix::I(), SkRect::Make(dstRect),
+ SkRect::Make(srcRect));
}
-void apply_morphology_rect_no_bounds(GrContext* context,
+void apply_morphology_rect_no_bounds(GrDrawContext* drawContext,
GrRenderTarget* rt,
const GrClip& clip,
GrTexture* texture,
direction,
radius,
morphType))->unref();
- context->drawNonAARectToRect(rt, clip, paint, SkMatrix::I(), SkRect::Make(dstRect),
- SkRect::Make(srcRect));
+ drawContext->drawNonAARectToRect(rt, clip, paint, SkMatrix::I(), SkRect::Make(dstRect),
+ SkRect::Make(srcRect));
}
-void apply_morphology_pass(GrContext* context,
+void apply_morphology_pass(GrDrawContext* drawContext,
GrRenderTarget* rt,
const GrClip& clip,
GrTexture* texture,
}
if (middleSrcRect.fLeft - middleSrcRect.fRight >= 0) {
// radius covers srcRect; use bounds over entire draw
- apply_morphology_rect(context, rt, clip, texture, srcRect, dstRect, radius,
+ apply_morphology_rect(drawContext, rt, clip, texture, srcRect, dstRect, radius,
morphType, bounds, direction);
} else {
// Draw upper and lower margins with bounds; middle without.
- apply_morphology_rect(context, rt, clip, texture, lowerSrcRect, lowerDstRect, radius,
+ apply_morphology_rect(drawContext, rt, clip, texture, lowerSrcRect, lowerDstRect, radius,
morphType, bounds, direction);
- apply_morphology_rect(context, rt, clip, texture, upperSrcRect, upperDstRect, radius,
+ apply_morphology_rect(drawContext, rt, clip, texture, upperSrcRect, upperDstRect, radius,
morphType, bounds, direction);
- apply_morphology_rect_no_bounds(context, rt, clip, texture, middleSrcRect, middleDstRect,
+ apply_morphology_rect_no_bounds(drawContext, rt, clip, texture, middleSrcRect, middleDstRect,
radius, morphType, direction);
}
}
desc.fConfig = kSkia8888_GrPixelConfig;
SkIRect srcRect = rect;
+ GrDrawContext* drawContext = context->drawContext();
+ if (!drawContext) {
+ return false;
+ }
+
if (radius.fWidth > 0) {
GrTexture* texture = context->textureProvider()->refScratchTexture(
desc, GrTextureProvider::kApprox_ScratchTexMatch);
if (NULL == texture) {
return false;
}
- apply_morphology_pass(context, texture->asRenderTarget(), clip, srcTexture,
+ apply_morphology_pass(drawContext, texture->asRenderTarget(), clip, srcTexture,
srcRect, dstRect, radius.fWidth, morphType,
Gr1DKernelEffect::kX_Direction);
SkIRect clearRect = SkIRect::MakeXYWH(dstRect.fLeft, dstRect.fBottom,
GrColor clearColor = GrMorphologyEffect::kErode_MorphologyType == morphType ?
SK_ColorWHITE :
SK_ColorTRANSPARENT;
- context->clear(&clearRect, clearColor, false, texture->asRenderTarget());
+ drawContext->clear(texture->asRenderTarget(), &clearRect, clearColor, false);
srcTexture.reset(texture);
srcRect = dstRect;
}
if (NULL == texture) {
return false;
}
- apply_morphology_pass(context, texture->asRenderTarget(), clip, srcTexture,
+ apply_morphology_pass(drawContext, texture->asRenderTarget(), clip, srcTexture,
srcRect, dstRect, radius.fHeight, morphType,
Gr1DKernelEffect::kY_Direction);
srcTexture.reset(texture);
#include "SkXfermode.h"
#if SK_SUPPORT_GPU
#include "GrContext.h"
+#include "GrDrawContext.h"
#include "effects/GrTextureDomain.h"
#include "SkGr.h"
#endif
paint.addColorProcessor(foregroundDomain.get());
paint.addColorProcessor(xferProcessor)->unref();
- context->drawRect(dst->asRenderTarget(), GrClip::WideOpen(), paint, SkMatrix::I(), srcRect);
+
+ GrDrawContext* drawContext = context->drawContext();
+ if (!drawContext) {
+ return false;
+ }
+
+ drawContext->drawRect(dst->asRenderTarget(), GrClip::WideOpen(), paint,
+ SkMatrix::I(), srcRect);
offset->fX = backgroundOffset.fX;
offset->fY = backgroundOffset.fY;
};
}
-void GrAARectRenderer::geometryFillAARect(GrDrawTarget* target,
+void GrAARectRenderer::GeometryFillAARect(GrDrawTarget* target,
GrPipelineBuilder* pipelineBuilder,
GrColor color,
const SkMatrix& viewMatrix,
target->drawBatch(pipelineBuilder, batch);
}
-void GrAARectRenderer::strokeAARect(GrDrawTarget* target,
+void GrAARectRenderer::StrokeAARect(GrDrawTarget* target,
GrPipelineBuilder* pipelineBuilder,
GrColor color,
const SkMatrix& viewMatrix,
}
if (spare <= 0 && miterStroke) {
- this->fillAARect(target, pipelineBuilder, color, viewMatrix, devOutside, devOutside);
+ FillAARect(target, pipelineBuilder, color, viewMatrix, devOutside, devOutside);
return;
}
devOutsideAssist.outset(0, ry);
}
- this->geometryStrokeAARect(target, pipelineBuilder, color, viewMatrix, devOutside,
- devOutsideAssist, devInside, miterStroke);
+ GeometryStrokeAARect(target, pipelineBuilder, color, viewMatrix, devOutside,
+ devOutsideAssist, devInside, miterStroke);
}
GR_DECLARE_STATIC_UNIQUE_KEY(gMiterIndexBufferKey);
SkSTArray<1, Geometry, true> fGeoData;
};
-void GrAARectRenderer::geometryStrokeAARect(GrDrawTarget* target,
+void GrAARectRenderer::GeometryStrokeAARect(GrDrawTarget* target,
GrPipelineBuilder* pipelineBuilder,
GrColor color,
const SkMatrix& viewMatrix,
target->drawBatch(pipelineBuilder, batch);
}
-void GrAARectRenderer::fillAANestedRects(GrDrawTarget* target,
+void GrAARectRenderer::FillAANestedRects(GrDrawTarget* target,
GrPipelineBuilder* pipelineBuilder,
GrColor color,
const SkMatrix& viewMatrix,
viewMatrix.mapRect(&devInside, rects[1]);
if (devInside.isEmpty()) {
- this->fillAARect(target, pipelineBuilder, color, viewMatrix, devOutside, devOutside);
+ FillAARect(target, pipelineBuilder, color, viewMatrix, devOutside, devOutside);
return;
}
- this->geometryStrokeAARect(target, pipelineBuilder, color, viewMatrix, devOutside,
- devOutside, devInside, true);
+ GeometryStrokeAARect(target, pipelineBuilder, color, viewMatrix, devOutside,
+ devOutside, devInside, true);
}
///////////////////////////////////////////////////////////////////////////////////////////////////
#include "GrColor.h"
#include "SkMatrix.h"
#include "SkRect.h"
-#include "SkRefCnt.h"
#include "SkStrokeRec.h"
class GrClip;
/*
* This class wraps helper functions that draw AA rects (filled & stroked)
*/
-class GrAARectRenderer : public SkRefCnt {
+class GrAARectRenderer {
public:
- SK_DECLARE_INST_COUNT(GrAARectRenderer)
-
// TODO: potentialy fuse the fill & stroke methods and differentiate
// between them by passing in stroke (==NULL means fill).
- void fillAARect(GrDrawTarget* target,
- GrPipelineBuilder* pipelineBuilder,
- GrColor color,
- const SkMatrix& viewMatrix,
- const SkRect& rect,
- const SkRect& devRect) {
- this->geometryFillAARect(target, pipelineBuilder, color, viewMatrix, rect, devRect);
+ static void FillAARect(GrDrawTarget* target,
+ GrPipelineBuilder* pipelineBuilder,
+ GrColor color,
+ const SkMatrix& viewMatrix,
+ const SkRect& rect,
+ const SkRect& devRect) {
+ GeometryFillAARect(target, pipelineBuilder, color, viewMatrix, rect, devRect);
}
- void strokeAARect(GrDrawTarget*,
- GrPipelineBuilder*,
- GrColor,
- const SkMatrix& viewMatrix,
- const SkRect& rect,
- const SkRect& devRect,
- const SkStrokeRec& stroke);
+ static void StrokeAARect(GrDrawTarget*,
+ GrPipelineBuilder*,
+ GrColor,
+ const SkMatrix& viewMatrix,
+ const SkRect& rect,
+ const SkRect& devRect,
+ const SkStrokeRec& stroke);
// First rect is outer; second rect is inner
- void fillAANestedRects(GrDrawTarget*,
- GrPipelineBuilder*,
- GrColor,
- const SkMatrix& viewMatrix,
- const SkRect rects[2]);
+ static void FillAANestedRects(GrDrawTarget*,
+ GrPipelineBuilder*,
+ GrColor,
+ const SkMatrix& viewMatrix,
+ const SkRect rects[2]);
private:
- void geometryFillAARect(GrDrawTarget*,
- GrPipelineBuilder*,
- GrColor,
- const SkMatrix& viewMatrix,
- const SkRect& rect,
- const SkRect& devRect);
+ GrAARectRenderer();
- void geometryStrokeAARect(GrDrawTarget*,
- GrPipelineBuilder*,
- GrColor,
- const SkMatrix& viewMatrix,
- const SkRect& devOutside,
- const SkRect& devOutsideAssist,
- const SkRect& devInside,
- bool miterStroke);
+ static void GeometryFillAARect(GrDrawTarget*,
+ GrPipelineBuilder*,
+ GrColor,
+ const SkMatrix& viewMatrix,
+ const SkRect& rect,
+ const SkRect& devRect);
- typedef SkRefCnt INHERITED;
+ static void GeometryStrokeAARect(GrDrawTarget*,
+ GrPipelineBuilder*,
+ GrColor,
+ const SkMatrix& viewMatrix,
+ const SkRect& devOutside,
+ const SkRect& devOutsideAssist,
+ const SkRect& devInside,
+ bool miterStroke);
};
#endif // GrAARectRenderer_DEFINED
#define GrAtlas_DEFINED
+#include "SkTDArray.h"
#include "GrTexture.h"
-#include "GrDrawTarget.h"
#include "SkPoint.h"
#include "SkTInternalLList.h"
#include "GrBatchTarget.h"
#include "GrBatchTest.h"
#include "GrDefaultGeoProcFactory.h"
-#include "GrDrawTarget.h"
+#include "GrDrawContext.h"
#include "GrFontScaler.h"
#include "GrIndexBuffer.h"
#include "GrResourceProvider.h"
const SkTextBlob* blob, SkScalar x, SkScalar y,
SkDrawFilter* drawFilter, const SkIRect& clipBounds) {
// If we have been abandoned, then don't draw
- if (!fContext->getTextTarget()) {
+ if (fContext->abandoned()) {
+ return;
+ }
+
+ GrDrawContext* drawContext = fContext->drawContext();
+ if (!drawContext) {
return;
}
}
cacheBlob->fPaintColor = skPaint.getColor();
- this->flush(fContext->getTextTarget(), blob, cacheBlob, rt, skPaint, grPaint, drawFilter,
+ this->flush(drawContext, blob, cacheBlob, rt, skPaint, grPaint, drawFilter,
clip, viewMatrix, clipBounds, x, y, transX, transY);
}
// rasterizers and mask filters modify alpha, which doesn't
// translate well to distance
if (skPaint.getRasterizer() || skPaint.getMaskFilter() ||
- !fContext->getTextTarget()->caps()->shaderCaps()->shaderDerivativeSupport()) {
+ !fContext->shaderDerivativeSupport()) {
return false;
}
const SkMatrix& viewMatrix,
const char text[], size_t byteLength,
SkScalar x, SkScalar y, const SkIRect& regionClipBounds) {
- SkAutoTUnref<BitmapTextBlob> blob(
+ GrDrawContext* drawContext = fContext->drawContext();
+ if (drawContext) {
+ SkAutoTUnref<BitmapTextBlob> blob(
this->createDrawTextBlob(rt, clip, paint, skPaint, viewMatrix,
text, byteLength, x, y, regionClipBounds));
- this->flush(fContext->getTextTarget(), blob, rt, skPaint, paint, clip, regionClipBounds);
+ this->flush(drawContext, blob, rt, skPaint, paint, clip, regionClipBounds);
+ }
}
void GrAtlasTextContext::onDrawPosText(GrRenderTarget* rt, const GrClip& clip,
const char text[], size_t byteLength,
const SkScalar pos[], int scalarsPerPosition,
const SkPoint& offset, const SkIRect& regionClipBounds) {
- SkAutoTUnref<BitmapTextBlob> blob(
+ GrDrawContext* drawContext = fContext->drawContext();
+ if (drawContext) {
+ SkAutoTUnref<BitmapTextBlob> blob(
this->createDrawPosTextBlob(rt, clip, paint, skPaint, viewMatrix,
text, byteLength,
pos, scalarsPerPosition,
offset, regionClipBounds));
- this->flush(fContext->getTextTarget(), blob, rt, skPaint, paint, clip, regionClipBounds);
+ this->flush(drawContext, blob, rt, skPaint, paint, clip, regionClipBounds);
+ }
}
void GrAtlasTextContext::internalDrawBMPText(BitmapTextBlob* blob, int runIndex,
return batch;
}
-inline void GrAtlasTextContext::flushRun(GrDrawTarget* target, GrPipelineBuilder* pipelineBuilder,
+inline void GrAtlasTextContext::flushRun(GrDrawContext* drawContext,
+ GrPipelineBuilder* pipelineBuilder,
BitmapTextBlob* cacheBlob, int run, GrColor color,
- SkScalar transX, SkScalar transY, const SkPaint& skPaint) {
+ SkScalar transX, SkScalar transY,
+ const SkPaint& skPaint) {
for (int subRun = 0; subRun < cacheBlob->fRuns[run].fSubRunInfo.count(); subRun++) {
const PerSubRunInfo& info = cacheBlob->fRuns[run].fSubRunInfo[subRun];
int glyphCount = info.fGlyphEndIndex - info.fGlyphStartIndex;
SkAutoTUnref<BitmapTextBatch> batch(this->createBatch(cacheBlob, info, glyphCount, run,
subRun, color, transX, transY,
skPaint));
- target->drawBatch(pipelineBuilder, batch);
+ drawContext->drawText(pipelineBuilder, batch);
}
}
}
}
-void GrAtlasTextContext::flush(GrDrawTarget* target,
+void GrAtlasTextContext::flush(GrDrawContext* drawContext,
const SkTextBlob* blob,
BitmapTextBlob* cacheBlob,
GrRenderTarget* rt,
continue;
}
cacheBlob->fRuns[run].fVertexBounds.offset(transX, transY);
- this->flushRun(target, &pipelineBuilder, cacheBlob, run, color, transX, transY, skPaint);
+ this->flushRun(drawContext, &pipelineBuilder, cacheBlob, run, color,
+ transX, transY, skPaint);
}
// Now flush big glyphs
this->flushBigGlyphs(cacheBlob, rt, skPaint, transX, transY, clipBounds);
}
-void GrAtlasTextContext::flush(GrDrawTarget* target,
+void GrAtlasTextContext::flush(GrDrawContext* drawContext,
BitmapTextBlob* cacheBlob,
GrRenderTarget* rt,
const SkPaint& skPaint,
GrColor color = grPaint.getColor();
for (int run = 0; run < cacheBlob->fRunCount; run++) {
- this->flushRun(target, &pipelineBuilder, cacheBlob, run, color, 0, 0, skPaint);
+ this->flushRun(drawContext, &pipelineBuilder, cacheBlob, run, color, 0, 0, skPaint);
}
// Now flush big glyphs
#endif
class BitmapTextBatch;
+class GrDrawContext;
class GrPipelineBuilder;
class GrTextBlobCache;
int glyphCount, int run, int subRun,
GrColor, SkScalar transX, SkScalar transY,
const SkPaint&);
- inline void flushRun(GrDrawTarget*, GrPipelineBuilder*, BitmapTextBlob*, int run, GrColor,
+ inline void flushRun(GrDrawContext*, GrPipelineBuilder*, BitmapTextBlob*, int run, GrColor,
SkScalar transX, SkScalar transY, const SkPaint&);
inline void flushBigGlyphs(BitmapTextBlob* cacheBlob, GrRenderTarget* rt,
const SkPaint& skPaint,
SkScalar transX, SkScalar transY, const SkIRect& clipBounds);
// We have to flush SkTextBlobs differently from drawText / drawPosText
- void flush(GrDrawTarget*, const SkTextBlob*, BitmapTextBlob*, GrRenderTarget*, const SkPaint&,
+ void flush(GrDrawContext*, const SkTextBlob*, BitmapTextBlob*, GrRenderTarget*, const SkPaint&,
const GrPaint&, SkDrawFilter*, const GrClip&, const SkMatrix& viewMatrix,
const SkIRect& clipBounds, SkScalar x, SkScalar y, SkScalar transX, SkScalar transY);
- void flush(GrDrawTarget*, BitmapTextBlob*, GrRenderTarget*, const SkPaint&,
+ void flush(GrDrawContext*, BitmapTextBlob*, GrRenderTarget*, const SkPaint&,
const GrPaint&, const GrClip&, const SkIRect& clipBounds);
// A helper for drawing BitmapText in a run of distance fields
#define GrBatchFontCache_DEFINED
#include "GrBatchAtlas.h"
-#include "GrDrawTarget.h"
#include "GrFontScaler.h"
#include "GrGlyph.h"
#include "SkTDynamicHash.h"
#include "GrClipMaskManager.h"
#include "GrAAConvexPathRenderer.h"
#include "GrAAHairLinePathRenderer.h"
-#include "GrAARectRenderer.h"
#include "GrCaps.h"
+#include "GrDrawContext.h"
+#include "GrDrawTarget.h"
#include "GrPaint.h"
#include "GrPathRenderer.h"
#include "GrRenderTarget.h"
if (element->isAA()) {
SkRect devRect = element->getRect();
viewMatrix.mapRect(&devRect);
- this->getContext()->getAARectRenderer()->fillAARect(fClipTarget,
- pipelineBuilder,
- color,
- viewMatrix,
- element->getRect(),
- devRect);
+
+ fClipTarget->drawAARect(pipelineBuilder, color, viewMatrix,
+ element->getRect(), devRect);
} else {
- fClipTarget->drawSimpleRect(pipelineBuilder, color, viewMatrix, element->getRect());
+ fClipTarget->drawSimpleRect(pipelineBuilder, color, viewMatrix,
+ element->getRect());
}
return true;
default: {
#include "GrCaps.h"
#include "GrContextOptions.h"
#include "GrDefaultGeoProcFactory.h"
+#include "GrDrawContext.h"
#include "GrGpuResource.h"
#include "GrGpuResourcePriv.h"
#include "GrGpu.h"
#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;
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();
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));
}
GrContext::~GrContext() {
- if (NULL == fGpu) {
+ if (!fGpu) {
return;
}
SkDELETE(fResourceProvider);
SkDELETE(fResourceCache);
SkDELETE(fBatchFontCache);
- SkDELETE(fDrawBuffer);
-
- fAARectRenderer->unref();
- fOvalRenderer->unref();
fGpu->unref();
SkSafeUnref(fPathRendererChain);
SkSafeSetNull(fPathRendererChain);
SkSafeSetNull(fSoftwarePathRenderer);
- SkDELETE(fDrawBuffer);
- fDrawBuffer = NULL;
+ fDrawingMgr.abandon();
fBatchFontCache->freeAll();
fLayerCache->freeAll();
void GrContext::freeGpuResources() {
this->flush();
- if (fDrawBuffer) {
- fDrawBuffer->purgeResources();
- }
+ fDrawingMgr.purgeResources();
fBatchFontCache->freeAll();
fLayerCache->freeAll();
////////////////////////////////////////////////////////////////////////////////
+bool GrContext::shaderDerivativeSupport() const {
+ return fGpu->caps()->shaderCaps()->shaderDerivativeSupport();
+}
+
bool GrContext::isConfigTexturable(GrPixelConfig config) const {
return fGpu->caps()->isConfigTexturable(config);
}
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;
// 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;
}
}
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,
buffer = tmpPixels.get();
}
}
- if (NULL == fp) {
+ if (!fp) {
fp.reset(GrConfigConversionEffect::Create(texture,
swapRAndB,
GrConfigConversionEffect::kNone_PMConversion,
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);
}
// 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;
}
}
-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);
// 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();
}
}
-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.
GrPathRendererChain::DrawType drawType,
GrPathRendererChain::StencilSupport* stencilSupport) {
- if (NULL == fPathRendererChain) {
+ if (!fPathRendererChain) {
fPathRendererChain = SkNEW_ARGS(GrPathRendererChain, (this));
}
drawType,
stencilSupport);
- if (NULL == pr && allowSW) {
- if (NULL == fSoftwarePathRenderer) {
+ if (!pr && allowSW) {
+ if (!fSoftwarePathRenderer) {
fSoftwarePathRenderer = SkNEW_ARGS(GrSoftwarePathRenderer, (this));
}
pr = fSoftwarePathRenderer;
chosenSampleCount : 0;
}
-GrDrawTarget* GrContext::getTextTarget() {
- return this->prepareToDraw();
-}
-
namespace {
void test_pm_conversions(GrContext* ctx, int* pmToUPMValue, int* upmToPMValue) {
GrConfigConversionEffect::PMConversion pmToUPM;
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
}
const SkMatrix& viewM = (reverse && viewMatrix.hasPerspective()) ? SkMatrix::I() :
viewMatrix;
- target->drawRect(pipelineBuilder, color, viewM, bounds, NULL, &localMatrix);
+ target->drawBWRect(pipelineBuilder, color, viewM, bounds, NULL, &localMatrix);
} else {
if (passCount > 1) {
pipelineBuilder->setDisableColorXPFactory();
--- /dev/null
+
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "GrAARectRenderer.h"
+#include "GrBatch.h"
+#include "GrBatchTest.h"
+#include "GrDefaultGeoProcFactory.h"
+#include "GrDrawContext.h"
+#include "GrOvalRenderer.h"
+#include "GrPathRenderer.h"
+
+#define ASSERT_OWNED_RESOURCE(R) SkASSERT(!(R) || (R)->getContext() == fContext)
+#define RETURN_IF_ABANDONED if (!fDrawTarget) { return; }
+#define RETURN_FALSE_IF_ABANDONED if (!fDrawTarget) { return false; }
+#define RETURN_NULL_IF_ABANDONED if (!fDrawTarget) { return NULL; }
+
+class AutoCheckFlush {
+public:
+ AutoCheckFlush(GrContext* context) : fContext(context) { SkASSERT(context); }
+ ~AutoCheckFlush() { fContext->flushIfNecessary(); }
+
+private:
+ GrContext* fContext;
+};
+
+GrDrawContext::GrDrawContext(GrContext* context, GrDrawTarget* drawTarget)
+ : fContext(context)
+ , fDrawTarget(SkRef(drawTarget)) {
+}
+
+void GrDrawContext::copySurface(GrRenderTarget* dst, GrSurface* src,
+ const SkIRect& srcRect, const SkIPoint& dstPoint) {
+ if (!this->prepareToDraw(dst)) {
+ return;
+ }
+
+ fDrawTarget->copySurface(dst, src, srcRect, dstPoint);
+}
+
+void GrDrawContext::drawText(GrPipelineBuilder* pipelineBuilder, GrBatch* batch) {
+ fDrawTarget->drawBatch(pipelineBuilder, batch);
+}
+
+void GrDrawContext::drawPaths(GrPipelineBuilder* pipelineBuilder,
+ const GrPathProcessor* pathProc,
+ const GrPathRange* pathRange,
+ const void* indices,
+ int /*GrDrawTarget::PathIndexType*/ indexType,
+ const float transformValues[],
+ int /*GrDrawTarget::PathTransformType*/ transformType,
+ int count,
+ int /*GrPathRendering::FillType*/ fill) {
+ fDrawTarget->drawPaths(pipelineBuilder, pathProc, pathRange,
+ indices, (GrDrawTarget::PathIndexType) indexType,
+ transformValues,
+ (GrDrawTarget::PathTransformType) transformType,
+ count, (GrPathRendering::FillType) fill);
+}
+
+void GrDrawContext::discard(GrRenderTarget* renderTarget) {
+ RETURN_IF_ABANDONED
+ SkASSERT(renderTarget);
+ AutoCheckFlush acf(fContext);
+ if (!this->prepareToDraw(renderTarget)) {
+ return;
+ }
+ fDrawTarget->discard(renderTarget);
+}
+
+void GrDrawContext::clear(GrRenderTarget* renderTarget,
+ const SkIRect* rect,
+ const GrColor color,
+ bool canIgnoreRect) {
+ RETURN_IF_ABANDONED
+ SkASSERT(renderTarget);
+
+ AutoCheckFlush acf(fContext);
+ if (!this->prepareToDraw(renderTarget)) {
+ return;
+ }
+ fDrawTarget->clear(rect, color, canIgnoreRect, renderTarget);
+}
+
+
+void GrDrawContext::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(fContext);
+ GrPipelineBuilder pipelineBuilder;
+ if (!this->prepareToDraw(&pipelineBuilder, rt, clip, paint)) {
+ return;
+ }
+
+ fDrawTarget->drawBWRect(&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 GrDrawContext::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(fContext);
+ GrPipelineBuilder pipelineBuilder;
+ if (!this->prepareToDraw(&pipelineBuilder, rt, clip, &paint)) {
+ return;
+ }
+
+ 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)) {
+ fDrawTarget->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(fDrawTarget, &pipelineBuilder, &devBoundRect, rect,
+ width, viewMatrix, color);
+
+ if (doAA) {
+ if (width >= 0) {
+ GrAARectRenderer::StrokeAARect(fDrawTarget,
+ &pipelineBuilder,
+ color,
+ viewMatrix,
+ rect,
+ devBoundRect,
+ *strokeInfo);
+ } else {
+ // filled AA rect
+ GrAARectRenderer::FillAARect(fDrawTarget,
+ &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);
+ fDrawTarget->drawBatch(&pipelineBuilder, batch);
+ } else {
+ // filled BW rect
+ fDrawTarget->drawSimpleRect(&pipelineBuilder, color, viewMatrix, rect);
+ }
+}
+
+void GrDrawContext::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(fContext);
+ GrPipelineBuilder pipelineBuilder;
+ if (!this->prepareToDraw(&pipelineBuilder, rt, clip, &paint)) {
+ return;
+ }
+
+ fDrawTarget->drawBWRect(&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 GrDrawContext::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(fContext);
+ GrPipelineBuilder pipelineBuilder;
+
+ if (!this->prepareToDraw(&pipelineBuilder, rt, clip, &paint)) {
+ return;
+ }
+
+ // 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));
+
+ fDrawTarget->drawBatch(&pipelineBuilder, batch);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void GrDrawContext::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(fContext);
+ GrPipelineBuilder pipelineBuilder;
+ if (!this->prepareToDraw(&pipelineBuilder, rt, clip, &paint)) {
+ return;
+ }
+
+ GrColor color = paint.getColor();
+ if (!GrOvalRenderer::DrawRRect(fDrawTarget,
+ &pipelineBuilder,
+ color,
+ viewMatrix,
+ paint.isAntiAlias(),
+ rrect,
+ strokeInfo)) {
+ SkPath path;
+ path.setIsVolatile(true);
+ path.addRRect(rrect);
+ this->internalDrawPath(fDrawTarget, &pipelineBuilder, viewMatrix, color,
+ paint.isAntiAlias(), path, strokeInfo);
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void GrDrawContext::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(fContext);
+ GrPipelineBuilder pipelineBuilder;
+ if (!this->prepareToDraw(&pipelineBuilder, rt, clip, &paint)) {
+ return;
+ }
+
+ GrColor color = paint.getColor();
+ if (!GrOvalRenderer::DrawDRRect(fDrawTarget,
+ &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(fDrawTarget, &pipelineBuilder, viewMatrix, color,
+ paint.isAntiAlias(), path, fillRec);
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void GrDrawContext::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(fContext);
+ GrPipelineBuilder pipelineBuilder;
+ if (!this->prepareToDraw(&pipelineBuilder, rt, clip, &paint)) {
+ return;
+ }
+
+ GrColor color = paint.getColor();
+ if (!GrOvalRenderer::DrawOval(fDrawTarget,
+ &pipelineBuilder,
+ color,
+ viewMatrix,
+ paint.isAntiAlias(),
+ oval,
+ strokeInfo)) {
+ SkPath path;
+ path.setIsVolatile(true);
+ path.addOval(oval);
+ this->internalDrawPath(fDrawTarget, &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 GrDrawContext::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(fContext);
+ GrPipelineBuilder pipelineBuilder;
+ if (!this->prepareToDraw(&pipelineBuilder, rt, clip, &paint)) {
+ return;
+ }
+
+ 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(fDrawTarget, &pipelineBuilder, color, viewMatrix, path, strokeInfo,
+ rects)) {
+ GrAARectRenderer::FillAANestedRects(fDrawTarget, &pipelineBuilder, color,
+ viewMatrix, rects);
+ return;
+ }
+ }
+ SkRect ovalRect;
+ bool isOval = path.isOval(&ovalRect);
+
+ if (isOval && !path.isInverseFillType()) {
+ if (GrOvalRenderer::DrawOval(fDrawTarget,
+ &pipelineBuilder,
+ color,
+ viewMatrix,
+ paint.isAntiAlias(),
+ ovalRect,
+ strokeInfo)) {
+ return;
+ }
+ }
+ }
+ this->internalDrawPath(fDrawTarget, &pipelineBuilder, viewMatrix, color, paint.isAntiAlias(),
+ path, strokeInfo);
+}
+
+void GrDrawContext::internalDrawPath(GrDrawTarget* target,
+ GrPipelineBuilder* pipelineBuilder,
+ const SkMatrix& viewMatrix,
+ GrColor color,
+ bool useAA,
+ const SkPath& path,
+ const GrStrokeInfo& strokeInfo) {
+ RETURN_IF_ABANDONED
+ SkASSERT(!path.isEmpty());
+
+
+ // 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 = fContext->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 = fContext->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 = fContext->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);
+}
+
+bool GrDrawContext::prepareToDraw(GrPipelineBuilder* pipelineBuilder,
+ GrRenderTarget* rt,
+ const GrClip& clip,
+ const GrPaint* paint) {
+ RETURN_FALSE_IF_ABANDONED
+
+ ASSERT_OWNED_RESOURCE(rt);
+ SkASSERT(rt && paint);
+ pipelineBuilder->setFromPaint(*paint, rt, clip);
+ return true;
+}
+
+bool GrDrawContext::prepareToDraw(GrRenderTarget* rt) {
+ RETURN_FALSE_IF_ABANDONED
+
+ ASSERT_OWNED_RESOURCE(rt);
+ SkASSERT(rt);
+ return true;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+#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
+
#include "GrDrawTarget.h"
+#include "GrAARectRenderer.h"
#include "GrBatch.h"
#include "GrCaps.h"
#include "GrContext.h"
transformType, count, stencilSettings, pipelineInfo);
}
-void GrDrawTarget::drawRect(GrPipelineBuilder* pipelineBuilder,
+void GrDrawTarget::drawBWRect(GrPipelineBuilder* pipelineBuilder,
GrColor color,
const SkMatrix& viewMatrix,
const SkRect& rect,
this->drawBatch(pipelineBuilder, batch);
}
+void GrDrawTarget::drawAARect(GrPipelineBuilder* pipelineBuilder,
+ GrColor color,
+ const SkMatrix& viewMatrix,
+ const SkRect& rect,
+ const SkRect& devRect) {
+ GrAARectRenderer::FillAARect(this, pipelineBuilder, color, viewMatrix, rect, devRect);
+}
+
void GrDrawTarget::clear(const SkIRect* rect,
GrColor color,
bool canIgnoreRect,
* that rectangle before it is input to GrCoordTransforms that read local
* coordinates
*/
- void drawRect(GrPipelineBuilder* pipelineBuilder,
- GrColor color,
- const SkMatrix& viewMatrix,
- const SkRect& rect,
- const SkRect* localRect,
- const SkMatrix* localMatrix);
+ void drawBWRect(GrPipelineBuilder* pipelineBuilder,
+ GrColor color,
+ const SkMatrix& viewMatrix,
+ const SkRect& rect,
+ const SkRect* localRect,
+ const SkMatrix* localMatrix);
/**
* Helper for drawRect when the caller doesn't need separate local rects or matrices.
*/
void drawSimpleRect(GrPipelineBuilder* ds, GrColor color, const SkMatrix& viewM,
const SkRect& rect) {
- this->drawRect(ds, color, viewM, rect, NULL, NULL);
+ this->drawBWRect(ds, color, viewM, rect, NULL, NULL);
}
void drawSimpleRect(GrPipelineBuilder* ds, GrColor color, const SkMatrix& viewM,
const SkIRect& irect) {
SkRect rect = SkRect::Make(irect);
- this->drawRect(ds, color, viewM, rect, NULL, NULL);
+ this->drawBWRect(ds, color, viewM, rect, NULL, NULL);
}
+ void drawAARect(GrPipelineBuilder* pipelineBuilder,
+ GrColor color,
+ const SkMatrix& viewMatrix,
+ const SkRect& rect,
+ const SkRect& devRect);
/**
* Clear the passed in render target. Ignores the GrPipelineBuilder and clip. Clears the whole
*/
#include "GrAtlas.h"
+#include "GrDrawContext.h"
#include "GrGpu.h"
#include "GrLayerCache.h"
#include "GrSurfacePriv.h"
SkASSERT(0 == fPictureHash.count());
- fContext->discardRenderTarget(fAtlas->getTexture()->asRenderTarget());
+ GrDrawContext* drawContext = fContext->drawContext();
+
+ if (drawContext) {
+ drawContext->discard(fAtlas->getTexture()->asRenderTarget());
+ }
}
#endif
///////////////////////////////////////////////////////////////////////////////
-bool GrOvalRenderer::drawOval(GrDrawTarget* target,
+bool GrOvalRenderer::DrawOval(GrDrawTarget* target,
GrPipelineBuilder* pipelineBuilder,
GrColor color,
const SkMatrix& viewMatrix,
// we can draw circles
if (SkScalarNearlyEqual(oval.width(), oval.height()) && circle_stays_circle(viewMatrix)) {
- this->drawCircle(target, pipelineBuilder, color, viewMatrix, useCoverageAA, oval, stroke);
+ DrawCircle(target, pipelineBuilder, color, viewMatrix, useCoverageAA, oval, stroke);
// if we have shader derivative support, render as device-independent
} else if (target->caps()->shaderCaps()->shaderDerivativeSupport()) {
- return this->drawDIEllipse(target, pipelineBuilder, color, viewMatrix, useCoverageAA, oval,
- stroke);
+ return DrawDIEllipse(target, pipelineBuilder, color, viewMatrix, useCoverageAA, oval,
+ stroke);
// otherwise axis-aligned ellipses only
} else if (viewMatrix.rectStaysRect()) {
- return this->drawEllipse(target, pipelineBuilder, color, viewMatrix, useCoverageAA, oval,
- stroke);
+ return DrawEllipse(target, pipelineBuilder, color, viewMatrix, useCoverageAA, oval,
+ stroke);
} else {
return false;
}
return CircleBatch::Create(geometry);
}
-void GrOvalRenderer::drawCircle(GrDrawTarget* target,
+void GrOvalRenderer::DrawCircle(GrDrawTarget* target,
GrPipelineBuilder* pipelineBuilder,
GrColor color,
const SkMatrix& viewMatrix,
return EllipseBatch::Create(geometry);
}
-bool GrOvalRenderer::drawEllipse(GrDrawTarget* target,
+bool GrOvalRenderer::DrawEllipse(GrDrawTarget* target,
GrPipelineBuilder* pipelineBuilder,
GrColor color,
const SkMatrix& viewMatrix,
return DIEllipseBatch::Create(geometry, devBounds);
}
-bool GrOvalRenderer::drawDIEllipse(GrDrawTarget* target,
+bool GrOvalRenderer::DrawDIEllipse(GrDrawTarget* target,
GrPipelineBuilder* pipelineBuilder,
GrColor color,
const SkMatrix& viewMatrix,
}
}
-bool GrOvalRenderer::drawDRRect(GrDrawTarget* target,
+bool GrOvalRenderer::DrawDRRect(GrDrawTarget* target,
GrPipelineBuilder* pipelineBuilder,
GrColor color,
const SkMatrix& viewMatrix,
}
SkStrokeRec fillRec(SkStrokeRec::kFill_InitStyle);
- if (this->drawRRect(target, pipelineBuilder, color, viewMatrix, useAA, origOuter, fillRec)) {
+ if (DrawRRect(target, pipelineBuilder, color, viewMatrix, useAA, origOuter, fillRec)) {
return true;
}
if (applyAA) {
bounds.outset(SK_ScalarHalf, SK_ScalarHalf);
}
- target->drawRect(pipelineBuilder, color, SkMatrix::I(), bounds, NULL, &invert);
+ target->drawBWRect(pipelineBuilder, color, SkMatrix::I(), bounds, NULL, &invert);
return true;
}
}
}
-bool GrOvalRenderer::drawRRect(GrDrawTarget* target,
+bool GrOvalRenderer::DrawRRect(GrDrawTarget* target,
GrPipelineBuilder* pipelineBuilder,
GrColor color,
const SkMatrix& viewMatrix,
const SkRRect& rrect,
const SkStrokeRec& stroke) {
if (rrect.isOval()) {
- return this->drawOval(target, pipelineBuilder, color, viewMatrix, useAA, rrect.getBounds(),
- stroke);
+ return DrawOval(target, pipelineBuilder, color, viewMatrix, useAA, rrect.getBounds(),
+ stroke);
}
bool useCoverageAA = useAA && !pipelineBuilder->getRenderTarget()->isMultisampled();
#ifndef GrOvalRenderer_DEFINED
#define GrOvalRenderer_DEFINED
-#include "GrContext.h"
#include "GrPaint.h"
-class GrContext;
class GrDrawTarget;
-class GrPaint;
+class GrPipelineBuilder;
struct SkRect;
class SkStrokeRec;
/*
* This class wraps helper functions that draw ovals and roundrects (filled & stroked)
*/
-class GrOvalRenderer : public SkRefCnt {
+class GrOvalRenderer {
public:
- SK_DECLARE_INST_COUNT(GrOvalRenderer)
-
- bool drawOval(GrDrawTarget*,
- GrPipelineBuilder*,
- GrColor,
- const SkMatrix& viewMatrix,
- bool useAA,
- const SkRect& oval,
- const SkStrokeRec& stroke);
- bool drawRRect(GrDrawTarget*,
- GrPipelineBuilder*,
- GrColor,
- const SkMatrix& viewMatrix,
- bool useAA,
- const SkRRect& rrect,
- const SkStrokeRec& stroke);
- bool drawDRRect(GrDrawTarget* target,
- GrPipelineBuilder*,
- GrColor,
- const SkMatrix& viewMatrix,
- bool useAA,
- const SkRRect& outer,
- const SkRRect& inner);
+ static bool DrawOval(GrDrawTarget*,
+ GrPipelineBuilder*,
+ GrColor,
+ const SkMatrix& viewMatrix,
+ bool useAA,
+ const SkRect& oval,
+ const SkStrokeRec& stroke);
+ static bool DrawRRect(GrDrawTarget*,
+ GrPipelineBuilder*,
+ GrColor,
+ const SkMatrix& viewMatrix,
+ bool useAA,
+ const SkRRect& rrect,
+ const SkStrokeRec& stroke);
+ static bool DrawDRRect(GrDrawTarget* target,
+ GrPipelineBuilder*,
+ GrColor,
+ const SkMatrix& viewMatrix,
+ bool useAA,
+ const SkRRect& outer,
+ const SkRRect& inner);
private:
- bool drawEllipse(GrDrawTarget* target,
- GrPipelineBuilder*,
- GrColor,
- const SkMatrix& viewMatrix,
- bool useCoverageAA,
- const SkRect& ellipse,
- const SkStrokeRec& stroke);
- bool drawDIEllipse(GrDrawTarget* target,
- GrPipelineBuilder*,
- GrColor,
- const SkMatrix& viewMatrix,
- bool useCoverageAA,
- const SkRect& ellipse,
- const SkStrokeRec& stroke);
- void drawCircle(GrDrawTarget* target,
- GrPipelineBuilder*,
- GrColor,
- const SkMatrix& viewMatrix,
- bool useCoverageAA,
- const SkRect& circle,
- const SkStrokeRec& stroke);
+ GrOvalRenderer();
- typedef SkRefCnt INHERITED;
+ static bool DrawEllipse(GrDrawTarget* target,
+ GrPipelineBuilder*,
+ GrColor,
+ const SkMatrix& viewMatrix,
+ bool useCoverageAA,
+ const SkRect& ellipse,
+ const SkStrokeRec& stroke);
+ static bool DrawDIEllipse(GrDrawTarget* target,
+ GrPipelineBuilder*,
+ GrColor,
+ const SkMatrix& viewMatrix,
+ bool useCoverageAA,
+ const SkRect& ellipse,
+ const SkStrokeRec& stroke);
+ static void DrawCircle(GrDrawTarget* target,
+ GrPipelineBuilder*,
+ GrColor,
+ const SkMatrix& viewMatrix,
+ bool useCoverageAA,
+ const SkRect& circle,
+ const SkStrokeRec& stroke);
};
#endif // GrOvalRenderer_DEFINED
#include "GrRenderTarget.h"
#include "GrContext.h"
+#include "GrDrawContext.h"
#include "GrGpu.h"
#include "GrRenderTargetPriv.h"
#include "GrStencilAttachment.h"
void GrRenderTarget::discard() {
// go through context so that all necessary flushing occurs
GrContext* context = this->getContext();
- if (NULL == context) {
+ GrDrawContext* drawContext = context ? context->drawContext() : NULL;
+ if (!drawContext) {
return;
}
- context->discardRenderTarget(this);
+
+ drawContext->discard(this);
}
void GrRenderTarget::flagAsNeedingResolve(const SkIRect* rect) {
GrTextureParams::kNone_FilterMode,
kDevice_GrCoordSet))->unref();
- target->drawRect(pipelineBuilder, color, SkMatrix::I(), dstRect, NULL, &invert);
+ target->drawBWRect(pipelineBuilder, color, SkMatrix::I(), dstRect, NULL, &invert);
}
if (devClipBounds.fTop < devPathBounds.fTop) {
rect.iset(devClipBounds.fLeft, devClipBounds.fTop,
devClipBounds.fRight, devPathBounds.fTop);
- target->drawRect(pipelineBuilder, color, SkMatrix::I(), rect, NULL, &invert);
+ target->drawBWRect(pipelineBuilder, color, SkMatrix::I(), rect, NULL, &invert);
}
if (devClipBounds.fLeft < devPathBounds.fLeft) {
rect.iset(devClipBounds.fLeft, devPathBounds.fTop,
devPathBounds.fLeft, devPathBounds.fBottom);
- target->drawRect(pipelineBuilder, color, SkMatrix::I(), rect, NULL, &invert);
+ target->drawBWRect(pipelineBuilder, color, SkMatrix::I(), rect, NULL, &invert);
}
if (devClipBounds.fRight > devPathBounds.fRight) {
rect.iset(devPathBounds.fRight, devPathBounds.fTop,
devClipBounds.fRight, devPathBounds.fBottom);
- target->drawRect(pipelineBuilder, color, SkMatrix::I(), rect, NULL, &invert);
+ target->drawBWRect(pipelineBuilder, color, SkMatrix::I(), rect, NULL, &invert);
}
if (devClipBounds.fBottom > devPathBounds.fBottom) {
rect.iset(devClipBounds.fLeft, devPathBounds.fBottom,
devClipBounds.fRight, devClipBounds.fBottom);
- target->drawRect(pipelineBuilder, color, SkMatrix::I(), rect, NULL, &invert);
+ target->drawBWRect(pipelineBuilder, color, SkMatrix::I(), rect, NULL, &invert);
}
}
}
}
const SkMatrix& viewM = viewMatrix.hasPerspective() ? SkMatrix::I() : viewMatrix;
- target->drawRect(pipelineBuilder, color, viewM, bounds, NULL, &invert);
+ target->drawBWRect(pipelineBuilder, color, viewM, bounds, NULL, &invert);
} else {
GR_STATIC_CONST_SAME_STENCIL(kStencilPass,
kZero_StencilOp,
#include "GrStencilAndCoverTextContext.h"
#include "GrAtlasTextContext.h"
+#include "GrDrawContext.h"
#include "GrDrawTarget.h"
#include "GrPath.h"
#include "GrPathRange.h"
SkAutoTUnref<GrPathProcessor> pp(GrPathProcessor::Create(fPaint.getColor(),
fViewMatrix,
fLocalMatrix));
- fDrawTarget->drawPaths(&fPipelineBuilder, pp, fGlyphs,
+
+ GrDrawContext* drawContext = fContext->drawContext();
+ if (!drawContext) {
+ return;
+ }
+
+ drawContext->drawPaths(&fPipelineBuilder, pp, fGlyphs,
fGlyphIndices, GrPathRange::kU16_PathIndexType,
get_xy_scalar_array(fGlyphPositions),
GrPathRendering::kTranslate_PathTransformType,
fPipelineBuilder.stencil()->setDisabled();
fStateRestore.set(NULL);
fViewMatrix = fContextInitialMatrix;
- GrTextContext::finish();
}
// then disconnects. This would help prevent test writers from mixing using the returned
// GrDrawTarget and regular drawing. We could also assert or fail in GrContext drawing methods
// until ~GrTestTarget().
- tar->init(this, fDrawBuffer);
+ tar->init(this, fDrawingMgr.fDrawTarget);
}
///////////////////////////////////////////////////////////////////////////////
// We delete these because we want to test the cache starting with zero resources. Also, none of
// these objects are required for any of tests that use this context. TODO: make stop allocating
// resources in the buffer pools.
- SkDELETE(fDrawBuffer);
- fDrawBuffer = NULL;
-
+ fDrawingMgr.abandon();
}
: fFallbackTextContext(NULL)
, fContext(context)
, fGpuDevice(gpuDevice)
- , fDeviceProperties(properties)
- , fDrawTarget(NULL) {
+ , fDeviceProperties(properties) {
}
GrTextContext::~GrTextContext() {
fRegionClipBounds = regionClipBounds;
fClip.getConservativeBounds(fRenderTarget->width(), fRenderTarget->height(), &fClipRect);
- fDrawTarget = fContext->getTextTarget();
-
fPaint = grPaint;
fSkPaint = skPaint;
}
const SkPaint& skPaint, const SkMatrix& viewMatrix,
const char text[], size_t byteLength,
SkScalar x, SkScalar y, const SkIRect& clipBounds) {
- if (!fContext->getTextTarget()) {
+ if (fContext->abandoned()) {
return;
}
const char text[], size_t byteLength,
const SkScalar pos[], int scalarsPerPosition,
const SkPoint& offset, const SkIRect& clipBounds) {
- if (!fContext->getTextTarget()) {
+ if (fContext->abandoned()) {
return;
}
SkAutoTUnref<GrRenderTarget> fRenderTarget;
GrClip fClip;
- GrDrawTarget* fDrawTarget;
SkIRect fClipRect;
SkIRect fRegionClipBounds;
GrPaint fPaint;
void init(GrRenderTarget*, const GrClip&, const GrPaint&, const SkPaint&,
const SkIRect& regionClipBounds);
- void finish() { fDrawTarget = NULL; }
static GrFontScaler* GetGrFontScaler(SkGlyphCache* cache);
// sets extent in stopVector and returns glyph count
#include "SkGpuDevice.h"
#include "GrContext.h"
+#include "GrDrawContext.h"
#include "GrGpu.h"
#include "GrGpuResourcePriv.h"
#include "GrLayerHoister.h"
bool useDFT = fSurfaceProps.isUseDistanceFieldFonts();
fTextContext = fContext->createTextContext(fRenderTarget, this, this->getLeakyProperties(),
useDFT);
+ fDrawContext.reset(SkRef(fContext->drawContext()));
}
GrRenderTarget* SkGpuDevice::CreateRenderTarget(GrContext* context, SkSurface::Budgeted budgeted,
delete fDrawProcs;
}
- delete fTextContext;
+ SkDELETE(fTextContext);
fRenderTarget->unref();
fContext->unref();
GrColor color = 0;
GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice::clearAll", fContext);
SkIRect rect = SkIRect::MakeWH(this->width(), this->height());
- fContext->clear(&rect, color, true, fRenderTarget);
+ fDrawContext->clear(fRenderTarget, &rect, color, true);
fNeedClear = false;
}
SkASSERT(fRenderTarget->surfacePriv().info() == fLegacyBitmap.info());
SkPixelRef* pr = SkNEW_ARGS(SkGrPixelRef, (fRenderTarget->surfacePriv().info(), fRenderTarget));
fLegacyBitmap.setPixelRef(pr)->unref();
+
+ fDrawContext.reset(SkRef(fRenderTarget->getContext()->drawContext()));
}
///////////////////////////////////////////////////////////////////////////////
return;
}
- fContext->drawPaint(fRenderTarget, fClip, grPaint, *draw.fMatrix);
+ fDrawContext->drawPaint(fRenderTarget, fClip, grPaint, *draw.fMatrix);
}
// must be in SkCanvas::PointMode order
path.setIsVolatile(true);
path.moveTo(pts[0]);
path.lineTo(pts[1]);
- fContext->drawPath(fRenderTarget, fClip, grPaint, *draw.fMatrix, path, strokeInfo);
+ fDrawContext->drawPath(fRenderTarget, fClip, grPaint, *draw.fMatrix, path, strokeInfo);
return;
}
return;
}
- fContext->drawVertices(fRenderTarget,
- fClip,
- grPaint,
- *draw.fMatrix,
- gPointMode2PrimtiveType[mode],
- SkToS32(count),
- (SkPoint*)pts,
- NULL,
- NULL,
- NULL,
- 0);
+ fDrawContext->drawVertices(fRenderTarget,
+ fClip,
+ grPaint,
+ *draw.fMatrix,
+ gPointMode2PrimtiveType[mode],
+ SkToS32(count),
+ (SkPoint*)pts,
+ NULL,
+ NULL,
+ NULL,
+ 0);
}
///////////////////////////////////////////////////////////////////////////////
return;
}
- fContext->drawRect(fRenderTarget, fClip, grPaint, *draw.fMatrix, rect, &strokeInfo);
+ fDrawContext->drawRect(fRenderTarget, fClip, grPaint, *draw.fMatrix, rect, &strokeInfo);
}
///////////////////////////////////////////////////////////////////////////////
return;
}
- fContext->drawRRect(fRenderTarget, fClip, grPaint, *draw.fMatrix, rect, strokeInfo);
+ fDrawContext->drawRRect(fRenderTarget, fClip, grPaint, *draw.fMatrix, rect, strokeInfo);
}
void SkGpuDevice::drawDRRect(const SkDraw& draw, const SkRRect& outer,
}
if (NULL == paint.getMaskFilter() && NULL == paint.getPathEffect()) {
- fContext->drawDRRect(fRenderTarget, fClip, grPaint, *draw.fMatrix, outer, inner);
+ fDrawContext->drawDRRect(fRenderTarget, fClip, grPaint, *draw.fMatrix, outer, inner);
return;
}
}
return;
}
- fContext->drawOval(fRenderTarget, fClip, grPaint, *draw.fMatrix, oval, strokeInfo);
+ fDrawContext->drawOval(fRenderTarget, fClip, grPaint, *draw.fMatrix, oval, strokeInfo);
}
#include "SkMaskFilter.h"
// Draw a mask using the supplied paint. Since the coverage/geometry
// is already burnt into the mask this boils down to a rect draw.
// Return true if the mask was successfully drawn.
-bool draw_mask(GrContext* context,
+bool draw_mask(GrDrawContext* drawContext,
GrRenderTarget* rt,
const GrClip& clip,
const SkMatrix& viewMatrix,
if (!viewMatrix.invert(&inverse)) {
return false;
}
- context->drawNonAARectWithLocalMatrix(rt, clip, *grp, SkMatrix::I(), maskRect, inverse);
+ drawContext->drawNonAARectWithLocalMatrix(rt, clip, *grp, SkMatrix::I(), maskRect, inverse);
return true;
}
return clipBounds.isEmpty() || rect.isEmpty() || !SkIRect::Intersects(clipBounds, rect);
}
-bool draw_with_mask_filter(GrContext* context,
+bool draw_with_mask_filter(GrDrawContext* drawContext,
+ GrTextureProvider* textureProvider,
GrRenderTarget* rt,
const GrClip& clipData,
const SkMatrix& viewMatrix,
desc.fHeight = dstM.fBounds.height();
desc.fConfig = kAlpha_8_GrPixelConfig;
- SkAutoTUnref<GrTexture> texture(context->textureProvider()->refScratchTexture(
+ SkAutoTUnref<GrTexture> texture(textureProvider->refScratchTexture(
desc, GrTextureProvider::kApprox_ScratchTexMatch));
if (!texture) {
return false;
SkRect maskRect = SkRect::Make(dstM.fBounds);
- return draw_mask(context, rt, clipData, viewMatrix, maskRect, grp, texture);
+ return draw_mask(drawContext, rt, clipData, viewMatrix, maskRect, grp, texture);
}
// Create a mask of 'devPath' and place the result in 'mask'.
GrTexture* create_mask_GPU(GrContext* context,
- GrRenderTarget* rt,
const SkRect& maskRect,
const SkPath& devPath,
const GrStrokeInfo& strokeInfo,
SkRect clipRect = SkRect::MakeWH(maskRect.width(), maskRect.height());
- context->clear(NULL, 0x0, true, mask->asRenderTarget());
+ GrDrawContext* drawContext = context->drawContext();
+ if (!drawContext) {
+ return NULL;
+ }
+
+ drawContext->clear(mask->asRenderTarget(), NULL, 0x0, true);
GrPaint tempPaint;
tempPaint.setAntiAlias(doAA);
// Draw the mask into maskTexture with the path's top-left at the origin using tempPaint.
SkMatrix translate;
translate.setTranslate(-maskRect.fLeft, -maskRect.fTop);
- context->drawPath(mask->asRenderTarget(), clip, tempPaint, translate, devPath, strokeInfo);
+ drawContext->drawPath(mask->asRenderTarget(), clip, tempPaint, translate, devPath, strokeInfo);
return mask;
}
SkAutoTUnref<GrTexture> mask(create_mask_GPU(fContext,
- fRenderTarget,
maskRect,
*devPathPtr,
strokeInfo,
if (paint.getMaskFilter()->filterMaskGPU(mask, viewMatrix, maskRect, &filtered, true)) {
// filterMaskGPU gives us ownership of a ref to the result
SkAutoTUnref<GrTexture> atu(filtered);
- if (draw_mask(fContext,
+ if (draw_mask(fDrawContext,
fRenderTarget,
fClip,
viewMatrix,
// GPU path fails
SkPaint::Style style = strokeInfo.isHairlineStyle() ? SkPaint::kStroke_Style :
SkPaint::kFill_Style;
- draw_with_mask_filter(fContext, fRenderTarget, fClip, viewMatrix, *devPathPtr,
+ draw_with_mask_filter(fDrawContext, fContext->textureProvider(), fRenderTarget,
+ fClip, viewMatrix, *devPathPtr,
paint.getMaskFilter(), clipBounds, &grPaint, style);
return;
}
- fContext->drawPath(fRenderTarget, fClip, grPaint, viewMatrix, *pathPtr, strokeInfo);
+ fDrawContext->drawPath(fRenderTarget, fClip, grPaint, viewMatrix, *pathPtr, strokeInfo);
}
static const int kBmpSmallTileSize = 1 << 10;
return;
}
- fContext->drawNonAARectToRect(fRenderTarget, fClip, grPaint, viewMatrix, dstRect,
- paintRect);
+ fDrawContext->drawNonAARectToRect(fRenderTarget, fClip, grPaint, viewMatrix, dstRect,
+ paintRect);
}
bool SkGpuDevice::filterTexture(GrContext* context, GrTexture* texture,
return;
}
- fContext->drawNonAARectToRect(fRenderTarget,
- fClip,
- grPaint,
- SkMatrix::I(),
- SkRect::MakeXYWH(SkIntToScalar(left),
- SkIntToScalar(top),
- SkIntToScalar(w),
- SkIntToScalar(h)),
- SkRect::MakeXYWH(0,
- 0,
- SK_Scalar1 * w / texture->width(),
- SK_Scalar1 * h / texture->height()));
+ fDrawContext->drawNonAARectToRect(fRenderTarget,
+ fClip,
+ grPaint,
+ SkMatrix::I(),
+ SkRect::MakeXYWH(SkIntToScalar(left),
+ SkIntToScalar(top),
+ SkIntToScalar(w),
+ SkIntToScalar(h)),
+ SkRect::MakeXYWH(0,
+ 0,
+ SK_Scalar1 * w / texture->width(),
+ SK_Scalar1 * h / texture->height()));
}
void SkGpuDevice::drawBitmapRect(const SkDraw& origDraw, const SkBitmap& bitmap,
SkRect srcRect = SkRect::MakeWH(SK_Scalar1 * w / devTex->width(),
SK_Scalar1 * h / devTex->height());
- fContext->drawNonAARectToRect(fRenderTarget, fClip, grPaint, SkMatrix::I(), dstRect,
- srcRect);
+ fDrawContext->drawNonAARectToRect(fRenderTarget, fClip, grPaint, SkMatrix::I(), dstRect,
+ srcRect);
}
bool SkGpuDevice::canHandleImageFilter(const SkImageFilter* filter) {
}
colors = convertedColors.get();
}
- fContext->drawVertices(fRenderTarget,
- fClip,
- grPaint,
- *draw.fMatrix,
- primType,
- vertexCount,
- vertices,
- texs,
- colors,
- outIndices,
- indexCount);
+ fDrawContext->drawVertices(fRenderTarget,
+ fClip,
+ grPaint,
+ *draw.fMatrix,
+ primType,
+ vertexCount,
+ vertices,
+ texs,
+ colors,
+ outIndices,
+ indexCount);
}
///////////////////////////////////////////////////////////////////////////////
SkIPoint fClipOrigin;
GrClip fClip;
GrTextContext* fTextContext;
+ SkAutoTUnref<GrDrawContext> fDrawContext;
SkSurfaceProps fSurfaceProps;
GrRenderTarget* fRenderTarget;
// remove when our clients don't rely on accessBitmap()
#include "SkGr.h"
+#include "GrDrawContext.h"
#include "GrXferProcessor.h"
#include "SkColorFilter.h"
#include "SkConfig8888.h"
SkRect rect = SkRect::MakeWH(SkIntToScalar(rtDesc.fWidth), SkIntToScalar(rtDesc.fHeight));
SkRect localRect = SkRect::MakeWH(1.f, 1.f);
- context->drawNonAARectToRect(stretched->asRenderTarget(), GrClip::WideOpen(), paint,
- SkMatrix::I(), rect, localRect);
+ GrDrawContext* drawContext = context->drawContext();
+ if (!drawContext) {
+ return NULL;
+ }
+
+ drawContext->drawNonAARectToRect(stretched->asRenderTarget(), GrClip::WideOpen(), paint,
+ SkMatrix::I(), rect, localRect);
return stretched;
}
SkRect r = SkRect::MakeWH(SkIntToScalar(yuvInfo.fSize[0].fWidth),
SkIntToScalar(yuvInfo.fSize[0].fHeight));
- ctx->drawRect(renderTarget, GrClip::WideOpen(), paint, SkMatrix::I(), r);
+ GrDrawContext* drawContext = ctx->drawContext();
+ if (!drawContext) {
+ return NULL;
+ }
+
+ drawContext->drawRect(renderTarget, GrClip::WideOpen(), paint, SkMatrix::I(), r);
return result;
}
#include "GrConfigConversionEffect.h"
#include "GrContext.h"
+#include "GrDrawContext.h"
#include "GrInvariantOutput.h"
#include "GrSimpleTextureEffect.h"
#include "SkMatrix.h"
bool failed = true;
+ GrDrawContext* drawContext = context->drawContext();
+ if (!drawContext) {
+ return;
+ }
+
for (size_t i = 0; i < SK_ARRAY_COUNT(kConversionRules) && failed; ++i) {
*pmToUPMRule = kConversionRules[i][0];
*upmToPMRule = kConversionRules[i][1];
GrPaint paint1;
paint1.addColorProcessor(pmToUPM1);
- context->drawNonAARectToRect(readTex->asRenderTarget(),
- GrClip::WideOpen(),
- paint1,
- SkMatrix::I(),
- kDstRect,
- kSrcRect);
+ drawContext->drawNonAARectToRect(readTex->asRenderTarget(),
+ GrClip::WideOpen(),
+ paint1,
+ SkMatrix::I(),
+ kDstRect,
+ kSrcRect);
readTex->readPixels(0, 0, 256, 256, kRGBA_8888_GrPixelConfig, firstRead);
GrPaint paint2;
paint2.addColorProcessor(upmToPM);
- context->drawNonAARectToRect(tempTex->asRenderTarget(),
- GrClip::WideOpen(),
- paint2,
- SkMatrix::I(),
- kDstRect,
- kSrcRect);
+ drawContext->drawNonAARectToRect(tempTex->asRenderTarget(),
+ GrClip::WideOpen(),
+ paint2,
+ SkMatrix::I(),
+ kDstRect,
+ kSrcRect);
GrPaint paint3;
paint3.addColorProcessor(pmToUPM2);
- context->drawNonAARectToRect(readTex->asRenderTarget(),
- GrClip::WideOpen(),
- paint3,
- SkMatrix::I(),
- kDstRect,
- kSrcRect);
+ drawContext->drawNonAARectToRect(readTex->asRenderTarget(),
+ GrClip::WideOpen(),
+ paint3,
+ SkMatrix::I(),
+ kDstRect,
+ kSrcRect);
readTex->readPixels(0, 0, 256, 256, kRGBA_8888_GrPixelConfig, secondRead);