| Index: src/gpu/GrDrawContext.cpp
|
| diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrDrawContext.cpp
|
| old mode 100755
|
| new mode 100644
|
| similarity index 50%
|
| copy from src/gpu/GrContext.cpp
|
| copy to src/gpu/GrDrawContext.cpp
|
| index 3ed0b6baa26fc37c9483c44b0fa9b30aee85dd7b..3fe3f867199f8ed990cc670288d9fb5b70cf0375
|
| --- a/src/gpu/GrContext.cpp
|
| +++ b/src/gpu/GrDrawContext.cpp
|
| @@ -1,306 +1,96 @@
|
|
|
| /*
|
| - * Copyright 2011 Google Inc.
|
| + * 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 "GrContext.h"
|
| -
|
| #include "GrAARectRenderer.h"
|
| -#include "GrAtlasTextContext.h"
|
| #include "GrBatch.h"
|
| -#include "GrBatchFontCache.h"
|
| -#include "GrBatchTarget.h"
|
| #include "GrBatchTest.h"
|
| -#include "GrCaps.h"
|
| -#include "GrContextOptions.h"
|
| #include "GrDefaultGeoProcFactory.h"
|
| -#include "GrGpuResource.h"
|
| -#include "GrGpuResourcePriv.h"
|
| -#include "GrGpu.h"
|
| -#include "GrImmediateDrawTarget.h"
|
| -#include "GrIndexBuffer.h"
|
| -#include "GrInOrderDrawBuffer.h"
|
| -#include "GrLayerCache.h"
|
| +#include "GrDrawContext.h"
|
| #include "GrOvalRenderer.h"
|
| #include "GrPathRenderer.h"
|
| -#include "GrPathUtils.h"
|
| -#include "GrRenderTargetPriv.h"
|
| -#include "GrResourceCache.h"
|
| -#include "GrResourceProvider.h"
|
| -#include "GrSoftwarePathRenderer.h"
|
| -#include "GrStencilAndCoverTextContext.h"
|
| -#include "GrStrokeInfo.h"
|
| -#include "GrSurfacePriv.h"
|
| -#include "GrTextBlobCache.h"
|
| -#include "GrTexturePriv.h"
|
| -#include "GrTraceMarker.h"
|
| -#include "GrTracing.h"
|
| -#include "GrVertices.h"
|
| -#include "SkDashPathPriv.h"
|
| -#include "SkConfig8888.h"
|
| -#include "SkGr.h"
|
| -#include "SkRRect.h"
|
| -#include "SkStrokeRec.h"
|
| -#include "SkTLazy.h"
|
| -#include "SkTLS.h"
|
| -#include "SkTraceEvent.h"
|
| -
|
| -#include "effects/GrConfigConversionEffect.h"
|
| -#include "effects/GrDashingEffect.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; }
|
| -
|
| -class GrContext::AutoCheckFlush {
|
| +
|
| +#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() {
|
| - if (fContext->fFlushToReduceCacheSize) {
|
| - fContext->flush();
|
| - }
|
| - }
|
| + ~AutoCheckFlush() { fContext->flushIfNecessary(); }
|
|
|
| private:
|
| GrContext* fContext;
|
| };
|
|
|
| -GrContext* GrContext::Create(GrBackend backend, GrBackendContext backendContext) {
|
| - GrContextOptions defaultOptions;
|
| - return Create(backend, backendContext, defaultOptions);
|
| -}
|
| -
|
| -GrContext* GrContext::Create(GrBackend backend, GrBackendContext backendContext,
|
| - const GrContextOptions& options) {
|
| - GrContext* context = SkNEW(GrContext);
|
| -
|
| - if (context->init(backend, backendContext, options)) {
|
| - return context;
|
| - } else {
|
| - context->unref();
|
| - return NULL;
|
| - }
|
| +GrDrawContext::GrDrawContext(GrContext* context, GrDrawTarget* drawTarget)
|
| + : fContext(context)
|
| + , fDrawTarget(SkRef(drawTarget)) {
|
| }
|
|
|
| -static int32_t gNextID = 1;
|
| -static int32_t next_id() {
|
| - int32_t id;
|
| - do {
|
| - id = sk_atomic_inc(&gNextID);
|
| - } while (id == SK_InvalidGenID);
|
| - return id;
|
| -}
|
| -
|
| -GrContext::GrContext() : fUniqueID(next_id()) {
|
| - fGpu = NULL;
|
| - fResourceCache = NULL;
|
| - fResourceProvider = NULL;
|
| - 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);
|
| -
|
| - fGpu = GrGpu::Create(backend, backendContext, options, this);
|
| - if (NULL == fGpu) {
|
| - return false;
|
| - }
|
| - this->initCommon();
|
| - return true;
|
| -}
|
| -
|
| -void GrContext::initCommon() {
|
| - fResourceCache = SkNEW(GrResourceCache);
|
| - fResourceCache->setOverBudgetCallback(OverBudgetCB, this);
|
| - fResourceProvider = SkNEW_ARGS(GrResourceProvider, (fGpu, fResourceCache));
|
| -
|
| - 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
|
| -
|
| - // GrBatchFontCache will eventually replace GrFontCache
|
| - fBatchFontCache = SkNEW_ARGS(GrBatchFontCache, (this));
|
| -
|
| - fTextBlobCache.reset(SkNEW_ARGS(GrTextBlobCache, (TextBlobCacheOverBudgetCB, this)));
|
| -}
|
| -
|
| -GrContext::~GrContext() {
|
| - if (NULL == fGpu) {
|
| +void GrDrawContext::copySurface(GrRenderTarget* dst, GrSurface* src,
|
| + const SkIRect& srcRect, const SkIPoint& dstPoint) {
|
| + if (!this->prepareToDraw(dst)) {
|
| return;
|
| }
|
|
|
| - this->flush();
|
| -
|
| - for (int i = 0; i < fCleanUpData.count(); ++i) {
|
| - (*fCleanUpData[i].fFunc)(this, fCleanUpData[i].fInfo);
|
| - }
|
| -
|
| - SkDELETE(fResourceProvider);
|
| - SkDELETE(fResourceCache);
|
| - SkDELETE(fBatchFontCache);
|
| - SkDELETE(fDrawBuffer);
|
| -
|
| - fAARectRenderer->unref();
|
| - fOvalRenderer->unref();
|
| -
|
| - fGpu->unref();
|
| - SkSafeUnref(fPathRendererChain);
|
| - SkSafeUnref(fSoftwarePathRenderer);
|
| + fDrawTarget->copySurface(dst, src, srcRect, dstPoint);
|
| }
|
|
|
| -void GrContext::abandonContext() {
|
| - fResourceProvider->abandon();
|
| - // abandon first to so destructors
|
| - // don't try to free the resources in the API.
|
| - fResourceCache->abandonAll();
|
| -
|
| - fGpu->contextAbandoned();
|
| -
|
| - // a path renderer may be holding onto resources that
|
| - // are now unusable
|
| - SkSafeSetNull(fPathRendererChain);
|
| - SkSafeSetNull(fSoftwarePathRenderer);
|
| -
|
| - SkDELETE(fDrawBuffer);
|
| - fDrawBuffer = NULL;
|
| -
|
| - fBatchFontCache->freeAll();
|
| - fLayerCache->freeAll();
|
| - fTextBlobCache->freeAll();
|
| +void GrDrawContext::drawText(GrPipelineBuilder* pipelineBuilder, GrBatch* batch) {
|
| + fDrawTarget->drawBatch(pipelineBuilder, batch);
|
| }
|
|
|
| -void GrContext::resetContext(uint32_t state) {
|
| - fGpu->markContextDirty(state);
|
| -}
|
| -
|
| -void GrContext::freeGpuResources() {
|
| - this->flush();
|
| -
|
| - if (fDrawBuffer) {
|
| - fDrawBuffer->purgeResources();
|
| - }
|
| -
|
| - fBatchFontCache->freeAll();
|
| - fLayerCache->freeAll();
|
| - // a path renderer may be holding onto resources
|
| - SkSafeSetNull(fPathRendererChain);
|
| - SkSafeSetNull(fSoftwarePathRenderer);
|
| -
|
| - fResourceCache->purgeAllUnlocked();
|
| +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 GrContext::getResourceCacheUsage(int* resourceCount, size_t* resourceBytes) const {
|
| - if (resourceCount) {
|
| - *resourceCount = fResourceCache->getBudgetedResourceCount();
|
| - }
|
| - if (resourceBytes) {
|
| - *resourceBytes = fResourceCache->getBudgetedResourceBytes();
|
| +void GrDrawContext::discard(GrRenderTarget* renderTarget) {
|
| + RETURN_IF_ABANDONED
|
| + SkASSERT(renderTarget);
|
| + AutoCheckFlush acf(fContext);
|
| + if (!this->prepareToDraw(renderTarget)) {
|
| + return;
|
| }
|
| + fDrawTarget->discard(renderTarget);
|
| }
|
|
|
| -GrTextContext* GrContext::createTextContext(GrRenderTarget* renderTarget,
|
| - SkGpuDevice* gpuDevice,
|
| - const SkDeviceProperties&
|
| - leakyProperties,
|
| - bool enableDistanceFieldFonts) {
|
| - if (fGpu->caps()->shaderCaps()->pathRenderingSupport() && renderTarget->isMultisampled()) {
|
| - GrStencilAttachment* sb = renderTarget->renderTargetPriv().attachStencilAttachment();
|
| - if (sb) {
|
| - return GrStencilAndCoverTextContext::Create(this, gpuDevice, leakyProperties);
|
| - }
|
| - }
|
| -
|
| - return GrAtlasTextContext::Create(this, gpuDevice, leakyProperties, enableDistanceFieldFonts);
|
| -}
|
| -
|
| -////////////////////////////////////////////////////////////////////////////////
|
| -
|
| -bool GrContext::isConfigTexturable(GrPixelConfig config) const {
|
| - return fGpu->caps()->isConfigTexturable(config);
|
| -}
|
| -
|
| -bool GrContext::npotTextureTileSupport() const {
|
| - return fGpu->caps()->npotTextureTileSupport();
|
| -}
|
| -
|
| -void GrContext::OverBudgetCB(void* data) {
|
| - SkASSERT(data);
|
| -
|
| - GrContext* context = reinterpret_cast<GrContext*>(data);
|
| -
|
| - // Flush the InOrderDrawBuffer to possibly free up some textures
|
| - context->fFlushToReduceCacheSize = true;
|
| -}
|
| -
|
| -void GrContext::TextBlobCacheOverBudgetCB(void* data) {
|
| - SkASSERT(data);
|
| -
|
| - // Unlike the GrResourceCache, TextBlobs are drawn at the SkGpuDevice level, therefore they
|
| - // cannot use fFlushTorReduceCacheSize because it uses AutoCheckFlush. The solution is to move
|
| - // drawText calls to below the GrContext level, but this is not trivial because they call
|
| - // drawPath on SkGpuDevice
|
| - GrContext* context = reinterpret_cast<GrContext*>(data);
|
| - context->flush();
|
| -}
|
| -
|
| -int GrContext::getMaxTextureSize() const {
|
| - return SkTMin(fGpu->caps()->maxTextureSize(), fMaxTextureSizeOverride);
|
| -}
|
| -
|
| -int GrContext::getMaxRenderTargetSize() const {
|
| - return fGpu->caps()->maxRenderTargetSize();
|
| -}
|
| -
|
| -int GrContext::getMaxSampleCount() const {
|
| - return fGpu->caps()->maxSampleCount();
|
| -}
|
| -
|
| -///////////////////////////////////////////////////////////////////////////////
|
| -
|
| -void GrContext::clear(const SkIRect* rect,
|
| - const GrColor color,
|
| - bool canIgnoreRect,
|
| - GrRenderTarget* renderTarget) {
|
| +void GrDrawContext::clear(GrRenderTarget* renderTarget,
|
| + const SkIRect* rect,
|
| + const GrColor color,
|
| + bool canIgnoreRect) {
|
| 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) {
|
| + AutoCheckFlush acf(fContext);
|
| + if (!this->prepareToDraw(renderTarget)) {
|
| return;
|
| }
|
| - target->clear(rect, color, canIgnoreRect, renderTarget);
|
| + fDrawTarget->clear(rect, color, canIgnoreRect, renderTarget);
|
| }
|
|
|
| -void GrContext::drawPaint(GrRenderTarget* rt,
|
| - const GrClip& clip,
|
| - const GrPaint& origPaint,
|
| - const SkMatrix& viewMatrix) {
|
| +
|
| +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
|
| @@ -335,25 +125,21 @@ void GrContext::drawPaint(GrRenderTarget* rt,
|
| return;
|
| }
|
|
|
| - AutoCheckFlush acf(this);
|
| + AutoCheckFlush acf(fContext);
|
| GrPipelineBuilder pipelineBuilder;
|
| - GrDrawTarget* target = this->prepareToDraw(&pipelineBuilder, rt, clip, paint, &acf);
|
| - if (NULL == target) {
|
| + if (!this->prepareToDraw(&pipelineBuilder, rt, clip, paint)) {
|
| return;
|
| }
|
|
|
| - GR_CREATE_TRACE_MARKER("GrContext::drawPaintWithPerspective", target);
|
| - target->drawRect(&pipelineBuilder,
|
| - paint->getColor(),
|
| - SkMatrix::I(),
|
| - r,
|
| - NULL,
|
| - &localMatrix);
|
| + 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);
|
| @@ -573,12 +359,12 @@ private:
|
| 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) {
|
| +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;
|
| @@ -588,14 +374,12 @@ void GrContext::drawRect(GrRenderTarget* rt,
|
| return;
|
| }
|
|
|
| - AutoCheckFlush acf(this);
|
| + AutoCheckFlush acf(fContext);
|
| GrPipelineBuilder pipelineBuilder;
|
| - GrDrawTarget* target = this->prepareToDraw(&pipelineBuilder, rt, clip, &paint, &acf);
|
| - if (NULL == target) {
|
| + if (!this->prepareToDraw(&pipelineBuilder, rt, clip, &paint)) {
|
| 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
|
| @@ -625,7 +409,7 @@ void GrContext::drawRect(GrRenderTarget* rt,
|
| // Will it blend?
|
| GrColor clearColor;
|
| if (paint.isOpaqueAndConstantColor(&clearColor)) {
|
| - target->clear(NULL, clearColor, true, rt);
|
| + fDrawTarget->clear(NULL, clearColor, true, rt);
|
| return;
|
| }
|
| }
|
| @@ -635,26 +419,26 @@ void GrContext::drawRect(GrRenderTarget* rt,
|
| 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);
|
| + bool doAA = needAA && apply_aa_to_rect(fDrawTarget, &pipelineBuilder, &devBoundRect, rect,
|
| + width, viewMatrix, color);
|
|
|
| if (doAA) {
|
| if (width >= 0) {
|
| - fAARectRenderer->strokeAARect(target,
|
| - &pipelineBuilder,
|
| - color,
|
| - viewMatrix,
|
| - rect,
|
| - devBoundRect,
|
| - *strokeInfo);
|
| + GrAARectRenderer::StrokeAARect(fDrawTarget,
|
| + &pipelineBuilder,
|
| + color,
|
| + viewMatrix,
|
| + rect,
|
| + devBoundRect,
|
| + *strokeInfo);
|
| } else {
|
| // filled AA rect
|
| - fAARectRenderer->fillAARect(target,
|
| - &pipelineBuilder,
|
| - color,
|
| - viewMatrix,
|
| - rect,
|
| - devBoundRect);
|
| + GrAARectRenderer::FillAARect(fDrawTarget,
|
| + &pipelineBuilder,
|
| + color,
|
| + viewMatrix,
|
| + rect,
|
| + devBoundRect);
|
| }
|
| return;
|
| }
|
| @@ -675,36 +459,33 @@ void GrContext::drawRect(GrRenderTarget* rt,
|
| // is enabled because it can cause ugly artifacts.
|
| pipelineBuilder.setState(GrPipelineBuilder::kSnapVerticesToPixelCenters_Flag,
|
| snapToPixelCenters);
|
| - target->drawBatch(&pipelineBuilder, batch);
|
| + fDrawTarget->drawBatch(&pipelineBuilder, batch);
|
| } else {
|
| // filled BW rect
|
| - target->drawSimpleRect(&pipelineBuilder, color, viewMatrix, rect);
|
| + fDrawTarget->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) {
|
| +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(this);
|
| + AutoCheckFlush acf(fContext);
|
| GrPipelineBuilder pipelineBuilder;
|
| - GrDrawTarget* target = this->prepareToDraw(&pipelineBuilder, rt, clip, &paint, &acf);
|
| - if (NULL == target) {
|
| + if (!this->prepareToDraw(&pipelineBuilder, rt, clip, &paint)) {
|
| return;
|
| }
|
|
|
| - GR_CREATE_TRACE_MARKER("GrContext::drawRectToRect", target);
|
| -
|
| - target->drawRect(&pipelineBuilder,
|
| - paint.getColor(),
|
| - viewMatrix,
|
| - rectToDraw,
|
| - &localRect,
|
| - localMatrix);
|
| + fDrawTarget->drawBWRect(&pipelineBuilder,
|
| + paint.getColor(),
|
| + viewMatrix,
|
| + rectToDraw,
|
| + &localRect,
|
| + localMatrix);
|
| }
|
|
|
| static const GrGeometryProcessor* set_vertex_attributes(bool hasLocalCoords,
|
| @@ -978,28 +759,25 @@ private:
|
| 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) {
|
| +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(this);
|
| + AutoCheckFlush acf(fContext);
|
| GrPipelineBuilder pipelineBuilder;
|
|
|
| - GrDrawTarget* target = this->prepareToDraw(&pipelineBuilder, rt, clip, &paint, &acf);
|
| - if (NULL == target) {
|
| + if (!this->prepareToDraw(&pipelineBuilder, rt, clip, &paint)) {
|
| return;
|
| }
|
|
|
| - GR_CREATE_TRACE_MARKER("GrContext::drawVertices", target);
|
| -
|
| // TODO clients should give us bounds
|
| SkRect bounds;
|
| if (!bounds.setBoundsCheck(positions, vertexCount)) {
|
| @@ -1022,17 +800,17 @@ void GrContext::drawVertices(GrRenderTarget* rt,
|
| indexCount, colors, texCoords,
|
| bounds));
|
|
|
| - target->drawBatch(&pipelineBuilder, batch);
|
| + fDrawTarget->drawBatch(&pipelineBuilder, batch);
|
| }
|
|
|
| ///////////////////////////////////////////////////////////////////////////////
|
|
|
| -void GrContext::drawRRect(GrRenderTarget*rt,
|
| - const GrClip& clip,
|
| - const GrPaint& paint,
|
| - const SkMatrix& viewMatrix,
|
| - const SkRRect& rrect,
|
| - const GrStrokeInfo& strokeInfo) {
|
| +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;
|
| @@ -1046,77 +824,75 @@ void GrContext::drawRRect(GrRenderTarget*rt,
|
| return;
|
| }
|
|
|
| - AutoCheckFlush acf(this);
|
| + AutoCheckFlush acf(fContext);
|
| GrPipelineBuilder pipelineBuilder;
|
| - GrDrawTarget* target = this->prepareToDraw(&pipelineBuilder, rt, clip, &paint, &acf);
|
| - if (NULL == target) {
|
| + if (!this->prepareToDraw(&pipelineBuilder, rt, clip, &paint)) {
|
| return;
|
| }
|
|
|
| - GR_CREATE_TRACE_MARKER("GrContext::drawRRect", target);
|
| -
|
| GrColor color = paint.getColor();
|
| - if (!fOvalRenderer->drawRRect(target,
|
| - &pipelineBuilder,
|
| - color,
|
| - viewMatrix,
|
| - paint.isAntiAlias(),
|
| - rrect,
|
| - strokeInfo)) {
|
| + if (!GrOvalRenderer::DrawRRect(fDrawTarget,
|
| + &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);
|
| + this->internalDrawPath(fDrawTarget, &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) {
|
| +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(this);
|
| + AutoCheckFlush acf(fContext);
|
| GrPipelineBuilder pipelineBuilder;
|
| - GrDrawTarget* target = this->prepareToDraw(&pipelineBuilder, rt, clip, &paint, &acf);
|
| -
|
| - GR_CREATE_TRACE_MARKER("GrContext::drawDRRect", target);
|
| + if (!this->prepareToDraw(&pipelineBuilder, rt, clip, &paint)) {
|
| + return;
|
| + }
|
|
|
| GrColor color = paint.getColor();
|
| - if (!fOvalRenderer->drawDRRect(target,
|
| - &pipelineBuilder,
|
| - color,
|
| - viewMatrix,
|
| - paint.isAntiAlias(),
|
| - outer,
|
| - inner)) {
|
| + 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(target, &pipelineBuilder, viewMatrix, color, paint.isAntiAlias(),
|
| - path, fillRec);
|
| + this->internalDrawPath(fDrawTarget, &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) {
|
| +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;
|
| @@ -1130,28 +906,25 @@ void GrContext::drawOval(GrRenderTarget* rt,
|
| return;
|
| }
|
|
|
| - AutoCheckFlush acf(this);
|
| + AutoCheckFlush acf(fContext);
|
| GrPipelineBuilder pipelineBuilder;
|
| - GrDrawTarget* target = this->prepareToDraw(&pipelineBuilder, rt, clip, &paint, &acf);
|
| - if (NULL == target) {
|
| + if (!this->prepareToDraw(&pipelineBuilder, rt, clip, &paint)) {
|
| return;
|
| }
|
|
|
| - GR_CREATE_TRACE_MARKER("GrContext::drawOval", target);
|
| -
|
| GrColor color = paint.getColor();
|
| - if (!fOvalRenderer->drawOval(target,
|
| - &pipelineBuilder,
|
| - color,
|
| - viewMatrix,
|
| - paint.isAntiAlias(),
|
| - oval,
|
| - strokeInfo)) {
|
| + if (!GrOvalRenderer::DrawOval(fDrawTarget,
|
| + &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);
|
| + this->internalDrawPath(fDrawTarget, &pipelineBuilder, viewMatrix, color,
|
| + paint.isAntiAlias(), path, strokeInfo);
|
| }
|
| }
|
|
|
| @@ -1208,12 +981,12 @@ static bool is_nested_rects(GrDrawTarget* target,
|
| return allEq || allGoE1;
|
| }
|
|
|
| -void GrContext::drawPath(GrRenderTarget* rt,
|
| - const GrClip& clip,
|
| - const GrPaint& paint,
|
| - const SkMatrix& viewMatrix,
|
| - const SkPath& path,
|
| - const GrStrokeInfo& strokeInfo) {
|
| +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()) {
|
| @@ -1229,15 +1002,12 @@ void GrContext::drawPath(GrRenderTarget* rt,
|
| // 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);
|
| + AutoCheckFlush acf(fContext);
|
| GrPipelineBuilder pipelineBuilder;
|
| - GrDrawTarget* target = this->prepareToDraw(&pipelineBuilder, rt, clip, &paint, &acf);
|
| - if (NULL == target) {
|
| + if (!this->prepareToDraw(&pipelineBuilder, rt, clip, &paint)) {
|
| return;
|
| }
|
|
|
| - GR_CREATE_TRACE_MARKER1("GrContext::drawPath", target, "Is Convex", path.isConvex());
|
| -
|
| if (!strokeInfo.isDashed()) {
|
| bool useCoverageAA = paint.isAntiAlias() &&
|
| !pipelineBuilder.getRenderTarget()->isMultisampled();
|
| @@ -1246,10 +1016,10 @@ void GrContext::drawPath(GrRenderTarget* rt,
|
| // 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,
|
| + if (is_nested_rects(fDrawTarget, &pipelineBuilder, color, viewMatrix, path, strokeInfo,
|
| rects)) {
|
| - fAARectRenderer->fillAANestedRects(target, &pipelineBuilder, color, viewMatrix,
|
| - rects);
|
| + GrAARectRenderer::FillAANestedRects(fDrawTarget, &pipelineBuilder, color,
|
| + viewMatrix, rects);
|
| return;
|
| }
|
| }
|
| @@ -1257,33 +1027,31 @@ void GrContext::drawPath(GrRenderTarget* rt,
|
| bool isOval = path.isOval(&ovalRect);
|
|
|
| if (isOval && !path.isInverseFillType()) {
|
| - if (fOvalRenderer->drawOval(target,
|
| - &pipelineBuilder,
|
| - color,
|
| - viewMatrix,
|
| - paint.isAntiAlias(),
|
| - ovalRect,
|
| - strokeInfo)) {
|
| + if (GrOvalRenderer::DrawOval(fDrawTarget,
|
| + &pipelineBuilder,
|
| + color,
|
| + viewMatrix,
|
| + paint.isAntiAlias(),
|
| + ovalRect,
|
| + strokeInfo)) {
|
| return;
|
| }
|
| }
|
| }
|
| - this->internalDrawPath(target, &pipelineBuilder, viewMatrix, color, paint.isAntiAlias(),
|
| + this->internalDrawPath(fDrawTarget, &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) {
|
| +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());
|
|
|
| - 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
|
| @@ -1302,8 +1070,8 @@ void GrContext::internalDrawPath(GrDrawTarget* target,
|
| 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);
|
| + GrPathRenderer* pr = fContext->getPathRenderer(target, pipelineBuilder, viewMatrix, *pathPtr,
|
| + *strokeInfoPtr, false, type);
|
|
|
| GrStrokeInfo dashlessStrokeInfo(strokeInfo, false);
|
| if (NULL == pr && strokeInfo.isDashed()) {
|
| @@ -1316,8 +1084,8 @@ void GrContext::internalDrawPath(GrDrawTarget* target,
|
| return;
|
| }
|
| strokeInfoPtr = &dashlessStrokeInfo;
|
| - pr = this->getPathRenderer(target, pipelineBuilder, viewMatrix, *pathPtr, *strokeInfoPtr,
|
| - false, type);
|
| + pr = fContext->getPathRenderer(target, pipelineBuilder, viewMatrix, *pathPtr, *strokeInfoPtr,
|
| + false, type);
|
| }
|
|
|
| if (NULL == pr) {
|
| @@ -1340,8 +1108,8 @@ void GrContext::internalDrawPath(GrDrawTarget* target,
|
| }
|
|
|
| // This time, allow SW renderer
|
| - pr = this->getPathRenderer(target, pipelineBuilder, viewMatrix, *pathPtr, *strokeInfoPtr,
|
| - true, type);
|
| + pr = fContext->getPathRenderer(target, pipelineBuilder, viewMatrix, *pathPtr, *strokeInfoPtr,
|
| + true, type);
|
| }
|
|
|
| if (NULL == pr) {
|
| @@ -1354,523 +1122,24 @@ void GrContext::internalDrawPath(GrDrawTarget* target,
|
| pr->drawPath(target, pipelineBuilder, color, viewMatrix, *pathPtr, *strokeInfoPtr, useCoverageAA);
|
| }
|
|
|
| -////////////////////////////////////////////////////////////////////////////////
|
| -
|
| -void GrContext::flush(int flagsBitfield) {
|
| - if (NULL == fDrawBuffer) {
|
| - return;
|
| - }
|
| -
|
| - if (kDiscard_FlushBit & flagsBitfield) {
|
| - fDrawBuffer->reset();
|
| - } else {
|
| - fDrawBuffer->flush();
|
| - }
|
| - fResourceCache->notifyFlushOccurred();
|
| - fFlushToReduceCacheSize = false;
|
| -}
|
| -
|
| -bool sw_convert_to_premul(GrPixelConfig srcConfig, int width, int height, size_t inRowBytes,
|
| - const void* inPixels, size_t outRowBytes, void* outPixels) {
|
| - SkSrcPixelInfo srcPI;
|
| - if (!GrPixelConfig2ColorAndProfileType(srcConfig, &srcPI.fColorType, NULL)) {
|
| - return false;
|
| - }
|
| - srcPI.fAlphaType = kUnpremul_SkAlphaType;
|
| - srcPI.fPixels = inPixels;
|
| - srcPI.fRowBytes = inRowBytes;
|
| -
|
| - SkDstPixelInfo dstPI;
|
| - dstPI.fColorType = srcPI.fColorType;
|
| - dstPI.fAlphaType = kPremul_SkAlphaType;
|
| - dstPI.fPixels = outPixels;
|
| - dstPI.fRowBytes = outRowBytes;
|
| -
|
| - return srcPI.convertPixelsTo(&dstPI, width, height);
|
| -}
|
| -
|
| -bool GrContext::writeSurfacePixels(GrSurface* surface,
|
| - int left, int top, int width, int height,
|
| - GrPixelConfig srcConfig, const void* buffer, size_t rowBytes,
|
| - uint32_t pixelOpsFlags) {
|
| +bool GrDrawContext::prepareToDraw(GrPipelineBuilder* pipelineBuilder,
|
| + GrRenderTarget* rt,
|
| + const GrClip& clip,
|
| + const GrPaint* paint) {
|
| RETURN_FALSE_IF_ABANDONED
|
| - {
|
| - GrTexture* texture = NULL;
|
| - if (!(kUnpremul_PixelOpsFlag & pixelOpsFlags) && (texture = surface->asTexture()) &&
|
| - fGpu->canWriteTexturePixels(texture, srcConfig)) {
|
| -
|
| - if (!(kDontFlush_PixelOpsFlag & pixelOpsFlags) &&
|
| - surface->surfacePriv().hasPendingIO()) {
|
| - this->flush();
|
| - }
|
| - return fGpu->writeTexturePixels(texture, left, top, width, height,
|
| - srcConfig, buffer, rowBytes);
|
| - // Don't need to check kFlushWrites_PixelOp here, we just did a direct write so the
|
| - // upload is already flushed.
|
| - }
|
| - }
|
| -
|
| - // 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) {
|
| - return false;
|
| - }
|
| -
|
| - // We ignore the preferred config unless it is a R/B swap of the src config. In that case
|
| - // we will upload the original src data to a scratch texture but we will spoof it as the swapped
|
| - // config. This scratch will then have R and B swapped. We correct for this by swapping again
|
| - // when drawing the scratch to the dst using a conversion effect.
|
| - bool swapRAndB = false;
|
| - GrPixelConfig writeConfig = srcConfig;
|
| - if (GrPixelConfigSwapRAndB(srcConfig) ==
|
| - fGpu->preferredWritePixelsConfig(srcConfig, renderTarget->config())) {
|
| - writeConfig = GrPixelConfigSwapRAndB(srcConfig);
|
| - swapRAndB = true;
|
| - }
|
| -
|
| - GrSurfaceDesc desc;
|
| - desc.fWidth = width;
|
| - desc.fHeight = height;
|
| - desc.fConfig = writeConfig;
|
| - SkAutoTUnref<GrTexture> texture(this->textureProvider()->refScratchTexture(desc,
|
| - GrTextureProvider::kApprox_ScratchTexMatch));
|
| - if (!texture) {
|
| - return false;
|
| - }
|
| -
|
| - SkAutoTUnref<const GrFragmentProcessor> fp;
|
| - SkMatrix textureMatrix;
|
| - textureMatrix.setIDiv(texture->width(), texture->height());
|
| -
|
| - // allocate a tmp buffer and sw convert the pixels to premul
|
| - SkAutoSTMalloc<128 * 128, uint32_t> tmpPixels(0);
|
| -
|
| - if (kUnpremul_PixelOpsFlag & pixelOpsFlags) {
|
| - if (!GrPixelConfigIs8888(srcConfig)) {
|
| - 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) {
|
| - size_t tmpRowBytes = 4 * width;
|
| - tmpPixels.reset(width * height);
|
| - if (!sw_convert_to_premul(srcConfig, width, height, rowBytes, buffer, tmpRowBytes,
|
| - tmpPixels.get())) {
|
| - return false;
|
| - }
|
| - rowBytes = tmpRowBytes;
|
| - buffer = tmpPixels.get();
|
| - }
|
| - }
|
| - if (NULL == fp) {
|
| - fp.reset(GrConfigConversionEffect::Create(texture,
|
| - swapRAndB,
|
| - GrConfigConversionEffect::kNone_PMConversion,
|
| - textureMatrix));
|
| - }
|
| -
|
| - // Even if the client told us not to flush, we still flush here. The client may have known that
|
| - // writes to the original surface caused no data hazards, but they can't know that the scratch
|
| - // we just got is safe.
|
| - if (texture->surfacePriv().hasPendingIO()) {
|
| - this->flush();
|
| - }
|
| - if (!fGpu->writeTexturePixels(texture, 0, 0, width, height,
|
| - writeConfig, buffer, rowBytes)) {
|
| - return false;
|
| - }
|
| -
|
| - 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)));
|
| - }
|
| -
|
| - if (kFlushWrites_PixelOp & pixelOpsFlags) {
|
| - this->flushSurfaceWrites(surface);
|
| - }
|
|
|
| + ASSERT_OWNED_RESOURCE(rt);
|
| + SkASSERT(rt && paint);
|
| + pipelineBuilder->setFromPaint(*paint, rt, clip);
|
| return true;
|
| }
|
|
|
| -// toggles between RGBA and BGRA
|
| -static SkColorType toggle_colortype32(SkColorType ct) {
|
| - if (kRGBA_8888_SkColorType == ct) {
|
| - return kBGRA_8888_SkColorType;
|
| - } else {
|
| - SkASSERT(kBGRA_8888_SkColorType == ct);
|
| - return kRGBA_8888_SkColorType;
|
| - }
|
| -}
|
| -
|
| -bool GrContext::readRenderTargetPixels(GrRenderTarget* target,
|
| - int left, int top, int width, int height,
|
| - GrPixelConfig dstConfig, void* buffer, size_t rowBytes,
|
| - uint32_t flags) {
|
| +bool GrDrawContext::prepareToDraw(GrRenderTarget* rt) {
|
| RETURN_FALSE_IF_ABANDONED
|
| - ASSERT_OWNED_RESOURCE(target);
|
| - SkASSERT(target);
|
| -
|
| - if (!(kDontFlush_PixelOpsFlag & flags) && target->surfacePriv().hasPendingWrite()) {
|
| - this->flush();
|
| - }
|
| -
|
| - // Determine which conversions have to be applied: flipY, swapRAnd, and/or unpremul.
|
| -
|
| - // If fGpu->readPixels would incur a y-flip cost then we will read the pixels upside down. We'll
|
| - // either do the flipY by drawing into a scratch with a matrix or on the cpu after the read.
|
| - bool flipY = fGpu->readPixelsWillPayForYFlip(target, left, top,
|
| - width, height, dstConfig,
|
| - rowBytes);
|
| - // We ignore the preferred config if it is different than our config unless it is an R/B swap.
|
| - // In that case we'll perform an R and B swap while drawing to a scratch texture of the swapped
|
| - // config. Then we will call readPixels on the scratch with the swapped config. The swaps during
|
| - // the draw cancels out the fact that we call readPixels with a config that is R/B swapped from
|
| - // dstConfig.
|
| - GrPixelConfig readConfig = dstConfig;
|
| - bool swapRAndB = false;
|
| - if (GrPixelConfigSwapRAndB(dstConfig) ==
|
| - fGpu->preferredReadPixelsConfig(dstConfig, target->config())) {
|
| - readConfig = GrPixelConfigSwapRAndB(readConfig);
|
| - swapRAndB = true;
|
| - }
|
| -
|
| - bool unpremul = SkToBool(kUnpremul_PixelOpsFlag & flags);
|
| -
|
| - if (unpremul && !GrPixelConfigIs8888(dstConfig)) {
|
| - // The unpremul flag is only allowed for these two configs.
|
| - return false;
|
| - }
|
| -
|
| - SkAutoTUnref<GrTexture> tempTexture;
|
| -
|
| - // If the src is a texture and we would have to do conversions after read pixels, we instead
|
| - // do the conversions by drawing the src to a scratch texture. If we handle any of the
|
| - // conversions in the draw we set the corresponding bool to false so that we don't reapply it
|
| - // on the read back pixels.
|
| - GrTexture* src = target->asTexture();
|
| - if (src && (swapRAndB || unpremul || flipY)) {
|
| - // Make the scratch a render so we can read its pixels.
|
| - GrSurfaceDesc desc;
|
| - desc.fFlags = kRenderTarget_GrSurfaceFlag;
|
| - desc.fWidth = width;
|
| - desc.fHeight = height;
|
| - desc.fConfig = readConfig;
|
| - desc.fOrigin = kTopLeft_GrSurfaceOrigin;
|
| -
|
| - // When a full read back is faster than a partial we could always make the scratch exactly
|
| - // match the passed rect. However, if we see many different size rectangles we will trash
|
| - // our texture cache and pay the cost of creating and destroying many textures. So, we only
|
| - // request an exact match when the caller is reading an entire RT.
|
| - GrTextureProvider::ScratchTexMatch match = GrTextureProvider::kApprox_ScratchTexMatch;
|
| - if (0 == left &&
|
| - 0 == top &&
|
| - target->width() == width &&
|
| - target->height() == height &&
|
| - fGpu->fullReadPixelsIsFasterThanPartial()) {
|
| - match = GrTextureProvider::kExact_ScratchTexMatch;
|
| - }
|
| - tempTexture.reset(this->textureProvider()->refScratchTexture(desc, match));
|
| - if (tempTexture) {
|
| - // compute a matrix to perform the draw
|
| - SkMatrix textureMatrix;
|
| - textureMatrix.setTranslate(SK_Scalar1 *left, SK_Scalar1 *top);
|
| - textureMatrix.postIDiv(src->width(), src->height());
|
| -
|
| - SkAutoTUnref<const GrFragmentProcessor> fp;
|
| - if (unpremul) {
|
| - fp.reset(this->createPMToUPMEffect(src, swapRAndB, textureMatrix));
|
| - if (fp) {
|
| - unpremul = false; // we no longer need to do this on CPU after the read back.
|
| - }
|
| - }
|
| - // If we failed to create a PM->UPM effect and have no other conversions to perform then
|
| - // there is no longer any point to using the scratch.
|
| - if (fp || flipY || swapRAndB) {
|
| - if (!fp) {
|
| - fp.reset(GrConfigConversionEffect::Create(
|
| - src, swapRAndB, GrConfigConversionEffect::kNone_PMConversion,
|
| - textureMatrix));
|
| - }
|
| - swapRAndB = false; // we will handle the swap in the draw.
|
| -
|
| - // We protect the existing geometry here since it may not be
|
| - // clear to the caller that a draw operation (i.e., drawSimpleRect)
|
| - // can be invoked in this method
|
| - {
|
| - GrPipelineBuilder pipelineBuilder;
|
| - SkASSERT(fp);
|
| - pipelineBuilder.addColorProcessor(fp);
|
| -
|
| - pipelineBuilder.setRenderTarget(tempTexture->asRenderTarget());
|
| - SkRect rect = SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height));
|
| - fDrawBuffer->drawSimpleRect(&pipelineBuilder,
|
| - GrColor_WHITE,
|
| - SkMatrix::I(),
|
| - rect);
|
| - // we want to read back from the scratch's origin
|
| - left = 0;
|
| - top = 0;
|
| - target = tempTexture->asRenderTarget();
|
| - }
|
| - this->flushSurfaceWrites(target);
|
| - }
|
| - }
|
| - }
|
| -
|
| - if (!fGpu->readPixels(target,
|
| - left, top, width, height,
|
| - readConfig, buffer, rowBytes)) {
|
| - return false;
|
| - }
|
| - // Perform any conversions we weren't able to perform using a scratch texture.
|
| - if (unpremul || swapRAndB) {
|
| - SkDstPixelInfo dstPI;
|
| - if (!GrPixelConfig2ColorAndProfileType(dstConfig, &dstPI.fColorType, NULL)) {
|
| - return false;
|
| - }
|
| - dstPI.fAlphaType = kUnpremul_SkAlphaType;
|
| - dstPI.fPixels = buffer;
|
| - dstPI.fRowBytes = rowBytes;
|
| -
|
| - SkSrcPixelInfo srcPI;
|
| - srcPI.fColorType = swapRAndB ? toggle_colortype32(dstPI.fColorType) : dstPI.fColorType;
|
| - srcPI.fAlphaType = kPremul_SkAlphaType;
|
| - srcPI.fPixels = buffer;
|
| - srcPI.fRowBytes = rowBytes;
|
| -
|
| - return srcPI.convertPixelsTo(&dstPI, width, height);
|
| - }
|
| - return true;
|
| -}
|
| -
|
| -void GrContext::prepareSurfaceForExternalRead(GrSurface* surface) {
|
| - RETURN_IF_ABANDONED
|
| - SkASSERT(surface);
|
| - ASSERT_OWNED_RESOURCE(surface);
|
| - if (surface->surfacePriv().hasPendingIO()) {
|
| - this->flush();
|
| - }
|
| - GrRenderTarget* rt = surface->asRenderTarget();
|
| - if (fGpu && rt) {
|
| - fGpu->resolveRenderTarget(rt);
|
| - }
|
| -}
|
| -
|
| -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) {
|
| - return;
|
| - }
|
| - ASSERT_OWNED_RESOURCE(src);
|
| - ASSERT_OWNED_RESOURCE(dst);
|
| -
|
| - // Since we're going to the draw target and not GPU, no need to check kNoFlush
|
| - // here.
|
| -
|
| - GrDrawTarget* target = this->prepareToDraw();
|
| - if (NULL == target) {
|
| - return;
|
| - }
|
| - target->copySurface(dst, src, srcRect, dstPoint);
|
| -
|
| - if (kFlushWrites_PixelOp & pixelOpsFlags) {
|
| - this->flush();
|
| - }
|
| -}
|
| -
|
| -void GrContext::flushSurfaceWrites(GrSurface* surface) {
|
| - RETURN_IF_ABANDONED
|
| - if (surface->surfacePriv().hasPendingWrite()) {
|
| - 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.
|
| - * Due to its expense, the software path renderer has split out so it can
|
| - * can be individually allowed/disallowed via the "allowSW" boolean.
|
| - */
|
| -GrPathRenderer* GrContext::getPathRenderer(const GrDrawTarget* target,
|
| - const GrPipelineBuilder* pipelineBuilder,
|
| - const SkMatrix& viewMatrix,
|
| - const SkPath& path,
|
| - const GrStrokeInfo& stroke,
|
| - bool allowSW,
|
| - GrPathRendererChain::DrawType drawType,
|
| - GrPathRendererChain::StencilSupport* stencilSupport) {
|
| -
|
| - if (NULL == fPathRendererChain) {
|
| - fPathRendererChain = SkNEW_ARGS(GrPathRendererChain, (this));
|
| - }
|
| -
|
| - GrPathRenderer* pr = fPathRendererChain->getPathRenderer(target,
|
| - pipelineBuilder,
|
| - viewMatrix,
|
| - path,
|
| - stroke,
|
| - drawType,
|
| - stencilSupport);
|
| -
|
| - if (NULL == pr && allowSW) {
|
| - if (NULL == fSoftwarePathRenderer) {
|
| - fSoftwarePathRenderer = SkNEW_ARGS(GrSoftwarePathRenderer, (this));
|
| - }
|
| - pr = fSoftwarePathRenderer;
|
| - }
|
| -
|
| - return pr;
|
| -}
|
| -
|
| -////////////////////////////////////////////////////////////////////////////////
|
| -bool GrContext::isConfigRenderable(GrPixelConfig config, bool withMSAA) const {
|
| - return fGpu->caps()->isConfigRenderable(config, withMSAA);
|
| -}
|
| -
|
| -int GrContext::getRecommendedSampleCount(GrPixelConfig config,
|
| - SkScalar dpi) const {
|
| - if (!this->isConfigRenderable(config, true)) {
|
| - return 0;
|
| - }
|
| - int chosenSampleCount = 0;
|
| - if (fGpu->caps()->shaderCaps()->pathRenderingSupport()) {
|
| - if (dpi >= 250.0f) {
|
| - chosenSampleCount = 4;
|
| - } else {
|
| - chosenSampleCount = 16;
|
| - }
|
| - }
|
| - return chosenSampleCount <= fGpu->caps()->maxSampleCount() ?
|
| - chosenSampleCount : 0;
|
| -}
|
| -
|
| -GrDrawTarget* GrContext::getTextTarget() {
|
| - return this->prepareToDraw();
|
| -}
|
| -
|
| -namespace {
|
| -void test_pm_conversions(GrContext* ctx, int* pmToUPMValue, int* upmToPMValue) {
|
| - GrConfigConversionEffect::PMConversion pmToUPM;
|
| - GrConfigConversionEffect::PMConversion upmToPM;
|
| - GrConfigConversionEffect::TestForPreservingPMConversions(ctx, &pmToUPM, &upmToPM);
|
| - *pmToUPMValue = pmToUPM;
|
| - *upmToPMValue = upmToPM;
|
| -}
|
| -}
|
| -
|
| -const GrFragmentProcessor* GrContext::createPMToUPMEffect(GrTexture* texture,
|
| - bool swapRAndB,
|
| - const SkMatrix& matrix) {
|
| - if (!fDidTestPMConversions) {
|
| - test_pm_conversions(this, &fPMToUPMConversion, &fUPMToPMConversion);
|
| - fDidTestPMConversions = true;
|
| - }
|
| - GrConfigConversionEffect::PMConversion pmToUPM =
|
| - static_cast<GrConfigConversionEffect::PMConversion>(fPMToUPMConversion);
|
| - if (GrConfigConversionEffect::kNone_PMConversion != pmToUPM) {
|
| - return GrConfigConversionEffect::Create(texture, swapRAndB, pmToUPM, matrix);
|
| - } else {
|
| - return NULL;
|
| - }
|
| -}
|
| -
|
| -const GrFragmentProcessor* GrContext::createUPMToPMEffect(GrTexture* texture,
|
| - bool swapRAndB,
|
| - const SkMatrix& matrix) {
|
| - if (!fDidTestPMConversions) {
|
| - test_pm_conversions(this, &fPMToUPMConversion, &fUPMToPMConversion);
|
| - fDidTestPMConversions = true;
|
| - }
|
| - GrConfigConversionEffect::PMConversion upmToPM =
|
| - static_cast<GrConfigConversionEffect::PMConversion>(fUPMToPMConversion);
|
| - if (GrConfigConversionEffect::kNone_PMConversion != upmToPM) {
|
| - return GrConfigConversionEffect::Create(texture, swapRAndB, upmToPM, matrix);
|
| - } else {
|
| - return NULL;
|
| - }
|
| -}
|
| -
|
| -//////////////////////////////////////////////////////////////////////////////
|
| -
|
| -void GrContext::getResourceCacheLimits(int* maxTextures, size_t* maxTextureBytes) const {
|
| - if (maxTextures) {
|
| - *maxTextures = fResourceCache->getMaxResourceCount();
|
| - }
|
| - if (maxTextureBytes) {
|
| - *maxTextureBytes = fResourceCache->getMaxResourceBytes();
|
| - }
|
| -}
|
| -
|
| -void GrContext::setResourceCacheLimits(int maxTextures, size_t maxTextureBytes) {
|
| - fResourceCache->setLimits(maxTextures, maxTextureBytes);
|
| -}
|
| -
|
| -//////////////////////////////////////////////////////////////////////////////
|
| -
|
| -void GrContext::addGpuTraceMarker(const GrGpuTraceMarker* marker) {
|
| - fGpu->addGpuTraceMarker(marker);
|
| - if (fDrawBuffer) {
|
| - fDrawBuffer->addGpuTraceMarker(marker);
|
| - }
|
| -}
|
| -
|
| -void GrContext::removeGpuTraceMarker(const GrGpuTraceMarker* marker) {
|
| - fGpu->removeGpuTraceMarker(marker);
|
| - if (fDrawBuffer) {
|
| - fDrawBuffer->removeGpuTraceMarker(marker);
|
| - }
|
| + SkASSERT(rt);
|
| + return true;
|
| }
|
|
|
| ///////////////////////////////////////////////////////////////////////////////////////////////////
|
| @@ -1999,3 +1268,4 @@ BATCH_TEST_DEFINE(VerticesBatch) {
|
| }
|
|
|
| #endif
|
| +
|
|
|