Remove NVPR
Bug: skia:11760 Change-Id: Ie0fc1aaa3120b37b1d452fdc9a8b5cb91b6ffe1e Reviewed-on: https://skia-review.googlesource.com/c/skia/+/386559 Reviewed-by: Brian Salomon <bsalomon@google.com> Commit-Queue: Robert Phillips <robertphillips@google.com>
This commit is contained in:
parent
15206fb30d
commit
31798c2796
4
BUILD.gn
4
BUILD.gn
@ -872,10 +872,6 @@ optional("gpu") {
|
||||
sources -= skia_ccpr_sources
|
||||
sources += [ "src/gpu/ccpr/GrCoverageCountingPathRenderer_none.cpp" ]
|
||||
}
|
||||
if (!skia_enable_nvpr) {
|
||||
sources -= skia_nvpr_sources
|
||||
sources += [ "src/gpu/GrPathRendering_none.cpp" ]
|
||||
}
|
||||
|
||||
libs = []
|
||||
frameworks = []
|
||||
|
@ -10,6 +10,8 @@ Milestone 91
|
||||
development and isn't quite ready for prime time yet.
|
||||
https://review.skia.org/378496
|
||||
|
||||
* Skia's GPU backend no longer supports NVPR. Our more recent path renderers are more
|
||||
performant and are not limited to nVidia hardware.
|
||||
* * *
|
||||
|
||||
Milestone 90
|
||||
|
@ -164,7 +164,6 @@ echo "Compiling bitcode"
|
||||
\
|
||||
skia_enable_skshaper=true \
|
||||
skia_enable_ccpr=false \
|
||||
skia_enable_nvpr=false \
|
||||
skia_enable_pdf=false"
|
||||
|
||||
# Build all the libs we will need below
|
||||
|
@ -111,7 +111,6 @@ echo "Compiling bitcode"
|
||||
skia_enable_tools=false \
|
||||
skia_enable_skshaper=false \
|
||||
skia_enable_ccpr=false \
|
||||
skia_enable_nvpr=false \
|
||||
skia_enable_fontmgr_custom_directory=false \
|
||||
skia_enable_fontmgr_custom_embedded=true \
|
||||
skia_enable_fontmgr_custom_empty=false \
|
||||
|
21
gn/gpu.gni
21
gn/gpu.gni
@ -613,7 +613,6 @@ skia_gl_gpu_sources = [
|
||||
"$_src/gpu/gl/GrGLUniformHandler.h",
|
||||
"$_src/gpu/gl/GrGLUtil.cpp",
|
||||
"$_src/gpu/gl/GrGLUtil.h",
|
||||
"$_src/gpu/gl/GrGLVaryingHandler.cpp",
|
||||
"$_src/gpu/gl/GrGLVaryingHandler.h",
|
||||
"$_src/gpu/gl/GrGLVertexArray.cpp",
|
||||
"$_src/gpu/gl/GrGLVertexArray.h",
|
||||
@ -640,27 +639,7 @@ skia_ccpr_sources = [
|
||||
"$_src/gpu/ccpr/GrCoverageCountingPathRenderer.h",
|
||||
]
|
||||
|
||||
skia_nvpr_sources = [
|
||||
"$_src/gpu/GrPath.cpp",
|
||||
"$_src/gpu/GrPath.h",
|
||||
"$_src/gpu/GrPathProcessor.cpp",
|
||||
"$_src/gpu/GrPathProcessor.h",
|
||||
"$_src/gpu/GrPathRendering.cpp",
|
||||
"$_src/gpu/GrPathRendering.h",
|
||||
"$_src/gpu/gl/GrGLPath.cpp",
|
||||
"$_src/gpu/gl/GrGLPath.h",
|
||||
"$_src/gpu/gl/GrGLPathRendering.cpp",
|
||||
"$_src/gpu/gl/GrGLPathRendering.h",
|
||||
"$_src/gpu/ops/GrDrawPathOp.cpp",
|
||||
"$_src/gpu/ops/GrDrawPathOp.h",
|
||||
"$_src/gpu/ops/GrStencilAndCoverPathRenderer.cpp",
|
||||
"$_src/gpu/ops/GrStencilAndCoverPathRenderer.h",
|
||||
"$_src/gpu/ops/GrStencilPathOp.cpp",
|
||||
"$_src/gpu/ops/GrStencilPathOp.h",
|
||||
]
|
||||
|
||||
skia_gpu_sources += skia_ccpr_sources
|
||||
skia_gpu_sources += skia_nvpr_sources
|
||||
|
||||
skia_null_gpu_sources = [ "$_src/gpu/gl/GrGLMakeNativeInterface_none.cpp" ]
|
||||
|
||||
|
@ -108,7 +108,6 @@ declare_args() {
|
||||
skia_enable_fontmgr_win_gdi = is_win && !skia_enable_winuwp
|
||||
skia_enable_fontmgr_FontConfigInterface =
|
||||
skia_use_freetype && skia_use_fontconfig
|
||||
skia_enable_nvpr = !skia_enable_flutter_defines
|
||||
skia_enable_spirv_validation = is_skia_dev_build && is_debug && !skia_use_dawn
|
||||
skia_use_dng_sdk =
|
||||
!is_fuchsia && skia_use_libjpeg_turbo_decode && skia_use_zlib
|
||||
|
@ -218,7 +218,6 @@ enum GrGLBackendState {
|
||||
kProgram_GrGLBackendState = 1 << 8,
|
||||
kFixedFunction_GrGLBackendState = 1 << 9,
|
||||
kMisc_GrGLBackendState = 1 << 10,
|
||||
kPathRendering_GrGLBackendState = 1 << 11,
|
||||
kALL_GrGLBackendState = 0xffff
|
||||
};
|
||||
|
||||
|
@ -780,8 +780,7 @@ enum class GpuPathRenderers {
|
||||
kAALinearizing = 1 << 5,
|
||||
kSmall = 1 << 6,
|
||||
kTriangulating = 1 << 7,
|
||||
kStencilAndCover = 1 << 8,
|
||||
kDefault = ((1 << 8) - 1) // All path renderers except NVPR
|
||||
kDefault = ((1 << 8) - 1) // All path renderers.
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -320,7 +320,6 @@ echo "Compiling bitcode"
|
||||
${GN_VIEWER} \
|
||||
\
|
||||
skia_enable_skshaper=true \
|
||||
skia_enable_nvpr=false \
|
||||
skia_enable_skparagraph=true \
|
||||
skia_enable_pdf=false"
|
||||
|
||||
|
@ -131,7 +131,6 @@ echo "Compiling bitcode"
|
||||
skia_enable_ccpr=true \
|
||||
skia_enable_svg=true \
|
||||
skia_enable_skshaper=true \
|
||||
skia_enable_nvpr=false \
|
||||
skia_enable_skparagraph=true \
|
||||
skia_enable_pdf=false"
|
||||
|
||||
|
@ -223,7 +223,6 @@ BASE_SRCS_ALL = struct(
|
||||
"src/utils/win/**/*",
|
||||
|
||||
# Exclude multiple definitions.
|
||||
"src/gpu/GrPathRendering_none.cpp",
|
||||
"src/gpu/ccpr/GrCoverageCountingPathRenderer_none.cpp",
|
||||
"src/gpu/gl/GrGLMakeNativeInterface_none.cpp",
|
||||
"src/pdf/SkDocument_PDF_None.cpp", # We use src/pdf/SkPDFDocument.cpp.
|
||||
|
@ -22,7 +22,6 @@
|
||||
#include "src/gpu/GrDirectContextPriv.h"
|
||||
#include "src/gpu/GrGpuResourcePriv.h"
|
||||
#include "src/gpu/GrNativeRect.h"
|
||||
#include "src/gpu/GrPathRendering.h"
|
||||
#include "src/gpu/GrPipeline.h"
|
||||
#include "src/gpu/GrRenderTarget.h"
|
||||
#include "src/gpu/GrResourceCache.h"
|
||||
|
@ -33,7 +33,6 @@ class GrGLContext;
|
||||
class GrPath;
|
||||
class GrPathRenderer;
|
||||
class GrPathRendererChain;
|
||||
class GrPathRendering;
|
||||
class GrPipeline;
|
||||
class GrPrimitiveProcessor;
|
||||
class GrRenderTarget;
|
||||
@ -64,8 +63,6 @@ public:
|
||||
const GrCaps* caps() const { return fCaps.get(); }
|
||||
sk_sp<const GrCaps> refCaps() const { return fCaps; }
|
||||
|
||||
GrPathRendering* pathRendering() { return fPathRendering.get(); }
|
||||
|
||||
virtual GrStagingBufferManager* stagingBufferManager() { return nullptr; }
|
||||
|
||||
virtual GrRingBuffer* uniformsRingBuffer() { return nullptr; }
|
||||
@ -700,7 +697,6 @@ protected:
|
||||
void setOOMed() { fOOMed = true; }
|
||||
|
||||
Stats fStats;
|
||||
std::unique_ptr<GrPathRendering> fPathRendering;
|
||||
|
||||
// Subclass must call this to initialize caps & compiler in its constructor.
|
||||
void initCapsAndCompiler(sk_sp<const GrCaps> caps);
|
||||
|
@ -21,7 +21,6 @@
|
||||
#include "src/core/SkStringUtils.h"
|
||||
#include "src/core/SkTLazy.h"
|
||||
#include "src/gpu/GrAppliedClip.h"
|
||||
#include "src/gpu/GrPathRendering.h"
|
||||
#include "src/gpu/GrPrimitiveProcessor.h"
|
||||
#include "src/gpu/GrRenderTask.h"
|
||||
#include "src/gpu/ops/GrDrawOp.h"
|
||||
|
@ -1,55 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "src/gpu/GrPath.h"
|
||||
#include "src/gpu/geometry/GrStyledShape.h"
|
||||
|
||||
static inline void write_style_key(uint32_t* key, const GrStyle& style) {
|
||||
// Pass 1 for the scale since the GPU will apply the style not GrStyle::applyToPath().
|
||||
GrStyle::WriteKey(key, style, GrStyle::Apply::kPathEffectAndStrokeRec, SK_Scalar1);
|
||||
}
|
||||
|
||||
|
||||
void GrPath::ComputeKey(const GrStyledShape& shape, GrUniqueKey* key, bool* outIsVolatile) {
|
||||
int geoCnt = shape.unstyledKeySize();
|
||||
int styleCnt = GrStyle::KeySize(shape.style(), GrStyle::Apply::kPathEffectAndStrokeRec);
|
||||
// This should only fail for an arbitrary path effect, and we should not have gotten
|
||||
// here with anything other than a dash path effect.
|
||||
SkASSERT(styleCnt >= 0);
|
||||
if (geoCnt < 0) {
|
||||
*outIsVolatile = true;
|
||||
return;
|
||||
}
|
||||
static const GrUniqueKey::Domain kGeneralPathDomain = GrUniqueKey::GenerateDomain();
|
||||
GrUniqueKey::Builder builder(key, kGeneralPathDomain, geoCnt + styleCnt, "Path");
|
||||
shape.writeUnstyledKey(&builder[0]);
|
||||
if (styleCnt) {
|
||||
write_style_key(&builder[geoCnt], shape.style());
|
||||
}
|
||||
*outIsVolatile = false;
|
||||
}
|
||||
|
||||
#ifdef SK_DEBUG
|
||||
bool GrPath::isEqualTo(const SkPath& path, const GrStyle& style) const {
|
||||
// Since this is only called in debug we don't care about performance.
|
||||
int cnt0 = GrStyle::KeySize(fStyle, GrStyle::Apply::kPathEffectAndStrokeRec);
|
||||
int cnt1 = GrStyle::KeySize(style, GrStyle::Apply::kPathEffectAndStrokeRec);
|
||||
if (cnt0 < 0 || cnt1 < 0 || cnt0 != cnt1) {
|
||||
return false;
|
||||
}
|
||||
if (cnt0) {
|
||||
SkAutoTArray<uint32_t> key0(cnt0);
|
||||
SkAutoTArray<uint32_t> key1(cnt0);
|
||||
write_style_key(key0.get(), fStyle);
|
||||
write_style_key(key1.get(), style);
|
||||
if (0 != memcmp(key0.get(), key1.get(), cnt0)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return fSkPath == path;
|
||||
}
|
||||
#endif
|
@ -1,58 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef GrPath_DEFINED
|
||||
#define GrPath_DEFINED
|
||||
|
||||
#include "include/core/SkPath.h"
|
||||
#include "include/core/SkRect.h"
|
||||
#include "src/gpu/GrGpuResource.h"
|
||||
#include "src/gpu/GrPathRendering.h"
|
||||
#include "src/gpu/GrStyle.h"
|
||||
|
||||
class GrStyledShape;
|
||||
|
||||
class GrPath : public GrGpuResource {
|
||||
public:
|
||||
/**
|
||||
* Initialize to a path with a fixed stroke. Stroke must not be hairline.
|
||||
*/
|
||||
GrPath(GrGpu* gpu, const SkPath& skPath, const GrStyle& style)
|
||||
: INHERITED(gpu)
|
||||
, fBounds(SkRect::MakeEmpty())
|
||||
, fFillType(GrPathRendering::kWinding_FillType)
|
||||
#ifdef SK_DEBUG
|
||||
, fSkPath(skPath)
|
||||
, fStyle(style)
|
||||
#endif
|
||||
{
|
||||
}
|
||||
|
||||
static void ComputeKey(const GrStyledShape&, GrUniqueKey* key, bool* outIsVolatile);
|
||||
|
||||
const SkRect& getBounds() const { return fBounds; }
|
||||
|
||||
GrPathRendering::FillType getFillType() const { return fFillType; }
|
||||
#ifdef SK_DEBUG
|
||||
bool isEqualTo(const SkPath& path, const GrStyle& style) const;
|
||||
#endif
|
||||
|
||||
protected:
|
||||
// Subclass should init these.
|
||||
SkRect fBounds;
|
||||
GrPathRendering::FillType fFillType;
|
||||
#ifdef SK_DEBUG
|
||||
SkPath fSkPath;
|
||||
GrStyle fStyle;
|
||||
#endif
|
||||
|
||||
private:
|
||||
const char* getResourceType() const override { return "Path Data"; }
|
||||
using INHERITED = GrGpuResource;
|
||||
};
|
||||
|
||||
#endif
|
@ -1,129 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "src/gpu/GrPathProcessor.h"
|
||||
|
||||
#include "include/private/SkTo.h"
|
||||
#include "src/core/SkMatrixPriv.h"
|
||||
#include "src/gpu/GrShaderCaps.h"
|
||||
#include "src/gpu/gl/GrGLGpu.h"
|
||||
#ifdef SK_GL
|
||||
#include "src/gpu/gl/GrGLVaryingHandler.h"
|
||||
#endif
|
||||
#include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
|
||||
#include "src/gpu/glsl/GrGLSLPrimitiveProcessor.h"
|
||||
#include "src/gpu/glsl/GrGLSLUniformHandler.h"
|
||||
#include "src/gpu/glsl/GrGLSLVarying.h"
|
||||
|
||||
class GrGLPathProcessor : public GrGLSLPrimitiveProcessor {
|
||||
public:
|
||||
GrGLPathProcessor() : fColor(SK_PMColor4fILLEGAL) {}
|
||||
|
||||
static void GenKey(const GrPathProcessor& pathProc,
|
||||
const GrShaderCaps&,
|
||||
GrProcessorKeyBuilder* b) {
|
||||
b->add32(SkToInt(pathProc.viewMatrix().hasPerspective()));
|
||||
}
|
||||
|
||||
void emitCode(EmitArgs& args) override {
|
||||
GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
|
||||
const GrPathProcessor& pathProc = args.fGP.cast<GrPathProcessor>();
|
||||
|
||||
if (!pathProc.viewMatrix().hasPerspective()) {
|
||||
args.fVaryingHandler->setNoPerspective();
|
||||
}
|
||||
|
||||
// emit transforms
|
||||
this->emitTransforms(args.fVaryingHandler, args.fUniformHandler,
|
||||
args.fFPCoordTransformHandler);
|
||||
|
||||
// Setup uniform color
|
||||
const char* stagedLocalVarName;
|
||||
fColorUniform = args.fUniformHandler->addUniform(nullptr,
|
||||
kFragment_GrShaderFlag,
|
||||
kHalf4_GrSLType,
|
||||
"Color",
|
||||
&stagedLocalVarName);
|
||||
fragBuilder->codeAppendf("half4 %s = %s;", args.fOutputColor, stagedLocalVarName);
|
||||
|
||||
// setup constant solid coverage
|
||||
fragBuilder->codeAppendf("const half4 %s = half4(1);", args.fOutputCoverage);
|
||||
}
|
||||
|
||||
void emitTransforms(GrGLSLVaryingHandler* varyingHandler,
|
||||
GrGLSLUniformHandler* uniformHandler,
|
||||
FPCoordTransformHandler* transformHandler) {
|
||||
for (int i = 0; *transformHandler; ++*transformHandler, ++i) {
|
||||
SkString strVaryingName;
|
||||
strVaryingName.printf("TransformedCoord_%d", i);
|
||||
GrGLSLVarying v(kFloat2_GrSLType);
|
||||
#ifdef SK_GL
|
||||
GrGLVaryingHandler* glVaryingHandler = (GrGLVaryingHandler*)varyingHandler;
|
||||
fVaryingTransform.push_back().fHandle =
|
||||
glVaryingHandler->addPathProcessingVarying(strVaryingName.c_str(), &v)
|
||||
.toIndex();
|
||||
#endif
|
||||
GrShaderVar fragmentVar = {SkString(v.fsIn()), kFloat2_GrSLType};
|
||||
transformHandler->specifyCoordsForCurrCoordTransform(fragmentVar);
|
||||
}
|
||||
}
|
||||
|
||||
void setData(const GrGLSLProgramDataManager& pd,
|
||||
const GrPrimitiveProcessor& primProc) override {
|
||||
const GrPathProcessor& pathProc = primProc.cast<GrPathProcessor>();
|
||||
if (pathProc.color() != fColor) {
|
||||
pd.set4fv(fColorUniform, 1, pathProc.color().vec());
|
||||
fColor = pathProc.color();
|
||||
}
|
||||
|
||||
for (int v = 0; v < fVaryingTransform.count(); ++v) {
|
||||
if (fVaryingTransform[v].fHandle.isValid()) {
|
||||
SkMatrix m = pathProc.localMatrix();
|
||||
if (!SkMatrixPriv::CheapEqual(fVaryingTransform[v].fCurrentValue, m)) {
|
||||
fVaryingTransform[v].fCurrentValue = m;
|
||||
pd.setPathFragmentInputTransform(fVaryingTransform[v].fHandle, 2, m);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
using VaryingHandle = GrGLSLProgramDataManager::VaryingHandle;
|
||||
|
||||
// Varying transforms are used for non-explicitly sampled FPs. We provide a matrix
|
||||
// to GL as fixed function state and it uses it to compute a varying that we pick up
|
||||
// in the FS as the transformed local coords.
|
||||
struct TransformVarying {
|
||||
VaryingHandle fHandle;
|
||||
SkMatrix fCurrentValue = SkMatrix::InvalidMatrix();
|
||||
};
|
||||
|
||||
SkTArray<TransformVarying, true> fVaryingTransform;
|
||||
|
||||
UniformHandle fColorUniform;
|
||||
SkPMColor4f fColor;
|
||||
|
||||
using INHERITED = GrGLSLPrimitiveProcessor;
|
||||
};
|
||||
|
||||
GrPathProcessor::GrPathProcessor(const SkPMColor4f& color,
|
||||
const SkMatrix& viewMatrix,
|
||||
const SkMatrix& localMatrix)
|
||||
: INHERITED(kGrPathProcessor_ClassID)
|
||||
, fColor(color)
|
||||
, fViewMatrix(viewMatrix)
|
||||
, fLocalMatrix(localMatrix) {}
|
||||
|
||||
void GrPathProcessor::getGLSLProcessorKey(const GrShaderCaps& caps,
|
||||
GrProcessorKeyBuilder* b) const {
|
||||
GrGLPathProcessor::GenKey(*this, caps, b);
|
||||
}
|
||||
|
||||
GrGLSLPrimitiveProcessor* GrPathProcessor::createGLSLInstance(const GrShaderCaps& caps) const {
|
||||
SkASSERT(caps.pathRenderingSupport());
|
||||
return new GrGLPathProcessor();
|
||||
}
|
@ -1,47 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef GrPathProcessor_DEFINED
|
||||
#define GrPathProcessor_DEFINED
|
||||
|
||||
#include "src/gpu/GrPrimitiveProcessor.h"
|
||||
|
||||
/*
|
||||
* The path equivalent of the GP. For now this just manages color. In the long term we plan on
|
||||
* extending this class to handle all nvpr uniform / varying / program work.
|
||||
*/
|
||||
class GrPathProcessor : public GrPrimitiveProcessor {
|
||||
public:
|
||||
static GrPathProcessor* Create(const SkPMColor4f& color,
|
||||
const SkMatrix& viewMatrix = SkMatrix::I(),
|
||||
const SkMatrix& localMatrix = SkMatrix::I()) {
|
||||
return new GrPathProcessor(color, viewMatrix, localMatrix);
|
||||
}
|
||||
|
||||
const char* name() const override { return "PathProcessor"; }
|
||||
|
||||
const SkPMColor4f& color() const { return fColor; }
|
||||
const SkMatrix& viewMatrix() const { return fViewMatrix; }
|
||||
const SkMatrix& localMatrix() const { return fLocalMatrix; }
|
||||
|
||||
void getGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override;
|
||||
|
||||
GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps& caps) const override;
|
||||
|
||||
bool isPathRendering() const override { return true; }
|
||||
|
||||
private:
|
||||
GrPathProcessor(const SkPMColor4f&, const SkMatrix& viewMatrix, const SkMatrix& localMatrix);
|
||||
|
||||
SkPMColor4f fColor;
|
||||
const SkMatrix fViewMatrix;
|
||||
const SkMatrix fLocalMatrix;
|
||||
|
||||
using INHERITED = GrPrimitiveProcessor;
|
||||
};
|
||||
|
||||
#endif
|
@ -86,7 +86,7 @@ public:
|
||||
GrAAType fAAType;
|
||||
bool fTargetIsWrappedVkSecondaryCB;
|
||||
|
||||
// This is only used by GrStencilAndCoverPathRenderer
|
||||
// This is only used by GrTessellationPathRenderer
|
||||
bool fHasUserStencilSettings;
|
||||
|
||||
#ifdef SK_DEBUG
|
||||
|
@ -23,7 +23,6 @@
|
||||
#include "src/gpu/ops/GrDashLinePathRenderer.h"
|
||||
#include "src/gpu/ops/GrDefaultPathRenderer.h"
|
||||
#include "src/gpu/ops/GrSmallPathRenderer.h"
|
||||
#include "src/gpu/ops/GrStencilAndCoverPathRenderer.h"
|
||||
#include "src/gpu/ops/GrTriangulatingPathRenderer.h"
|
||||
#include "src/gpu/tessellate/GrTessellationPathRenderer.h"
|
||||
|
||||
@ -55,18 +54,6 @@ GrPathRendererChain::GrPathRendererChain(GrRecordingContext* context, const Opti
|
||||
if (options.fGpuPathRenderers & GpuPathRenderers::kSmall) {
|
||||
fChain.push_back(sk_make_sp<GrSmallPathRenderer>());
|
||||
}
|
||||
if (options.fGpuPathRenderers & GpuPathRenderers::kStencilAndCover) {
|
||||
auto direct = context->asDirectContext();
|
||||
if (direct) {
|
||||
auto resourceProvider = direct->priv().resourceProvider();
|
||||
|
||||
sk_sp<GrPathRenderer> pr(
|
||||
GrStencilAndCoverPathRenderer::Create(resourceProvider, caps));
|
||||
if (pr) {
|
||||
fChain.push_back(std::move(pr));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (options.fGpuPathRenderers & GpuPathRenderers::kTriangulating) {
|
||||
fChain.push_back(sk_make_sp<GrTriangulatingPathRenderer>());
|
||||
}
|
||||
|
@ -1,64 +0,0 @@
|
||||
/*
|
||||
* Copyright 2014 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "include/core/SkMatrix.h"
|
||||
#include "include/core/SkTypeface.h"
|
||||
#include "src/core/SkDescriptor.h"
|
||||
#include "src/core/SkGlyph.h"
|
||||
#include "src/core/SkScalerContext.h"
|
||||
#include "src/gpu/GrGpu.h"
|
||||
#include "src/gpu/GrPathRendering.h"
|
||||
#include "src/gpu/GrProgramInfo.h"
|
||||
#include "src/gpu/GrRenderTarget.h"
|
||||
|
||||
const GrUserStencilSettings& GrPathRendering::GetStencilPassSettings(FillType fill) {
|
||||
switch (fill) {
|
||||
default:
|
||||
SK_ABORT("Unexpected path fill.");
|
||||
case GrPathRendering::kWinding_FillType: {
|
||||
constexpr static GrUserStencilSettings kWindingStencilPass(
|
||||
GrUserStencilSettings::StaticInit<
|
||||
0xffff,
|
||||
GrUserStencilTest::kAlwaysIfInClip,
|
||||
0xffff,
|
||||
GrUserStencilOp::kIncWrap,
|
||||
GrUserStencilOp::kIncWrap,
|
||||
0xffff>()
|
||||
);
|
||||
return kWindingStencilPass;
|
||||
}
|
||||
case GrPathRendering::kEvenOdd_FillType: {
|
||||
constexpr static GrUserStencilSettings kEvenOddStencilPass(
|
||||
GrUserStencilSettings::StaticInit<
|
||||
0xffff,
|
||||
GrUserStencilTest::kAlwaysIfInClip,
|
||||
0xffff,
|
||||
GrUserStencilOp::kInvert,
|
||||
GrUserStencilOp::kInvert,
|
||||
0xffff>()
|
||||
);
|
||||
return kEvenOddStencilPass;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GrPathRendering::stencilPath(const StencilPathArgs& args, const GrPath* path) {
|
||||
fGpu->handleDirtyContext();
|
||||
this->onStencilPath(args, path);
|
||||
}
|
||||
|
||||
void GrPathRendering::drawPath(GrRenderTarget* renderTarget,
|
||||
const GrProgramInfo& programInfo,
|
||||
// Cover pass settings in pipeline.
|
||||
const GrStencilSettings& stencilPassSettings,
|
||||
const GrPath* path) {
|
||||
fGpu->handleDirtyContext();
|
||||
if (auto barrierType = programInfo.pipeline().xferBarrierType(*fGpu->caps())) {
|
||||
fGpu->xferBarrier(renderTarget, barrierType);
|
||||
}
|
||||
this->onDrawPath(stencilPassSettings, path);
|
||||
}
|
@ -1,134 +0,0 @@
|
||||
/*
|
||||
* Copyright 2014 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef GrPathRendering_DEFINED
|
||||
#define GrPathRendering_DEFINED
|
||||
|
||||
#include "include/core/SkPath.h"
|
||||
|
||||
class GrGpu;
|
||||
class GrPath;
|
||||
class GrProgramInfo;
|
||||
class GrRenderTarget;
|
||||
class GrRenderTargetProxy;
|
||||
class GrScissorState;
|
||||
class GrStencilSettings;
|
||||
class GrStyle;
|
||||
struct GrUserStencilSettings;
|
||||
struct SkScalerContextEffects;
|
||||
class SkDescriptor;
|
||||
class SkTypeface;
|
||||
|
||||
/**
|
||||
* Abstract class wrapping HW path rendering API.
|
||||
*
|
||||
* The subclasses of this class use the possible HW API to render paths (as opposed to path
|
||||
* rendering implemented in Skia on top of a "3d" HW API).
|
||||
* The subclasses hold the global state needed to render paths, including shadow of the global HW
|
||||
* API state. Similar to GrGpu.
|
||||
*
|
||||
* It is expected that the lifetimes of GrGpuXX and GrXXPathRendering are the same. The call context
|
||||
* interface (eg. * the concrete instance of GrGpu subclass) should be provided to the instance
|
||||
* during construction.
|
||||
*/
|
||||
class GrPathRendering {
|
||||
public:
|
||||
virtual ~GrPathRendering() { }
|
||||
|
||||
enum PathTransformType {
|
||||
kNone_PathTransformType, //!< []
|
||||
kTranslateX_PathTransformType, //!< [kMTransX]
|
||||
kTranslateY_PathTransformType, //!< [kMTransY]
|
||||
kTranslate_PathTransformType, //!< [kMTransX, kMTransY]
|
||||
kAffine_PathTransformType, //!< [kMScaleX, kMSkewX, kMTransX, kMSkewY, kMScaleY, kMTransY]
|
||||
|
||||
kLast_PathTransformType = kAffine_PathTransformType
|
||||
};
|
||||
|
||||
static inline int PathTransformSize(PathTransformType type) {
|
||||
switch (type) {
|
||||
case kNone_PathTransformType:
|
||||
return 0;
|
||||
case kTranslateX_PathTransformType:
|
||||
case kTranslateY_PathTransformType:
|
||||
return 1;
|
||||
case kTranslate_PathTransformType:
|
||||
return 2;
|
||||
case kAffine_PathTransformType:
|
||||
return 6;
|
||||
|
||||
default:
|
||||
SK_ABORT("Unknown path transform type");
|
||||
}
|
||||
}
|
||||
|
||||
// No native support for inverse at this time
|
||||
enum FillType {
|
||||
/** Specifies that "inside" is computed by a non-zero sum of signed
|
||||
edge crossings
|
||||
*/
|
||||
kWinding_FillType,
|
||||
/** Specifies that "inside" is computed by an odd number of edge
|
||||
crossings
|
||||
*/
|
||||
kEvenOdd_FillType,
|
||||
};
|
||||
|
||||
static const GrUserStencilSettings& GetStencilPassSettings(FillType);
|
||||
|
||||
/**
|
||||
* Creates a new gpu path, based on the specified path and stroke and returns it.
|
||||
*
|
||||
* @param SkPath the geometry.
|
||||
* @param GrStyle the style applied to the path. Styles with non-dash path effects are not
|
||||
* allowed.
|
||||
* @return a new GPU path object.
|
||||
*/
|
||||
virtual sk_sp<GrPath> createPath(const SkPath&, const GrStyle&) = 0;
|
||||
|
||||
/** None of these params are optional, pointers used just to avoid making copies. */
|
||||
struct StencilPathArgs {
|
||||
StencilPathArgs(bool useHWAA,
|
||||
GrRenderTargetProxy* proxy,
|
||||
GrSurfaceOrigin origin,
|
||||
const SkMatrix* viewMatrix,
|
||||
const GrScissorState* scissor,
|
||||
const GrStencilSettings* stencil)
|
||||
: fUseHWAA(useHWAA)
|
||||
, fProxy(proxy)
|
||||
, fOrigin(origin)
|
||||
, fViewMatrix(viewMatrix)
|
||||
, fScissor(scissor)
|
||||
, fStencil(stencil) {
|
||||
}
|
||||
bool fUseHWAA;
|
||||
GrRenderTargetProxy* fProxy;
|
||||
GrSurfaceOrigin fOrigin;
|
||||
const SkMatrix* fViewMatrix;
|
||||
const GrScissorState* fScissor;
|
||||
const GrStencilSettings* fStencil;
|
||||
};
|
||||
|
||||
void stencilPath(const StencilPathArgs& args, const GrPath* path);
|
||||
|
||||
void drawPath(GrRenderTarget*,
|
||||
const GrProgramInfo&,
|
||||
const GrStencilSettings& stencilPassSettings, // Cover pass settings in pipeline.
|
||||
const GrPath* path);
|
||||
|
||||
protected:
|
||||
GrPathRendering(GrGpu* gpu) : fGpu(gpu) { }
|
||||
|
||||
virtual void onStencilPath(const StencilPathArgs&, const GrPath*) = 0;
|
||||
virtual void onDrawPath(const GrStencilSettings&, const GrPath*) = 0;
|
||||
|
||||
GrGpu* fGpu;
|
||||
private:
|
||||
GrPathRendering& operator=(const GrPathRendering&);
|
||||
};
|
||||
|
||||
#endif
|
@ -1,56 +0,0 @@
|
||||
/*
|
||||
* Copyright 2018 Google LLC.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "include/core/SkTypes.h"
|
||||
#include "src/gpu/GrCaps.h"
|
||||
#include "src/gpu/GrGpu.h"
|
||||
#include "src/gpu/GrPath.h"
|
||||
#include "src/gpu/GrPathRenderer.h"
|
||||
#include "src/gpu/GrPathRendering.h"
|
||||
#include "src/gpu/GrResourceProvider.h"
|
||||
#include "src/gpu/gl/GrGLGpu.h"
|
||||
#include "src/gpu/gl/GrGLPathRendering.h"
|
||||
#include "src/gpu/ops/GrStencilAndCoverPathRenderer.h"
|
||||
#include "src/gpu/ops/GrStencilPathOp.h"
|
||||
|
||||
class GrRecordingContext;
|
||||
|
||||
GrPathRenderer* GrStencilAndCoverPathRenderer::Create(GrResourceProvider* resourceProvider,
|
||||
const GrCaps& caps) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
GrGLPathRendering::GrGLPathRendering(GrGLGpu* gpu)
|
||||
: GrPathRendering(gpu)
|
||||
, fPreallocatedPathCount(0) {}
|
||||
|
||||
GrGLPathRendering::~GrGLPathRendering() {}
|
||||
|
||||
void GrGLPathRendering::disconnect(GrGpu::DisconnectType) {}
|
||||
|
||||
void GrGLPathRendering::resetContext() {}
|
||||
|
||||
void GrGLPathRendering::setProgramPathFragmentInputTransform(GrGLuint, GrGLint,
|
||||
GrGLenum, GrGLint,
|
||||
const SkMatrix&) {}
|
||||
|
||||
void GrGLPathRendering::setProjectionMatrix(const SkMatrix&, const SkISize&, GrSurfaceOrigin) {}
|
||||
|
||||
sk_sp<GrPath> GrGLPathRendering::createPath(const SkPath&, const GrStyle&) { return nullptr; }
|
||||
|
||||
void GrGLPathRendering::onDrawPath(const GrStencilSettings&, const GrPath*) {}
|
||||
|
||||
void GrGLPathRendering::onStencilPath(const StencilPathArgs&, const GrPath*) {}
|
||||
|
||||
GrOp::Owner GrStencilPathOp::Make(GrRecordingContext*,
|
||||
const SkMatrix&,
|
||||
bool,
|
||||
bool,
|
||||
const GrScissorState&,
|
||||
sk_sp<const GrPath>) { return nullptr; }
|
||||
|
||||
void GrPath::ComputeKey(const GrStyledShape&, GrUniqueKey*, bool*) {}
|
@ -219,8 +219,6 @@ public:
|
||||
the object. */
|
||||
virtual GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const = 0;
|
||||
|
||||
virtual bool isPathRendering() const { return false; }
|
||||
|
||||
// We use these methods as a temporary back door to inject OpenGL tessellation code. Once
|
||||
// tessellation is supported by SkSL we can remove these.
|
||||
virtual SkString getTessControlShaderGLSL(const GrGLSLPrimitiveProcessor*,
|
||||
|
@ -99,11 +99,6 @@ public:
|
||||
void validate(bool flushTime) const;
|
||||
void checkAllInstantiated() const;
|
||||
void checkMSAAAndMIPSAreResolved() const;
|
||||
|
||||
bool isNVPR() const {
|
||||
return fPrimProc->isPathRendering() && !fPrimProc->willUseGeoShader() &&
|
||||
!fPrimProc->numVertexAttributes() && !fPrimProc->numInstanceAttributes();
|
||||
}
|
||||
#endif
|
||||
|
||||
private:
|
||||
|
@ -19,8 +19,6 @@
|
||||
#include "src/gpu/GrGpu.h"
|
||||
#include "src/gpu/GrGpuBuffer.h"
|
||||
#include "src/gpu/GrImageInfo.h"
|
||||
#include "src/gpu/GrPath.h"
|
||||
#include "src/gpu/GrPathRendering.h"
|
||||
#include "src/gpu/GrProxyProvider.h"
|
||||
#include "src/gpu/GrRenderTarget.h"
|
||||
#include "src/gpu/GrResourceCache.h"
|
||||
@ -449,15 +447,6 @@ int GrResourceProvider::NumVertsPerAAQuad() { return kVertsPerAAQuad; }
|
||||
int GrResourceProvider::NumIndicesPerAAQuad() { return kIndicesPerAAQuad; }
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
sk_sp<GrPath> GrResourceProvider::createPath(const SkPath& path, const GrStyle& style) {
|
||||
if (this->isAbandoned()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SkASSERT(this->gpu()->pathRendering());
|
||||
return this->gpu()->pathRendering()->createPath(path, style);
|
||||
}
|
||||
|
||||
sk_sp<GrGpuBuffer> GrResourceProvider::createBuffer(size_t size, GrGpuBufferType intendedType,
|
||||
GrAccessPattern accessPattern,
|
||||
const void* data) {
|
||||
|
@ -238,12 +238,6 @@ public:
|
||||
static int NumVertsPerAAQuad();
|
||||
static int NumIndicesPerAAQuad();
|
||||
|
||||
/**
|
||||
* Factories for GrPath objects. It's an error to call these if path rendering
|
||||
* is not supported.
|
||||
*/
|
||||
sk_sp<GrPath> createPath(const SkPath&, const GrStyle&);
|
||||
|
||||
/**
|
||||
* Returns a buffer.
|
||||
*
|
||||
|
@ -18,7 +18,6 @@ GrShaderCaps::GrShaderCaps(const GrContextOptions& options) {
|
||||
fShaderDerivativeSupport = false;
|
||||
fGeometryShaderSupport = false;
|
||||
fGSInvocationsSupport = false;
|
||||
fPathRenderingSupport = false;
|
||||
fDstReadInShaderSupport = false;
|
||||
fDualSourceBlendingSupport = false;
|
||||
fIntegerSupport = false;
|
||||
@ -86,7 +85,6 @@ void GrShaderCaps::dumpJSON(SkJSONWriter* writer) const {
|
||||
writer->appendBool("Shader Derivative Support", fShaderDerivativeSupport);
|
||||
writer->appendBool("Geometry Shader Support", fGeometryShaderSupport);
|
||||
writer->appendBool("Geometry Shader Invocations Support", fGSInvocationsSupport);
|
||||
writer->appendBool("Path Rendering Support", fPathRenderingSupport);
|
||||
writer->appendBool("Dst Read In Shader Support", fDstReadInShaderSupport);
|
||||
writer->appendBool("Dual Source Blending Support", fDualSourceBlendingSupport);
|
||||
writer->appendBool("Integer Support", fIntegerSupport);
|
||||
|
@ -44,7 +44,6 @@ public:
|
||||
bool shaderDerivativeSupport() const { return fShaderDerivativeSupport; }
|
||||
bool geometryShaderSupport() const { return fGeometryShaderSupport; }
|
||||
bool gsInvocationsSupport() const { return fGSInvocationsSupport; }
|
||||
bool pathRenderingSupport() const { return fPathRenderingSupport; }
|
||||
bool dstReadInShaderSupport() const { return fDstReadInShaderSupport; }
|
||||
bool dualSourceBlendingSupport() const { return fDualSourceBlendingSupport; }
|
||||
bool integerSupport() const { return fIntegerSupport; }
|
||||
@ -263,7 +262,6 @@ private:
|
||||
bool fShaderDerivativeSupport : 1;
|
||||
bool fGeometryShaderSupport : 1;
|
||||
bool fGSInvocationsSupport : 1;
|
||||
bool fPathRenderingSupport : 1;
|
||||
bool fDstReadInShaderSupport : 1;
|
||||
bool fDualSourceBlendingSupport : 1;
|
||||
bool fIntegerSupport : 1;
|
||||
|
@ -43,6 +43,7 @@
|
||||
#include "src/gpu/GrProxyProvider.h"
|
||||
#include "src/gpu/GrRenderTarget.h"
|
||||
#include "src/gpu/GrResourceProvider.h"
|
||||
#include "src/gpu/GrStencilSettings.h"
|
||||
#include "src/gpu/GrStyle.h"
|
||||
#include "src/gpu/GrTracing.h"
|
||||
#include "src/gpu/SkGr.h"
|
||||
@ -64,7 +65,6 @@
|
||||
#include "src/gpu/ops/GrOvalOpFactory.h"
|
||||
#include "src/gpu/ops/GrRegionOp.h"
|
||||
#include "src/gpu/ops/GrShadowRRectOp.h"
|
||||
#include "src/gpu/ops/GrStencilPathOp.h"
|
||||
#include "src/gpu/ops/GrStrokeRectOp.h"
|
||||
#include "src/gpu/ops/GrTextureOp.h"
|
||||
#include "src/gpu/text/GrSDFTControl.h"
|
||||
@ -818,51 +818,6 @@ bool GrSurfaceDrawContext::stencilPath(const GrHardClip* clip,
|
||||
return true;
|
||||
}
|
||||
|
||||
void GrSurfaceDrawContext::stencilPath(const GrHardClip* clip,
|
||||
GrAA doStencilMSAA,
|
||||
const SkMatrix& viewMatrix,
|
||||
sk_sp<const GrPath> path) {
|
||||
ASSERT_SINGLE_OWNER
|
||||
RETURN_IF_ABANDONED
|
||||
SkDEBUGCODE(this->validate();)
|
||||
GR_CREATE_TRACE_MARKER_CONTEXT("GrSurfaceDrawContext", "stencilPath", fContext);
|
||||
|
||||
// TODO: extract portions of checkDraw that are relevant to path stenciling.
|
||||
SkASSERT(path);
|
||||
SkASSERT(this->caps()->shaderCaps()->pathRenderingSupport());
|
||||
|
||||
// FIXME: Use path bounds instead of this WAR once
|
||||
// https://bugs.chromium.org/p/skia/issues/detail?id=5640 is resolved.
|
||||
SkIRect bounds = SkIRect::MakeSize(this->dimensions());
|
||||
|
||||
// Setup clip and reject offscreen paths; we do this explicitly instead of relying on addDrawOp
|
||||
// because GrStencilPathOp is not a draw op as its state depends directly on the choices made
|
||||
// during this clip application.
|
||||
GrAppliedHardClip appliedClip(this->dimensions(),
|
||||
this->asSurfaceProxy()->backingStoreDimensions());
|
||||
|
||||
if (clip && GrClip::Effect::kClippedOut == clip->apply(&appliedClip, &bounds)) {
|
||||
return;
|
||||
}
|
||||
// else see FIXME above; we'd normally want to check path bounds with render target bounds,
|
||||
// but as it is, we're just using the full render target so intersecting the two bounds would
|
||||
// do nothing.
|
||||
|
||||
GrOp::Owner op = GrStencilPathOp::Make(fContext,
|
||||
viewMatrix,
|
||||
doStencilMSAA == GrAA::kYes,
|
||||
appliedClip.hasStencilClip(),
|
||||
appliedClip.scissorState(),
|
||||
std::move(path));
|
||||
if (!op) {
|
||||
return;
|
||||
}
|
||||
op->setClippedBounds(SkRect::Make(bounds));
|
||||
|
||||
this->setNeedsStencil(GrAA::kYes == doStencilMSAA);
|
||||
this->addOp(std::move(op));
|
||||
}
|
||||
|
||||
void GrSurfaceDrawContext::drawTextureSet(const GrClip* clip,
|
||||
TextureSetEntry set[],
|
||||
int cnt,
|
||||
|
@ -592,12 +592,6 @@ public:
|
||||
const SkMatrix& viewMatrix,
|
||||
const SkPath&);
|
||||
|
||||
// Same as for stencilPath, but for an NVPR path object.
|
||||
void stencilPath(const GrHardClip*,
|
||||
GrAA doStencilMSAA,
|
||||
const SkMatrix& viewMatrix,
|
||||
sk_sp<const GrPath>);
|
||||
|
||||
/**
|
||||
* Draws a path, either AA or not, and touches the stencil buffer with the user stencil settings
|
||||
* for each color sample written.
|
||||
|
@ -48,12 +48,6 @@ public:
|
||||
void setMatrix3fv(UniformHandle, int arrayCount, const float matrices[]) const override;
|
||||
void setMatrix4fv(UniformHandle, int arrayCount, const float matrices[]) const override;
|
||||
|
||||
// for nvpr only
|
||||
void setPathFragmentInputTransform(VaryingHandle u, int components,
|
||||
const SkMatrix& matrix) const override {
|
||||
SK_ABORT("Only supported in NVPR, which is only available in GL");
|
||||
}
|
||||
|
||||
// For the uniform data to be dirty so that we will reupload on the next use.
|
||||
void markDirty() { fUniformsDirty = true; }
|
||||
|
||||
|
@ -354,8 +354,6 @@ void GrGLCaps::init(const GrContextOptions& contextOptions,
|
||||
this->initGLSL(ctxInfo, gli);
|
||||
GrShaderCaps* shaderCaps = fShaderCaps.get();
|
||||
|
||||
shaderCaps->fPathRenderingSupport = this->hasPathRenderingSupport(ctxInfo, gli);
|
||||
|
||||
// Enable supported shader-related caps
|
||||
if (GR_IS_GR_GL(standard)) {
|
||||
shaderCaps->fDualSourceBlendingSupport =
|
||||
@ -993,42 +991,6 @@ void GrGLCaps::initGLSL(const GrGLContextInfo& ctxInfo, const GrGLInterface* gli
|
||||
}
|
||||
}
|
||||
|
||||
bool GrGLCaps::hasPathRenderingSupport(const GrGLContextInfo& ctxInfo, const GrGLInterface* gli) {
|
||||
bool hasChromiumPathRendering = ctxInfo.hasExtension("GL_CHROMIUM_path_rendering");
|
||||
|
||||
if (!(ctxInfo.hasExtension("GL_NV_path_rendering") || hasChromiumPathRendering)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (GR_IS_GR_GL(ctxInfo.standard())) {
|
||||
if (ctxInfo.version() < GR_GL_VER(4, 3) &&
|
||||
!ctxInfo.hasExtension("GL_ARB_program_interface_query")) {
|
||||
return false;
|
||||
}
|
||||
} else if (GR_IS_GR_GL_ES(ctxInfo.standard())) {
|
||||
if (!hasChromiumPathRendering &&
|
||||
ctxInfo.version() < GR_GL_VER(3, 1)) {
|
||||
return false;
|
||||
}
|
||||
} else if (GR_IS_GR_WEBGL(ctxInfo.standard())) {
|
||||
// No WebGL support
|
||||
return false;
|
||||
}
|
||||
// We only support v1.3+ of GL_NV_path_rendering which allows us to
|
||||
// set individual fragment inputs with ProgramPathFragmentInputGen. The API
|
||||
// additions are detected by checking the existence of the function.
|
||||
// We also use *Then* functions that not all drivers might have. Check
|
||||
// them for consistency.
|
||||
if (!gli->fFunctions.fStencilThenCoverFillPath ||
|
||||
!gli->fFunctions.fStencilThenCoverStrokePath ||
|
||||
!gli->fFunctions.fStencilThenCoverFillPathInstanced ||
|
||||
!gli->fFunctions.fStencilThenCoverStrokePathInstanced ||
|
||||
!gli->fFunctions.fProgramPathFragmentInputGen) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void GrGLCaps::initFSAASupport(const GrContextOptions& contextOptions,
|
||||
const GrGLContextInfo& ctxInfo, const GrGLInterface* gli) {
|
||||
if (ctxInfo.hasExtension("GL_NV_framebuffer_mixed_samples") ||
|
||||
@ -3944,19 +3906,6 @@ void GrGLCaps::applyDriverCorrectnessWorkarounds(const GrGLContextInfo& ctxInfo,
|
||||
}
|
||||
}
|
||||
|
||||
// Workaround NVIDIA bug related to glInvalidateFramebuffer and mixed samples.
|
||||
if (fMultisampleDisableSupport &&
|
||||
this->shaderCaps()->dualSourceBlendingSupport() &&
|
||||
this->shaderCaps()->pathRenderingSupport() &&
|
||||
fMixedSamplesSupport &&
|
||||
#if GR_TEST_UTILS
|
||||
(contextOptions.fGpuPathRenderers & GpuPathRenderers::kStencilAndCover) &&
|
||||
#endif
|
||||
(kNVIDIA_GrGLDriver == ctxInfo.driver() ||
|
||||
kChromium_GrGLDriver == ctxInfo.driver())) {
|
||||
fInvalidateFBType = kNone_InvalidateFBType;
|
||||
}
|
||||
|
||||
// Many ES3 drivers only advertise the ES2 image_external extension, but support the _essl3
|
||||
// extension, and require that it be enabled to work with ESSL3. Other devices require the ES2
|
||||
// extension to be enabled, even when using ESSL3. Enabling both extensions fixes both cases.
|
||||
|
@ -479,7 +479,6 @@ private:
|
||||
|
||||
void init(const GrContextOptions&, const GrGLContextInfo&, const GrGLInterface*);
|
||||
void initGLSL(const GrGLContextInfo&, const GrGLInterface*);
|
||||
bool hasPathRenderingSupport(const GrGLContextInfo&, const GrGLInterface*);
|
||||
|
||||
struct FormatWorkarounds {
|
||||
bool fDisableSRGBRenderWithMSAAForMacAMD = false;
|
||||
|
@ -372,10 +372,6 @@ GrGLGpu::GrGLGpu(std::unique_ptr<GrGLContext> ctx, GrDirectContext* dContext)
|
||||
}
|
||||
static_assert(kGrGpuBufferTypeCount == SK_ARRAY_COUNT(fHWBufferState));
|
||||
|
||||
if (this->glCaps().shaderCaps()->pathRenderingSupport()) {
|
||||
fPathRendering = std::make_unique<GrGLPathRendering>(this);
|
||||
}
|
||||
|
||||
if (this->glCaps().useSamplerObjects()) {
|
||||
fSamplerObjectCache = std::make_unique<SamplerObjectCache>(this);
|
||||
}
|
||||
@ -384,7 +380,6 @@ GrGLGpu::GrGLGpu(std::unique_ptr<GrGLContext> ctx, GrDirectContext* dContext)
|
||||
GrGLGpu::~GrGLGpu() {
|
||||
// Ensure any GrGpuResource objects get deleted first, since they may require a working GrGLGpu
|
||||
// to release the resources held by the objects themselves.
|
||||
fPathRendering.reset();
|
||||
fCopyProgramArrayBuffer.reset();
|
||||
fMipmapProgramArrayBuffer.reset();
|
||||
if (fProgramCache) {
|
||||
@ -480,9 +475,6 @@ void GrGLGpu::disconnect(DisconnectType type) {
|
||||
fMipmapPrograms[i].fProgram = 0;
|
||||
}
|
||||
|
||||
if (this->glCaps().shaderCaps()->pathRenderingSupport()) {
|
||||
this->glPathRendering()->disconnect(type);
|
||||
}
|
||||
fFinishCallbacks.callAll(/* doDelete */ DisconnectType::kCleanup == type);
|
||||
}
|
||||
|
||||
@ -606,12 +598,6 @@ void GrGLGpu::onResetContext(uint32_t resetBits) {
|
||||
fBoundDrawFramebuffer = 0;
|
||||
}
|
||||
|
||||
if (resetBits & kPathRendering_GrGLBackendState) {
|
||||
if (this->caps()->shaderCaps()->pathRenderingSupport()) {
|
||||
this->glPathRendering()->resetContext();
|
||||
}
|
||||
}
|
||||
|
||||
// we assume these values
|
||||
if (resetBits & kPixelStore_GrGLBackendState) {
|
||||
if (this->caps()->writePixelsRowBytesSupport()) {
|
||||
|
@ -20,7 +20,6 @@
|
||||
#include "src/gpu/GrXferProcessor.h"
|
||||
#include "src/gpu/gl/GrGLAttachment.h"
|
||||
#include "src/gpu/gl/GrGLContext.h"
|
||||
#include "src/gpu/gl/GrGLPathRendering.h"
|
||||
#include "src/gpu/gl/GrGLProgram.h"
|
||||
#include "src/gpu/gl/GrGLRenderTarget.h"
|
||||
#include "src/gpu/gl/GrGLTexture.h"
|
||||
@ -50,11 +49,6 @@ public:
|
||||
GrGLSLGeneration glslGeneration() const { return fGLContext->glslGeneration(); }
|
||||
const GrGLCaps& glCaps() const { return *fGLContext->caps(); }
|
||||
|
||||
GrGLPathRendering* glPathRendering() {
|
||||
SkASSERT(glCaps().shaderCaps()->pathRenderingSupport());
|
||||
return static_cast<GrGLPathRendering*>(pathRendering());
|
||||
}
|
||||
|
||||
// Used by GrGLProgram to configure OpenGL state.
|
||||
void bindTexture(int unitIdx, GrSamplerState samplerState, const GrSwizzle&, GrGLTexture*);
|
||||
|
||||
|
@ -1,347 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "src/core/SkPathPriv.h"
|
||||
#include "src/gpu/GrStyle.h"
|
||||
#include "src/gpu/gl/GrGLGpu.h"
|
||||
#include "src/gpu/gl/GrGLPath.h"
|
||||
#include "src/gpu/gl/GrGLPathRendering.h"
|
||||
|
||||
namespace {
|
||||
inline GrGLubyte verb_to_gl_path_cmd(SkPath::Verb verb) {
|
||||
static const GrGLubyte gTable[] = {
|
||||
GR_GL_MOVE_TO,
|
||||
GR_GL_LINE_TO,
|
||||
GR_GL_QUADRATIC_CURVE_TO,
|
||||
GR_GL_CONIC_CURVE_TO,
|
||||
GR_GL_CUBIC_CURVE_TO,
|
||||
GR_GL_CLOSE_PATH,
|
||||
};
|
||||
static_assert(0 == SkPath::kMove_Verb);
|
||||
static_assert(1 == SkPath::kLine_Verb);
|
||||
static_assert(2 == SkPath::kQuad_Verb);
|
||||
static_assert(3 == SkPath::kConic_Verb);
|
||||
static_assert(4 == SkPath::kCubic_Verb);
|
||||
static_assert(5 == SkPath::kClose_Verb);
|
||||
|
||||
SkASSERT(verb >= 0 && (size_t)verb < SK_ARRAY_COUNT(gTable));
|
||||
return gTable[verb];
|
||||
}
|
||||
|
||||
#ifdef SK_DEBUG
|
||||
inline int num_coords(SkPath::Verb verb) {
|
||||
static const int gTable[] = {
|
||||
2, // move
|
||||
2, // line
|
||||
4, // quad
|
||||
5, // conic
|
||||
6, // cubic
|
||||
0, // close
|
||||
};
|
||||
static_assert(0 == SkPath::kMove_Verb);
|
||||
static_assert(1 == SkPath::kLine_Verb);
|
||||
static_assert(2 == SkPath::kQuad_Verb);
|
||||
static_assert(3 == SkPath::kConic_Verb);
|
||||
static_assert(4 == SkPath::kCubic_Verb);
|
||||
static_assert(5 == SkPath::kClose_Verb);
|
||||
|
||||
SkASSERT(verb >= 0 && (size_t)verb < SK_ARRAY_COUNT(gTable));
|
||||
return gTable[verb];
|
||||
}
|
||||
#endif
|
||||
|
||||
inline GrGLenum join_to_gl_join(SkPaint::Join join) {
|
||||
static GrGLenum gSkJoinsToGrGLJoins[] = {
|
||||
GR_GL_MITER_REVERT,
|
||||
GR_GL_ROUND,
|
||||
GR_GL_BEVEL
|
||||
};
|
||||
return gSkJoinsToGrGLJoins[join];
|
||||
static_assert(0 == SkPaint::kMiter_Join);
|
||||
static_assert(1 == SkPaint::kRound_Join);
|
||||
static_assert(2 == SkPaint::kBevel_Join);
|
||||
static_assert(SK_ARRAY_COUNT(gSkJoinsToGrGLJoins) == SkPaint::kJoinCount);
|
||||
}
|
||||
|
||||
inline GrGLenum cap_to_gl_cap(SkPaint::Cap cap) {
|
||||
static GrGLenum gSkCapsToGrGLCaps[] = {
|
||||
GR_GL_FLAT,
|
||||
GR_GL_ROUND,
|
||||
GR_GL_SQUARE
|
||||
};
|
||||
return gSkCapsToGrGLCaps[cap];
|
||||
static_assert(0 == SkPaint::kButt_Cap);
|
||||
static_assert(1 == SkPaint::kRound_Cap);
|
||||
static_assert(2 == SkPaint::kSquare_Cap);
|
||||
static_assert(SK_ARRAY_COUNT(gSkCapsToGrGLCaps) == SkPaint::kCapCount);
|
||||
}
|
||||
|
||||
#ifdef SK_DEBUG
|
||||
inline void verify_floats(const float* floats, int count) {
|
||||
for (int i = 0; i < count; ++i) {
|
||||
SkASSERT(!SkScalarIsNaN(SkFloatToScalar(floats[i])));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
inline void points_to_coords(const SkPoint points[], size_t first_point, size_t amount,
|
||||
GrGLfloat coords[]) {
|
||||
for (size_t i = 0; i < amount; ++i) {
|
||||
coords[i * 2] = SkScalarToFloat(points[first_point + i].fX);
|
||||
coords[i * 2 + 1] = SkScalarToFloat(points[first_point + i].fY);
|
||||
}
|
||||
}
|
||||
|
||||
template<bool checkForDegenerates>
|
||||
inline bool init_path_object_for_general_path(GrGLGpu* gpu, GrGLuint pathID,
|
||||
const SkPath& skPath) {
|
||||
SkDEBUGCODE(int numCoords = 0);
|
||||
int verbCnt = skPath.countVerbs();
|
||||
int pointCnt = skPath.countPoints();
|
||||
int minCoordCnt = pointCnt * 2;
|
||||
|
||||
SkSTArray<16, GrGLubyte, true> pathCommands(verbCnt);
|
||||
SkSTArray<16, GrGLfloat, true> pathCoords(minCoordCnt);
|
||||
bool lastVerbWasMove = true; // A path with just "close;" means "moveto(0,0); close;"
|
||||
for (auto [verb, points, w] : SkPathPriv::Iterate(skPath)) {
|
||||
pathCommands.push_back(verb_to_gl_path_cmd((SkPath::Verb)verb));
|
||||
GrGLfloat coords[6];
|
||||
int coordsForVerb;
|
||||
switch (verb) {
|
||||
case SkPathVerb::kMove:
|
||||
if (checkForDegenerates) {
|
||||
lastVerbWasMove = true;
|
||||
}
|
||||
points_to_coords(points, 0, 1, coords);
|
||||
coordsForVerb = 2;
|
||||
break;
|
||||
case SkPathVerb::kLine:
|
||||
if (checkForDegenerates) {
|
||||
if (SkPath::IsLineDegenerate(points[0], points[1], true)) {
|
||||
return false;
|
||||
}
|
||||
lastVerbWasMove = false;
|
||||
}
|
||||
|
||||
points_to_coords(points, 1, 1, coords);
|
||||
coordsForVerb = 2;
|
||||
break;
|
||||
case SkPathVerb::kConic:
|
||||
if (checkForDegenerates) {
|
||||
if (SkPath::IsQuadDegenerate(points[0], points[1], points[2], true)) {
|
||||
return false;
|
||||
}
|
||||
lastVerbWasMove = false;
|
||||
}
|
||||
points_to_coords(points, 1, 2, coords);
|
||||
coords[4] = SkScalarToFloat(*w);
|
||||
coordsForVerb = 5;
|
||||
break;
|
||||
case SkPathVerb::kQuad:
|
||||
if (checkForDegenerates) {
|
||||
if (SkPath::IsQuadDegenerate(points[0], points[1], points[2], true)) {
|
||||
return false;
|
||||
}
|
||||
lastVerbWasMove = false;
|
||||
}
|
||||
points_to_coords(points, 1, 2, coords);
|
||||
coordsForVerb = 4;
|
||||
break;
|
||||
case SkPathVerb::kCubic:
|
||||
if (checkForDegenerates) {
|
||||
if (SkPath::IsCubicDegenerate(points[0], points[1], points[2], points[3],
|
||||
true)) {
|
||||
return false;
|
||||
}
|
||||
lastVerbWasMove = false;
|
||||
}
|
||||
points_to_coords(points, 1, 3, coords);
|
||||
coordsForVerb = 6;
|
||||
break;
|
||||
case SkPathVerb::kClose:
|
||||
if (checkForDegenerates) {
|
||||
if (lastVerbWasMove) {
|
||||
// Interpret "move(x,y);close;" as "move(x,y);lineto(x,y);close;".
|
||||
// which produces a degenerate segment.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
SkDEBUGCODE(numCoords += num_coords((SkPath::Verb)verb));
|
||||
SkDEBUGCODE(verify_floats(coords, coordsForVerb));
|
||||
pathCoords.push_back_n(coordsForVerb, coords);
|
||||
}
|
||||
SkASSERT(verbCnt == pathCommands.count());
|
||||
SkASSERT(numCoords == pathCoords.count());
|
||||
|
||||
GR_GL_CALL(gpu->glInterface(),
|
||||
PathCommands(pathID, pathCommands.count(), pathCommands.begin(),
|
||||
pathCoords.count(), GR_GL_FLOAT, pathCoords.begin()));
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* For now paths only natively support winding and even odd fill types
|
||||
*/
|
||||
static GrPathRendering::FillType convert_skpath_filltype(SkPathFillType fill) {
|
||||
switch (fill) {
|
||||
default:
|
||||
SK_ABORT("Incomplete Switch\n");
|
||||
case SkPathFillType::kWinding:
|
||||
case SkPathFillType::kInverseWinding:
|
||||
return GrPathRendering::kWinding_FillType;
|
||||
case SkPathFillType::kEvenOdd:
|
||||
case SkPathFillType::kInverseEvenOdd:
|
||||
return GrPathRendering::kEvenOdd_FillType;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool GrGLPath::InitPathObjectPathDataCheckingDegenerates(GrGLGpu* gpu, GrGLuint pathID,
|
||||
const SkPath& skPath) {
|
||||
return init_path_object_for_general_path<true>(gpu, pathID, skPath);
|
||||
}
|
||||
|
||||
void GrGLPath::InitPathObjectPathData(GrGLGpu* gpu,
|
||||
GrGLuint pathID,
|
||||
const SkPath& skPath) {
|
||||
SkASSERT(!skPath.isEmpty());
|
||||
|
||||
#if 1 // SK_SCALAR_IS_FLOAT
|
||||
// This branch does type punning, converting SkPoint* to GrGLfloat*.
|
||||
if ((skPath.getSegmentMasks() & SkPath::kConic_SegmentMask) == 0) {
|
||||
int verbCnt = skPath.countVerbs();
|
||||
int pointCnt = skPath.countPoints();
|
||||
int coordCnt = pointCnt * 2;
|
||||
SkAutoSTArray<16, GrGLubyte> pathCommands(verbCnt);
|
||||
SkAutoSTArray<16, GrGLfloat> pathCoords(coordCnt);
|
||||
|
||||
static_assert(sizeof(SkPoint) == sizeof(GrGLfloat) * 2, "sk_point_not_two_floats");
|
||||
|
||||
skPath.getPoints(reinterpret_cast<SkPoint*>(&pathCoords[0]), pointCnt);
|
||||
skPath.getVerbs(&pathCommands[0], verbCnt);
|
||||
|
||||
SkDEBUGCODE(int verbCoordCnt = 0);
|
||||
for (int i = 0; i < verbCnt; ++i) {
|
||||
SkPath::Verb v = static_cast<SkPath::Verb>(pathCommands[i]);
|
||||
pathCommands[i] = verb_to_gl_path_cmd(v);
|
||||
SkDEBUGCODE(verbCoordCnt += num_coords(v));
|
||||
}
|
||||
SkASSERT(verbCnt == pathCommands.count());
|
||||
SkASSERT(verbCoordCnt == pathCoords.count());
|
||||
SkDEBUGCODE(verify_floats(&pathCoords[0], pathCoords.count()));
|
||||
GR_GL_CALL(gpu->glInterface(), PathCommands(pathID, pathCommands.count(), &pathCommands[0],
|
||||
pathCoords.count(), GR_GL_FLOAT,
|
||||
&pathCoords[0]));
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
SkAssertResult(init_path_object_for_general_path<false>(gpu, pathID, skPath));
|
||||
}
|
||||
|
||||
void GrGLPath::InitPathObjectStroke(GrGLGpu* gpu, GrGLuint pathID, const SkStrokeRec& stroke) {
|
||||
SkASSERT(!stroke.isHairlineStyle());
|
||||
GR_GL_CALL(gpu->glInterface(),
|
||||
PathParameterf(pathID, GR_GL_PATH_STROKE_WIDTH, SkScalarToFloat(stroke.getWidth())));
|
||||
GR_GL_CALL(gpu->glInterface(),
|
||||
PathParameterf(pathID, GR_GL_PATH_MITER_LIMIT, SkScalarToFloat(stroke.getMiter())));
|
||||
GrGLenum join = join_to_gl_join(stroke.getJoin());
|
||||
GR_GL_CALL(gpu->glInterface(), PathParameteri(pathID, GR_GL_PATH_JOIN_STYLE, join));
|
||||
GrGLenum cap = cap_to_gl_cap(stroke.getCap());
|
||||
GR_GL_CALL(gpu->glInterface(), PathParameteri(pathID, GR_GL_PATH_END_CAPS, cap));
|
||||
GR_GL_CALL(gpu->glInterface(), PathParameterf(pathID, GR_GL_PATH_STROKE_BOUND, 0.02f));
|
||||
}
|
||||
|
||||
void GrGLPath::InitPathObjectEmptyPath(GrGLGpu* gpu, GrGLuint pathID) {
|
||||
GR_GL_CALL(gpu->glInterface(), PathCommands(pathID, 0, nullptr, 0, GR_GL_FLOAT, nullptr));
|
||||
}
|
||||
|
||||
GrGLPath::GrGLPath(GrGLGpu* gpu, const SkPath& origSkPath, const GrStyle& style)
|
||||
: INHERITED(gpu, origSkPath, style),
|
||||
fPathID(gpu->glPathRendering()->genPaths(1)) {
|
||||
|
||||
if (origSkPath.isEmpty()) {
|
||||
InitPathObjectEmptyPath(gpu, fPathID);
|
||||
fShouldStroke = false;
|
||||
fShouldFill = false;
|
||||
} else {
|
||||
const SkPath* skPath = &origSkPath;
|
||||
SkTLazy<SkPath> tmpPath;
|
||||
SkStrokeRec stroke(SkStrokeRec::kFill_InitStyle);
|
||||
|
||||
if (style.pathEffect()) {
|
||||
// Skia stroking and NVPR stroking differ with respect to dashing
|
||||
// pattern.
|
||||
// Convert a dashing (or other path effect) to either a stroke or a fill.
|
||||
if (style.applyPathEffectToPath(tmpPath.init(), &stroke, *skPath, SK_Scalar1)) {
|
||||
skPath = tmpPath.get();
|
||||
}
|
||||
} else {
|
||||
stroke = style.strokeRec();
|
||||
}
|
||||
|
||||
// applyPathEffectToPath could have generated an empty path
|
||||
if (skPath->isEmpty()) {
|
||||
InitPathObjectEmptyPath(gpu, fPathID);
|
||||
fShouldStroke = false;
|
||||
fShouldFill = false;
|
||||
} else {
|
||||
bool didInit = false;
|
||||
if (stroke.needToApply() && stroke.getCap() != SkPaint::kButt_Cap) {
|
||||
// Skia stroking and NVPR stroking differ with respect to stroking
|
||||
// end caps of empty subpaths.
|
||||
// Convert stroke to fill if path contains empty subpaths.
|
||||
didInit = InitPathObjectPathDataCheckingDegenerates(gpu, fPathID, *skPath);
|
||||
if (!didInit) {
|
||||
if (!tmpPath.isValid()) {
|
||||
tmpPath.init();
|
||||
}
|
||||
SkAssertResult(stroke.applyToPath(tmpPath.get(), *skPath));
|
||||
skPath = tmpPath.get();
|
||||
stroke.setFillStyle();
|
||||
}
|
||||
}
|
||||
|
||||
if (!didInit) {
|
||||
InitPathObjectPathData(gpu, fPathID, *skPath);
|
||||
}
|
||||
|
||||
fShouldStroke = stroke.needToApply();
|
||||
fShouldFill = stroke.isFillStyle() ||
|
||||
stroke.getStyle() == SkStrokeRec::kStrokeAndFill_Style;
|
||||
|
||||
fFillType = convert_skpath_filltype(skPath->getFillType());
|
||||
fBounds = skPath->getBounds();
|
||||
SkScalar radius = stroke.getInflationRadius();
|
||||
fBounds.outset(radius, radius);
|
||||
if (fShouldStroke) {
|
||||
InitPathObjectStroke(gpu, fPathID, stroke);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this->registerWithCache(SkBudgeted::kYes);
|
||||
}
|
||||
|
||||
void GrGLPath::onRelease() {
|
||||
TRACE_EVENT0("skia.gpu", TRACE_FUNC);
|
||||
|
||||
if (0 != fPathID) {
|
||||
static_cast<GrGLGpu*>(this->getGpu())->glPathRendering()->deletePaths(fPathID, 1);
|
||||
fPathID = 0;
|
||||
}
|
||||
|
||||
INHERITED::onRelease();
|
||||
}
|
||||
|
||||
void GrGLPath::onAbandon() {
|
||||
fPathID = 0;
|
||||
|
||||
INHERITED::onAbandon();
|
||||
}
|
@ -1,56 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef GrGLPath_DEFINED
|
||||
#define GrGLPath_DEFINED
|
||||
|
||||
#include "include/gpu/gl/GrGLTypes.h"
|
||||
#include "src/gpu/GrPath.h"
|
||||
|
||||
class GrGLGpu;
|
||||
class GrStyle;
|
||||
|
||||
/**
|
||||
* Currently this represents a path built using GL_NV_path_rendering. If we
|
||||
* support other GL path extensions then this would have to have a type enum
|
||||
* and/or be subclassed.
|
||||
*/
|
||||
|
||||
class GrGLPath : public GrPath {
|
||||
public:
|
||||
static bool InitPathObjectPathDataCheckingDegenerates(GrGLGpu*,
|
||||
GrGLuint pathID,
|
||||
const SkPath&);
|
||||
static void InitPathObjectPathData(GrGLGpu*,
|
||||
GrGLuint pathID,
|
||||
const SkPath&);
|
||||
static void InitPathObjectStroke(GrGLGpu*, GrGLuint pathID, const SkStrokeRec&);
|
||||
|
||||
static void InitPathObjectEmptyPath(GrGLGpu*, GrGLuint pathID);
|
||||
|
||||
|
||||
GrGLPath(GrGLGpu*, const SkPath&, const GrStyle&);
|
||||
GrGLuint pathID() const { return fPathID; }
|
||||
|
||||
bool shouldStroke() const { return fShouldStroke; }
|
||||
bool shouldFill() const { return fShouldFill; }
|
||||
protected:
|
||||
void onRelease() override;
|
||||
void onAbandon() override;
|
||||
|
||||
private:
|
||||
// TODO: Figure out how to get an approximate size of the path in Gpu memory.
|
||||
size_t onGpuMemorySize() const override { return 100; }
|
||||
|
||||
GrGLuint fPathID;
|
||||
bool fShouldStroke;
|
||||
bool fShouldFill;
|
||||
|
||||
using INHERITED = GrPath;
|
||||
};
|
||||
|
||||
#endif
|
@ -1,259 +0,0 @@
|
||||
/*
|
||||
* Copyright 2014 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "include/core/SkStream.h"
|
||||
#include "include/core/SkTypeface.h"
|
||||
#include "src/core/SkMatrixPriv.h"
|
||||
#include "src/gpu/GrProgramInfo.h"
|
||||
#include "src/gpu/GrRenderTargetProxy.h"
|
||||
#include "src/gpu/gl/GrGLGpu.h"
|
||||
#include "src/gpu/gl/GrGLPath.h"
|
||||
#include "src/gpu/gl/GrGLPathRendering.h"
|
||||
#include "src/gpu/gl/GrGLUtil.h"
|
||||
|
||||
#define GL_CALL(X) GR_GL_CALL(this->gpu()->glInterface(), X)
|
||||
#define GL_CALL_RET(RET, X) GR_GL_CALL_RET(this->gpu()->glInterface(), RET, X)
|
||||
|
||||
// Number of paths to allocate per glGenPaths call. The call can be overly slow on command buffer GL
|
||||
// implementation. The call has a result value, and thus waiting for the call completion is needed.
|
||||
static const GrGLsizei kPathIDPreallocationAmount = 65536;
|
||||
|
||||
static_assert(0 == GrPathRendering::kNone_PathTransformType);
|
||||
static_assert(1 == GrPathRendering::kTranslateX_PathTransformType);
|
||||
static_assert(2 == GrPathRendering::kTranslateY_PathTransformType);
|
||||
static_assert(3 == GrPathRendering::kTranslate_PathTransformType);
|
||||
static_assert(4 == GrPathRendering::kAffine_PathTransformType);
|
||||
static_assert(GrPathRendering::kAffine_PathTransformType == GrPathRendering::kLast_PathTransformType);
|
||||
|
||||
#ifdef SK_DEBUG
|
||||
|
||||
static void verify_floats(const float* floats, int count) {
|
||||
for (int i = 0; i < count; ++i) {
|
||||
SkASSERT(!SkScalarIsNaN(SkFloatToScalar(floats[i])));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static GrGLenum gr_stencil_op_to_gl_path_rendering_fill_mode(GrStencilOp op) {
|
||||
switch (op) {
|
||||
default:
|
||||
SK_ABORT("Unexpected path fill.");
|
||||
/* fallthrough */
|
||||
case GrStencilOp::kIncWrap:
|
||||
return GR_GL_COUNT_UP;
|
||||
case GrStencilOp::kInvert:
|
||||
return GR_GL_INVERT;
|
||||
}
|
||||
}
|
||||
|
||||
GrGLPathRendering::GrGLPathRendering(GrGLGpu* gpu)
|
||||
: GrPathRendering(gpu)
|
||||
, fPreallocatedPathCount(0) {
|
||||
const GrGLInterface* glInterface = gpu->glInterface();
|
||||
fCaps.bindFragmentInputSupport = (bool)glInterface->fFunctions.fBindFragmentInputLocation;
|
||||
}
|
||||
|
||||
GrGLPathRendering::~GrGLPathRendering() {
|
||||
if (fPreallocatedPathCount > 0) {
|
||||
this->deletePaths(fFirstPreallocatedPathID, fPreallocatedPathCount);
|
||||
}
|
||||
}
|
||||
|
||||
void GrGLPathRendering::disconnect(GrGpu::DisconnectType type) {
|
||||
if (GrGpu::DisconnectType::kCleanup == type) {
|
||||
this->deletePaths(fFirstPreallocatedPathID, fPreallocatedPathCount);
|
||||
}
|
||||
fPreallocatedPathCount = 0;
|
||||
}
|
||||
|
||||
void GrGLPathRendering::resetContext() {
|
||||
fHWProjectionMatrixState.invalidate();
|
||||
// we don't use the model view matrix.
|
||||
GL_CALL(MatrixLoadIdentity(GR_GL_PATH_MODELVIEW));
|
||||
|
||||
fHWPathStencilSettings.invalidate();
|
||||
}
|
||||
|
||||
sk_sp<GrPath> GrGLPathRendering::createPath(const SkPath& inPath, const GrStyle& style) {
|
||||
return sk_make_sp<GrGLPath>(this->gpu(), inPath, style);
|
||||
}
|
||||
|
||||
void GrGLPathRendering::onStencilPath(const StencilPathArgs& args, const GrPath* path) {
|
||||
GrGLGpu* gpu = this->gpu();
|
||||
SkASSERT(gpu->caps()->shaderCaps()->pathRenderingSupport());
|
||||
gpu->flushColorWrite(false);
|
||||
|
||||
GrGLRenderTarget* rt = static_cast<GrGLRenderTarget*>(args.fProxy->peekRenderTarget());
|
||||
SkISize dimensions = rt->dimensions();
|
||||
this->setProjectionMatrix(*args.fViewMatrix, dimensions, args.fOrigin);
|
||||
gpu->flushScissor(*args.fScissor, rt->height(), args.fOrigin);
|
||||
gpu->flushHWAAState(rt, args.fUseHWAA);
|
||||
gpu->flushRenderTarget(rt);
|
||||
|
||||
const GrGLPath* glPath = static_cast<const GrGLPath*>(path);
|
||||
|
||||
this->flushPathStencilSettings(*args.fStencil);
|
||||
|
||||
GrGLenum fillMode = gr_stencil_op_to_gl_path_rendering_fill_mode(
|
||||
fHWPathStencilSettings.singleSidedFace().fPassOp);
|
||||
GrGLint writeMask = fHWPathStencilSettings.singleSidedFace().fWriteMask;
|
||||
|
||||
if (glPath->shouldFill()) {
|
||||
GL_CALL(StencilFillPath(glPath->pathID(), fillMode, writeMask));
|
||||
}
|
||||
if (glPath->shouldStroke()) {
|
||||
GL_CALL(StencilStrokePath(glPath->pathID(), 0xffff, writeMask));
|
||||
}
|
||||
}
|
||||
|
||||
void GrGLPathRendering::onDrawPath(const GrStencilSettings& stencilPassSettings,
|
||||
const GrPath* path) {
|
||||
const GrGLPath* glPath = static_cast<const GrGLPath*>(path);
|
||||
|
||||
this->flushPathStencilSettings(stencilPassSettings);
|
||||
|
||||
GrGLenum fillMode = gr_stencil_op_to_gl_path_rendering_fill_mode(
|
||||
fHWPathStencilSettings.singleSidedFace().fPassOp);
|
||||
GrGLint writeMask = fHWPathStencilSettings.singleSidedFace().fWriteMask;
|
||||
|
||||
if (glPath->shouldStroke()) {
|
||||
if (glPath->shouldFill()) {
|
||||
GL_CALL(StencilFillPath(glPath->pathID(), fillMode, writeMask));
|
||||
}
|
||||
GL_CALL(StencilThenCoverStrokePath(glPath->pathID(), 0xffff, writeMask,
|
||||
GR_GL_BOUNDING_BOX));
|
||||
} else {
|
||||
GL_CALL(StencilThenCoverFillPath(glPath->pathID(), fillMode, writeMask,
|
||||
GR_GL_BOUNDING_BOX));
|
||||
}
|
||||
}
|
||||
|
||||
void GrGLPathRendering::setProgramPathFragmentInputTransform(GrGLuint program, GrGLint location,
|
||||
GrGLenum genMode, GrGLint components,
|
||||
const SkMatrix& matrix) {
|
||||
float coefficients[3 * 3];
|
||||
SkASSERT(components >= 1 && components <= 3);
|
||||
|
||||
coefficients[0] = SkScalarToFloat(matrix[SkMatrix::kMScaleX]);
|
||||
coefficients[1] = SkScalarToFloat(matrix[SkMatrix::kMSkewX]);
|
||||
coefficients[2] = SkScalarToFloat(matrix[SkMatrix::kMTransX]);
|
||||
|
||||
if (components >= 2) {
|
||||
coefficients[3] = SkScalarToFloat(matrix[SkMatrix::kMSkewY]);
|
||||
coefficients[4] = SkScalarToFloat(matrix[SkMatrix::kMScaleY]);
|
||||
coefficients[5] = SkScalarToFloat(matrix[SkMatrix::kMTransY]);
|
||||
}
|
||||
|
||||
if (components >= 3) {
|
||||
coefficients[6] = SkScalarToFloat(matrix[SkMatrix::kMPersp0]);
|
||||
coefficients[7] = SkScalarToFloat(matrix[SkMatrix::kMPersp1]);
|
||||
coefficients[8] = SkScalarToFloat(matrix[SkMatrix::kMPersp2]);
|
||||
}
|
||||
SkDEBUGCODE(verify_floats(coefficients, components * 3));
|
||||
|
||||
GL_CALL(ProgramPathFragmentInputGen(program, location, genMode, components, coefficients));
|
||||
}
|
||||
|
||||
void GrGLPathRendering::setProjectionMatrix(const SkMatrix& matrix,
|
||||
const SkISize& renderTargetSize,
|
||||
GrSurfaceOrigin renderTargetOrigin) {
|
||||
|
||||
SkASSERT(this->gpu()->glCaps().shaderCaps()->pathRenderingSupport());
|
||||
|
||||
if (renderTargetOrigin == fHWProjectionMatrixState.fRenderTargetOrigin &&
|
||||
renderTargetSize == fHWProjectionMatrixState.fRenderTargetSize &&
|
||||
SkMatrixPriv::CheapEqual(matrix, fHWProjectionMatrixState.fViewMatrix)) {
|
||||
return;
|
||||
}
|
||||
|
||||
fHWProjectionMatrixState.fViewMatrix = matrix;
|
||||
fHWProjectionMatrixState.fRenderTargetSize = renderTargetSize;
|
||||
fHWProjectionMatrixState.fRenderTargetOrigin = renderTargetOrigin;
|
||||
|
||||
float glMatrix[4 * 4];
|
||||
fHWProjectionMatrixState.getRTAdjustedGLMatrix(glMatrix);
|
||||
SkDEBUGCODE(verify_floats(glMatrix, SK_ARRAY_COUNT(glMatrix)));
|
||||
GL_CALL(MatrixLoadf(GR_GL_PATH_PROJECTION, glMatrix));
|
||||
}
|
||||
|
||||
GrGLuint GrGLPathRendering::genPaths(GrGLsizei range) {
|
||||
SkASSERT(range > 0);
|
||||
GrGLuint firstID;
|
||||
if (fPreallocatedPathCount >= range) {
|
||||
firstID = fFirstPreallocatedPathID;
|
||||
fPreallocatedPathCount -= range;
|
||||
fFirstPreallocatedPathID += range;
|
||||
return firstID;
|
||||
}
|
||||
// Allocate range + the amount to fill up preallocation amount. If succeed, either join with
|
||||
// the existing preallocation range or delete the existing and use the new (potentially partial)
|
||||
// preallocation range.
|
||||
GrGLsizei allocAmount = range + (kPathIDPreallocationAmount - fPreallocatedPathCount);
|
||||
if (allocAmount >= range) {
|
||||
GL_CALL_RET(firstID, GenPaths(allocAmount));
|
||||
|
||||
if (firstID != 0) {
|
||||
if (fPreallocatedPathCount > 0 &&
|
||||
firstID == fFirstPreallocatedPathID + fPreallocatedPathCount) {
|
||||
firstID = fFirstPreallocatedPathID;
|
||||
fPreallocatedPathCount += allocAmount - range;
|
||||
fFirstPreallocatedPathID += range;
|
||||
return firstID;
|
||||
}
|
||||
|
||||
if (allocAmount > range) {
|
||||
if (fPreallocatedPathCount > 0) {
|
||||
this->deletePaths(fFirstPreallocatedPathID, fPreallocatedPathCount);
|
||||
}
|
||||
fFirstPreallocatedPathID = firstID + range;
|
||||
fPreallocatedPathCount = allocAmount - range;
|
||||
}
|
||||
// Special case: if allocAmount == range, we have full preallocated range.
|
||||
return firstID;
|
||||
}
|
||||
}
|
||||
// Failed to allocate with preallocation. Remove existing preallocation and try to allocate just
|
||||
// the range.
|
||||
if (fPreallocatedPathCount > 0) {
|
||||
this->deletePaths(fFirstPreallocatedPathID, fPreallocatedPathCount);
|
||||
fPreallocatedPathCount = 0;
|
||||
}
|
||||
|
||||
GL_CALL_RET(firstID, GenPaths(range));
|
||||
if (firstID == 0) {
|
||||
SkDebugf("Warning: Failed to allocate path\n");
|
||||
}
|
||||
return firstID;
|
||||
}
|
||||
|
||||
void GrGLPathRendering::deletePaths(GrGLuint path, GrGLsizei range) {
|
||||
GL_CALL(DeletePaths(path, range));
|
||||
}
|
||||
|
||||
void GrGLPathRendering::flushPathStencilSettings(const GrStencilSettings& stencilSettings) {
|
||||
SkASSERT(!stencilSettings.isTwoSided());
|
||||
if (fHWPathStencilSettings != stencilSettings) {
|
||||
SkASSERT(stencilSettings.isValid());
|
||||
// Just the func, ref, and mask is set here. The op and write mask are params to the call
|
||||
// that draws the path to the SB (glStencilFillPath)
|
||||
uint16_t ref = stencilSettings.singleSidedFace().fRef;
|
||||
GrStencilTest test = stencilSettings.singleSidedFace().fTest;
|
||||
uint16_t testMask = stencilSettings.singleSidedFace().fTestMask;
|
||||
|
||||
if (!fHWPathStencilSettings.isValid() ||
|
||||
ref != fHWPathStencilSettings.singleSidedFace().fRef ||
|
||||
test != fHWPathStencilSettings.singleSidedFace().fTest ||
|
||||
testMask != fHWPathStencilSettings.singleSidedFace().fTestMask) {
|
||||
GL_CALL(PathStencilFunc(GrToGLStencilFunc(test), ref, testMask));
|
||||
}
|
||||
fHWPathStencilSettings = stencilSettings;
|
||||
}
|
||||
}
|
||||
|
||||
inline GrGLGpu* GrGLPathRendering::gpu() {
|
||||
return static_cast<GrGLGpu*>(fGpu);
|
||||
}
|
@ -1,120 +0,0 @@
|
||||
/*
|
||||
* Copyright 2014 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef GrGLPathRendering_DEFINED
|
||||
#define GrGLPathRendering_DEFINED
|
||||
|
||||
#include "include/core/SkM44.h"
|
||||
#include "include/core/SkRefCnt.h"
|
||||
#include "include/gpu/gl/GrGLTypes.h"
|
||||
#include "src/gpu/GrGpu.h"
|
||||
#include "src/gpu/GrPathRendering.h"
|
||||
#include "src/gpu/GrStencilSettings.h"
|
||||
|
||||
class GrGLGpu;
|
||||
class GrStyle;
|
||||
|
||||
/**
|
||||
* This class wraps the NV_path_rendering extension and manages its various
|
||||
* API versions. If a method is not present in the GrGLInterface of the GrGLGpu
|
||||
* (because the driver version is old), it tries to provide a backup
|
||||
* implementation. But if a backup implementation is not practical, it marks the
|
||||
* method as not supported.
|
||||
*/
|
||||
class GrGLPathRendering : public GrPathRendering {
|
||||
public:
|
||||
/**
|
||||
* Create a new GrGLPathRendering object from a given GrGLGpu.
|
||||
*/
|
||||
GrGLPathRendering(GrGLGpu* gpu);
|
||||
~GrGLPathRendering() override;
|
||||
|
||||
// GrPathRendering implementations.
|
||||
sk_sp<GrPath> createPath(const SkPath&, const GrStyle&) override;
|
||||
|
||||
/* Called when the 3D context state is unknown. */
|
||||
void resetContext();
|
||||
|
||||
/**
|
||||
* Called when the context either is about to be lost or is lost. DisconnectType indicates
|
||||
* whether GPU resources should be cleaned up or abandoned when this is called.
|
||||
*/
|
||||
void disconnect(GrGpu::DisconnectType);
|
||||
|
||||
bool shouldBindFragmentInputs() const {
|
||||
return fCaps.bindFragmentInputSupport;
|
||||
}
|
||||
|
||||
// Functions for "separable shader" texturing support.
|
||||
void setProgramPathFragmentInputTransform(GrGLuint program, GrGLint location,
|
||||
GrGLenum genMode, GrGLint components,
|
||||
const SkMatrix&);
|
||||
|
||||
/* Sets the projection matrix for path rendering */
|
||||
void setProjectionMatrix(const SkMatrix& matrix,
|
||||
const SkISize& renderTargetSize,
|
||||
GrSurfaceOrigin renderTargetOrigin);
|
||||
|
||||
GrGLuint genPaths(GrGLsizei range);
|
||||
GrGLvoid deletePaths(GrGLuint path, GrGLsizei range);
|
||||
|
||||
protected:
|
||||
void onStencilPath(const StencilPathArgs&, const GrPath*) override;
|
||||
void onDrawPath(const GrStencilSettings&, const GrPath*) override;
|
||||
|
||||
private:
|
||||
/**
|
||||
* Mark certain functionality as not supported.
|
||||
*/
|
||||
struct Caps {
|
||||
bool bindFragmentInputSupport : 1;
|
||||
};
|
||||
|
||||
void flushPathStencilSettings(const GrStencilSettings&);
|
||||
|
||||
struct MatrixState {
|
||||
SkMatrix fViewMatrix;
|
||||
SkISize fRenderTargetSize;
|
||||
GrSurfaceOrigin fRenderTargetOrigin;
|
||||
|
||||
MatrixState() { this->invalidate(); }
|
||||
void invalidate() {
|
||||
fViewMatrix = SkMatrix::InvalidMatrix();
|
||||
fRenderTargetSize.fWidth = -1;
|
||||
fRenderTargetSize.fHeight = -1;
|
||||
fRenderTargetOrigin = (GrSurfaceOrigin) -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a matrix that goes from local coordinates to GL normalized device coords.
|
||||
*/
|
||||
void getRTAdjustedGLMatrix(float* destMatrix) {
|
||||
SkMatrix combined;
|
||||
if (kBottomLeft_GrSurfaceOrigin == fRenderTargetOrigin) {
|
||||
combined.setAll(SkIntToScalar(2) / fRenderTargetSize.fWidth, 0, -SK_Scalar1,
|
||||
0, -SkIntToScalar(2) / fRenderTargetSize.fHeight, SK_Scalar1,
|
||||
0, 0, 1);
|
||||
} else {
|
||||
combined.setAll(SkIntToScalar(2) / fRenderTargetSize.fWidth, 0, -SK_Scalar1,
|
||||
0, SkIntToScalar(2) / fRenderTargetSize.fHeight, -SK_Scalar1,
|
||||
0, 0, 1);
|
||||
}
|
||||
combined.preConcat(fViewMatrix);
|
||||
SkM44 combined44(combined);
|
||||
combined44.getColMajor(destMatrix);
|
||||
}
|
||||
};
|
||||
GrGLGpu* gpu();
|
||||
|
||||
GrGLuint fFirstPreallocatedPathID;
|
||||
GrGLsizei fPreallocatedPathCount;
|
||||
MatrixState fHWProjectionMatrixState;
|
||||
GrStencilSettings fHWPathStencilSettings;
|
||||
Caps fCaps;
|
||||
};
|
||||
|
||||
#endif
|
@ -7,7 +7,6 @@
|
||||
|
||||
#include "src/gpu/gl/GrGLProgram.h"
|
||||
|
||||
#include "src/gpu/GrPathProcessor.h"
|
||||
#include "src/gpu/GrPipeline.h"
|
||||
#include "src/gpu/GrProcessor.h"
|
||||
#include "src/gpu/GrProgramInfo.h"
|
||||
@ -15,7 +14,6 @@
|
||||
#include "src/gpu/GrXferProcessor.h"
|
||||
#include "src/gpu/gl/GrGLBuffer.h"
|
||||
#include "src/gpu/gl/GrGLGpu.h"
|
||||
#include "src/gpu/gl/GrGLPathRendering.h"
|
||||
#include "src/gpu/glsl/GrGLSLFragmentProcessor.h"
|
||||
#include "src/gpu/glsl/GrGLSLGeometryProcessor.h"
|
||||
#include "src/gpu/glsl/GrGLSLXferProcessor.h"
|
||||
@ -31,7 +29,6 @@ sk_sp<GrGLProgram> GrGLProgram::Make(
|
||||
GrGLuint programID,
|
||||
const UniformInfoArray& uniforms,
|
||||
const UniformInfoArray& textureSamplers,
|
||||
const VaryingInfoArray& pathProcVaryings,
|
||||
std::unique_ptr<GrGLSLPrimitiveProcessor> geometryProcessor,
|
||||
std::unique_ptr<GrGLSLXferProcessor> xferProcessor,
|
||||
std::vector<std::unique_ptr<GrGLSLFragmentProcessor>> fpImpls,
|
||||
@ -45,7 +42,6 @@ sk_sp<GrGLProgram> GrGLProgram::Make(
|
||||
programID,
|
||||
uniforms,
|
||||
textureSamplers,
|
||||
pathProcVaryings,
|
||||
std::move(geometryProcessor),
|
||||
std::move(xferProcessor),
|
||||
std::move(fpImpls),
|
||||
@ -60,21 +56,19 @@ sk_sp<GrGLProgram> GrGLProgram::Make(
|
||||
return program;
|
||||
}
|
||||
|
||||
GrGLProgram::GrGLProgram(
|
||||
GrGLGpu* gpu,
|
||||
const GrGLSLBuiltinUniformHandles& builtinUniforms,
|
||||
GrGLuint programID,
|
||||
const UniformInfoArray& uniforms,
|
||||
const UniformInfoArray& textureSamplers,
|
||||
const VaryingInfoArray& pathProcVaryings,
|
||||
std::unique_ptr<GrGLSLPrimitiveProcessor> geometryProcessor,
|
||||
std::unique_ptr<GrGLSLXferProcessor> xferProcessor,
|
||||
std::vector<std::unique_ptr<GrGLSLFragmentProcessor>> fpImpls,
|
||||
std::unique_ptr<Attribute[]> attributes,
|
||||
int vertexAttributeCnt,
|
||||
int instanceAttributeCnt,
|
||||
int vertexStride,
|
||||
int instanceStride)
|
||||
GrGLProgram::GrGLProgram(GrGLGpu* gpu,
|
||||
const GrGLSLBuiltinUniformHandles& builtinUniforms,
|
||||
GrGLuint programID,
|
||||
const UniformInfoArray& uniforms,
|
||||
const UniformInfoArray& textureSamplers,
|
||||
std::unique_ptr<GrGLSLPrimitiveProcessor> geometryProcessor,
|
||||
std::unique_ptr<GrGLSLXferProcessor> xferProcessor,
|
||||
std::vector<std::unique_ptr<GrGLSLFragmentProcessor>> fpImpls,
|
||||
std::unique_ptr<Attribute[]> attributes,
|
||||
int vertexAttributeCnt,
|
||||
int instanceAttributeCnt,
|
||||
int vertexStride,
|
||||
int instanceStride)
|
||||
: fBuiltinUniformHandles(builtinUniforms)
|
||||
, fProgramID(programID)
|
||||
, fPrimitiveProcessor(std::move(geometryProcessor))
|
||||
@ -86,7 +80,7 @@ GrGLProgram::GrGLProgram(
|
||||
, fVertexStride(vertexStride)
|
||||
, fInstanceStride(instanceStride)
|
||||
, fGpu(gpu)
|
||||
, fProgramDataManager(gpu, programID, uniforms, pathProcVaryings)
|
||||
, fProgramDataManager(gpu, uniforms)
|
||||
, fNumTextureSamplers(textureSamplers.count()) {
|
||||
}
|
||||
|
||||
@ -169,19 +163,13 @@ void GrGLProgram::setRenderTargetState(const GrRenderTarget* rt, GrSurfaceOrigin
|
||||
|
||||
// set RT adjustment
|
||||
SkISize dimensions = rt->dimensions();
|
||||
if (!primProc.isPathRendering()) {
|
||||
if (fRenderTargetState.fRenderTargetOrigin != origin ||
|
||||
fRenderTargetState.fRenderTargetSize != dimensions) {
|
||||
fRenderTargetState.fRenderTargetSize = dimensions;
|
||||
fRenderTargetState.fRenderTargetOrigin = origin;
|
||||
if (fRenderTargetState.fRenderTargetOrigin != origin ||
|
||||
fRenderTargetState.fRenderTargetSize != dimensions) {
|
||||
fRenderTargetState.fRenderTargetSize = dimensions;
|
||||
fRenderTargetState.fRenderTargetOrigin = origin;
|
||||
|
||||
float rtAdjustmentVec[4];
|
||||
fRenderTargetState.getRTAdjustmentVec(rtAdjustmentVec);
|
||||
fProgramDataManager.set4fv(fBuiltinUniformHandles.fRTAdjustmentUni, 1, rtAdjustmentVec);
|
||||
}
|
||||
} else {
|
||||
SkASSERT(fGpu->glCaps().shaderCaps()->pathRenderingSupport());
|
||||
const GrPathProcessor& pathProc = primProc.cast<GrPathProcessor>();
|
||||
fGpu->glPathRendering()->setProjectionMatrix(pathProc.viewMatrix(), dimensions, origin);
|
||||
float rtAdjustmentVec[4];
|
||||
fRenderTargetState.getRTAdjustmentVec(rtAdjustmentVec);
|
||||
fProgramDataManager.set4fv(fBuiltinUniformHandles.fRTAdjustmentUni, 1, rtAdjustmentVec);
|
||||
}
|
||||
}
|
||||
|
@ -55,7 +55,6 @@ public:
|
||||
GrGLuint programID,
|
||||
const UniformInfoArray& uniforms,
|
||||
const UniformInfoArray& textureSamplers,
|
||||
const VaryingInfoArray&, // used for NVPR only currently
|
||||
std::unique_ptr<GrGLSLPrimitiveProcessor> geometryProcessor,
|
||||
std::unique_ptr<GrGLSLXferProcessor> xferProcessor,
|
||||
std::vector<std::unique_ptr<GrGLSLFragmentProcessor>> fps,
|
||||
@ -147,7 +146,6 @@ private:
|
||||
GrGLuint programID,
|
||||
const UniformInfoArray& uniforms,
|
||||
const UniformInfoArray& textureSamplers,
|
||||
const VaryingInfoArray&, // used for NVPR only currently
|
||||
std::unique_ptr<GrGLSLPrimitiveProcessor> geometryProcessor,
|
||||
std::unique_ptr<GrGLSLXferProcessor> xferProcessor,
|
||||
std::vector<std::unique_ptr<GrGLSLFragmentProcessor>> fpImpls,
|
||||
|
@ -14,11 +14,8 @@
|
||||
SkASSERT((COUNT) <= (UNI).fArrayCount || \
|
||||
(1 == (COUNT) && GrShaderVar::kNonArray == (UNI).fArrayCount))
|
||||
|
||||
GrGLProgramDataManager::GrGLProgramDataManager(GrGLGpu* gpu, GrGLuint programID,
|
||||
const UniformInfoArray& uniforms,
|
||||
const VaryingInfoArray& pathProcVaryings)
|
||||
: fGpu(gpu)
|
||||
, fProgramID(programID) {
|
||||
GrGLProgramDataManager::GrGLProgramDataManager(GrGLGpu* gpu, const UniformInfoArray& uniforms)
|
||||
: fGpu(gpu) {
|
||||
fUniforms.push_back_n(uniforms.count());
|
||||
int i = 0;
|
||||
for (const GLUniformInfo& builderUniform : uniforms.items()) {
|
||||
@ -31,21 +28,6 @@ GrGLProgramDataManager::GrGLProgramDataManager(GrGLGpu* gpu, GrGLuint programID,
|
||||
)
|
||||
uniform.fLocation = builderUniform.fLocation;
|
||||
}
|
||||
|
||||
// NVPR programs have separable varyings
|
||||
fPathProcVaryings.push_back_n(pathProcVaryings.count());
|
||||
i = 0;
|
||||
for (const VaryingInfo& builderPathProcVarying : pathProcVaryings.items()) {
|
||||
SkASSERT(fGpu->glCaps().shaderCaps()->pathRenderingSupport());
|
||||
PathProcVarying& pathProcVarying = fPathProcVaryings[i++];
|
||||
SkASSERT(GrShaderVar::kNonArray == builderPathProcVarying.fVariable.getArrayCount() ||
|
||||
builderPathProcVarying.fVariable.getArrayCount() > 0);
|
||||
SkDEBUGCODE(
|
||||
pathProcVarying.fArrayCount = builderPathProcVarying.fVariable.getArrayCount();
|
||||
pathProcVarying.fType = builderPathProcVarying.fVariable.getType();
|
||||
)
|
||||
pathProcVarying.fLocation = builderPathProcVarying.fLocation;
|
||||
}
|
||||
}
|
||||
|
||||
void GrGLProgramDataManager::setSamplerUniforms(const UniformInfoArray& samplers,
|
||||
@ -296,21 +278,3 @@ template<> struct set_uniform_matrix<4> {
|
||||
GR_GL_CALL(gli, UniformMatrix4fv(loc, cnt, false, m));
|
||||
}
|
||||
};
|
||||
|
||||
void GrGLProgramDataManager::setPathFragmentInputTransform(VaryingHandle u,
|
||||
int components,
|
||||
const SkMatrix& matrix) const {
|
||||
SkASSERT(fGpu->glCaps().shaderCaps()->pathRenderingSupport());
|
||||
const PathProcVarying& fragmentInput = fPathProcVaryings[u.toIndex()];
|
||||
|
||||
SkASSERT((components == 2 && (fragmentInput.fType == kFloat2_GrSLType ||
|
||||
fragmentInput.fType == kHalf2_GrSLType)) ||
|
||||
(components == 3 && (fragmentInput.fType == kFloat3_GrSLType ||
|
||||
fragmentInput.fType == kHalf3_GrSLType)));
|
||||
|
||||
fGpu->glPathRendering()->setProgramPathFragmentInputTransform(fProgramID,
|
||||
fragmentInput.fLocation,
|
||||
GR_GL_OBJECT_LINEAR,
|
||||
components,
|
||||
matrix);
|
||||
}
|
||||
|
@ -41,8 +41,7 @@ public:
|
||||
typedef GrTBlockList<GLUniformInfo> UniformInfoArray;
|
||||
typedef GrTBlockList<VaryingInfo> VaryingInfoArray;
|
||||
|
||||
GrGLProgramDataManager(GrGLGpu*, GrGLuint programID, const UniformInfoArray&,
|
||||
const VaryingInfoArray&);
|
||||
GrGLProgramDataManager(GrGLGpu*, const UniformInfoArray&);
|
||||
|
||||
void setSamplerUniforms(const UniformInfoArray& samplers, int startUnit) const;
|
||||
|
||||
@ -74,10 +73,6 @@ public:
|
||||
void setMatrix3fv(UniformHandle, int arrayCount, const float matrices[]) const override;
|
||||
void setMatrix4fv(UniformHandle, int arrayCount, const float matrices[]) const override;
|
||||
|
||||
// for nvpr only
|
||||
void setPathFragmentInputTransform(VaryingHandle u, int components,
|
||||
const SkMatrix& matrix) const override;
|
||||
|
||||
private:
|
||||
enum {
|
||||
kUnusedUniform = -1,
|
||||
@ -91,24 +86,11 @@ private:
|
||||
#endif
|
||||
};
|
||||
|
||||
enum {
|
||||
kUnusedPathProcVarying = -1,
|
||||
};
|
||||
struct PathProcVarying {
|
||||
GrGLint fLocation;
|
||||
SkDEBUGCODE(
|
||||
GrSLType fType;
|
||||
int fArrayCount;
|
||||
);
|
||||
};
|
||||
|
||||
template<int N> inline void setMatrices(UniformHandle, int arrayCount,
|
||||
const float matrices[]) const;
|
||||
|
||||
SkTArray<Uniform, true> fUniforms;
|
||||
SkTArray<PathProcVarying, true> fPathProcVaryings;
|
||||
GrGLGpu* fGpu;
|
||||
GrGLuint fProgramID;
|
||||
|
||||
using INHERITED = GrGLSLProgramDataManager;
|
||||
};
|
||||
|
@ -1,36 +0,0 @@
|
||||
/*
|
||||
* 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 "src/gpu/gl/GrGLVaryingHandler.h"
|
||||
|
||||
#include "src/gpu/gl/GrGLGpu.h"
|
||||
#include "src/gpu/gl/builders/GrGLProgramBuilder.h"
|
||||
|
||||
|
||||
GrGLSLVaryingHandler::VaryingHandle GrGLVaryingHandler::addPathProcessingVarying(
|
||||
const char* name,
|
||||
GrGLSLVarying* v) {
|
||||
#ifdef SK_DEBUG
|
||||
GrGLProgramBuilder* glPB = (GrGLProgramBuilder*) fProgramBuilder;
|
||||
// This call is not used for non-NVPR backends.
|
||||
SkASSERT(glPB->gpu()->glCaps().shaderCaps()->pathRenderingSupport() &&
|
||||
fProgramBuilder->fProgramInfo.isNVPR());
|
||||
#endif
|
||||
this->addVarying(name, v);
|
||||
auto varyingInfo = fPathProcVaryingInfos.push_back();
|
||||
varyingInfo.fLocation = fPathProcVaryingInfos.count() - 1;
|
||||
return VaryingHandle(varyingInfo.fLocation);
|
||||
}
|
||||
|
||||
void GrGLVaryingHandler::onFinalize() {
|
||||
SkASSERT(fPathProcVaryingInfos.empty() || fPathProcVaryingInfos.count() == fFragInputs.count());
|
||||
VarArray::Iter::Item fragInputIter = fFragInputs.items().begin();
|
||||
for (auto& varyingInfo : fPathProcVaryingInfos.items()) {
|
||||
varyingInfo.fVariable = *fragInputIter;
|
||||
++fragInputIter;
|
||||
}
|
||||
}
|
@ -14,18 +14,10 @@
|
||||
|
||||
class GrGLVaryingHandler : public GrGLSLVaryingHandler {
|
||||
public:
|
||||
GrGLVaryingHandler(GrGLSLProgramBuilder* program)
|
||||
: INHERITED(program),
|
||||
fPathProcVaryingInfos(kVaryingsPerBlock) {}
|
||||
|
||||
// This function is used by the NVPR PathProcessor to add a varying directly into the fragment
|
||||
// shader since there is no vertex shader.
|
||||
VaryingHandle addPathProcessingVarying(const char* name, GrGLSLVarying*);
|
||||
GrGLVaryingHandler(GrGLSLProgramBuilder* program) : INHERITED(program) {}
|
||||
|
||||
private:
|
||||
void onFinalize() override;
|
||||
|
||||
GrGLProgramDataManager::VaryingInfoArray fPathProcVaryingInfos;
|
||||
void onFinalize() override {}
|
||||
|
||||
friend class GrGLProgramBuilder;
|
||||
|
||||
|
@ -378,11 +378,8 @@ sk_sp<GrGLProgram> GrGLProgramBuilder::finalize(const GrGLPrecompiledProgram* pr
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// This also binds vertex attribute locations. NVPR doesn't really use vertices,
|
||||
// even though it requires a vertex shader in the program.
|
||||
if (!primProc.isPathRendering()) {
|
||||
this->computeCountsAndStrides(programID, primProc, true);
|
||||
}
|
||||
// This also binds vertex attribute locations.
|
||||
this->computeCountsAndStrides(programID, primProc, true);
|
||||
|
||||
/*
|
||||
Tessellation Shaders
|
||||
@ -493,18 +490,6 @@ void GrGLProgramBuilder::bindProgramResourceLocations(GrGLuint programID) {
|
||||
GL_CALL(BindFragDataLocationIndexed(programID, 0, 1,
|
||||
GrGLSLFragmentShaderBuilder::DeclaredSecondaryColorOutputName()));
|
||||
}
|
||||
|
||||
// handle NVPR separable varyings
|
||||
if (!fGpu->glCaps().shaderCaps()->pathRenderingSupport() ||
|
||||
!fGpu->glPathRendering()->shouldBindFragmentInputs()) {
|
||||
return;
|
||||
}
|
||||
int i = 0;
|
||||
for (auto& varying : fVaryingHandler.fPathProcVaryingInfos.items()) {
|
||||
GL_CALL(BindFragmentInputLocation(programID, i, varying.fVariable.c_str()));
|
||||
varying.fLocation = i;
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
bool GrGLProgramBuilder::checkLinkStatus(GrGLuint programID,
|
||||
@ -544,20 +529,6 @@ bool GrGLProgramBuilder::checkLinkStatus(GrGLuint programID,
|
||||
|
||||
void GrGLProgramBuilder::resolveProgramResourceLocations(GrGLuint programID, bool force) {
|
||||
fUniformHandler.getUniformLocations(programID, fGpu->glCaps(), force);
|
||||
|
||||
// handle NVPR separable varyings
|
||||
if (!fGpu->glCaps().shaderCaps()->pathRenderingSupport() ||
|
||||
fGpu->glPathRendering()->shouldBindFragmentInputs()) {
|
||||
return;
|
||||
}
|
||||
for (auto& varying : fVaryingHandler.fPathProcVaryingInfos.items()) {
|
||||
GrGLint location;
|
||||
GL_CALL_RET(location, GetProgramResourceLocation(
|
||||
programID,
|
||||
GR_GL_FRAGMENT_INPUT,
|
||||
varying.fVariable.c_str()));
|
||||
varying.fLocation = location;
|
||||
}
|
||||
}
|
||||
|
||||
sk_sp<GrGLProgram> GrGLProgramBuilder::createProgram(GrGLuint programID) {
|
||||
@ -566,7 +537,6 @@ sk_sp<GrGLProgram> GrGLProgramBuilder::createProgram(GrGLuint programID) {
|
||||
programID,
|
||||
fUniformHandler.fUniforms,
|
||||
fUniformHandler.fSamplers,
|
||||
fVaryingHandler.fPathProcVaryingInfos,
|
||||
std::move(fGeometryProcessor),
|
||||
std::move(fXferProcessor),
|
||||
std::move(fFPImpls),
|
||||
|
@ -58,11 +58,6 @@ public:
|
||||
// convenience method for uploading a SkMatrix to a 4x4 matrix uniform
|
||||
void setSkM44(UniformHandle, const SkM44&) const;
|
||||
|
||||
// for nvpr only
|
||||
GR_DEFINE_RESOURCE_HANDLE_CLASS(VaryingHandle);
|
||||
virtual void setPathFragmentInputTransform(VaryingHandle u, int components,
|
||||
const SkMatrix& matrix) const = 0;
|
||||
|
||||
protected:
|
||||
GrGLSLProgramDataManager() {}
|
||||
|
||||
|
@ -151,7 +151,6 @@ protected:
|
||||
|
||||
typedef GrTBlockList<VaryingInfo> VaryingList;
|
||||
typedef GrTBlockList<GrShaderVar> VarArray;
|
||||
typedef GrGLSLProgramDataManager::VaryingHandle VaryingHandle;
|
||||
|
||||
VaryingList fVaryings;
|
||||
VarArray fVertexInputs;
|
||||
|
@ -33,12 +33,6 @@ public:
|
||||
void setMatrix2f(UniformHandle, const float matrix[]) const override;
|
||||
void setMatrix2fv(UniformHandle, int arrayCount, const float matrices[]) const override;
|
||||
|
||||
// for nvpr only
|
||||
void setPathFragmentInputTransform(VaryingHandle u, int components,
|
||||
const SkMatrix& matrix) const override {
|
||||
SK_ABORT("Only supported in NVPR, which is not in Metal");
|
||||
}
|
||||
|
||||
void uploadAndBindUniformBuffers(GrMtlGpu* gpu,
|
||||
id<MTLRenderCommandEncoder> renderCmdEncoder) const;
|
||||
void resetDirtyBits();
|
||||
|
@ -1,151 +0,0 @@
|
||||
/*
|
||||
* 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 "src/gpu/ops/GrDrawPathOp.h"
|
||||
|
||||
#include "include/gpu/GrRecordingContext.h"
|
||||
#include "include/private/SkTemplates.h"
|
||||
#include "src/gpu/GrAppliedClip.h"
|
||||
#include "src/gpu/GrGpu.h"
|
||||
#include "src/gpu/GrMemoryPool.h"
|
||||
#include "src/gpu/GrProgramInfo.h"
|
||||
#include "src/gpu/GrRecordingContextPriv.h"
|
||||
#include "src/gpu/GrRenderTarget.h"
|
||||
#include "src/gpu/GrSurfaceDrawContext.h"
|
||||
#include "src/gpu/ops/GrSimpleMeshDrawOpHelper.h"
|
||||
|
||||
static constexpr GrUserStencilSettings kCoverPass{
|
||||
GrUserStencilSettings::StaticInit<
|
||||
0x0000,
|
||||
GrUserStencilTest::kNotEqual,
|
||||
0xffff,
|
||||
GrUserStencilOp::kZero,
|
||||
GrUserStencilOp::kKeep,
|
||||
0xffff>()
|
||||
};
|
||||
|
||||
GrDrawPathOpBase::GrDrawPathOpBase(uint32_t classID, const SkMatrix& viewMatrix, GrPaint&& paint,
|
||||
GrPathRendering::FillType fill, GrAA aa)
|
||||
: INHERITED(classID)
|
||||
, fViewMatrix(viewMatrix)
|
||||
, fInputColor(paint.getColor4f())
|
||||
, fFillType(fill)
|
||||
, fDoAA(GrAA::kYes == aa)
|
||||
, fProcessorSet(std::move(paint)) {}
|
||||
|
||||
#if GR_TEST_UTILS
|
||||
SkString GrDrawPathOp::onDumpInfo() const {
|
||||
return SkStringPrintf("PATH: 0x%p", fPath.get());
|
||||
}
|
||||
#endif
|
||||
|
||||
const GrProcessorSet::Analysis& GrDrawPathOpBase::doProcessorAnalysis(
|
||||
const GrCaps& caps, const GrAppliedClip* clip, bool hasMixedSampledCoverage,
|
||||
GrClampType clampType) {
|
||||
fAnalysis = fProcessorSet.finalize(
|
||||
fInputColor, GrProcessorAnalysisCoverage::kNone, clip, &kCoverPass,
|
||||
hasMixedSampledCoverage, caps, clampType, &fInputColor);
|
||||
return fAnalysis;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void init_stencil_pass_settings(const GrOpFlushState& flushState,
|
||||
GrPathRendering::FillType fillType, GrStencilSettings* stencil) {
|
||||
const GrAppliedClip* appliedClip = flushState.drawOpArgs().appliedClip();
|
||||
bool stencilClip = appliedClip && appliedClip->hasStencilClip();
|
||||
GrRenderTarget* rt = flushState.drawOpArgs().rtProxy()->peekRenderTarget();
|
||||
stencil->reset(GrPathRendering::GetStencilPassSettings(fillType), stencilClip,
|
||||
rt->numStencilBits());
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
GrOp::Owner GrDrawPathOp::Make(GrRecordingContext* context,
|
||||
const SkMatrix& viewMatrix,
|
||||
GrPaint&& paint,
|
||||
GrAA aa,
|
||||
sk_sp<const GrPath> path) {
|
||||
return GrOp::Make<GrDrawPathOp>(context, viewMatrix, std::move(paint), aa, std::move(path));
|
||||
}
|
||||
|
||||
void GrDrawPathOp::onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) {
|
||||
GrPipeline::InputFlags pipelineFlags = GrPipeline::InputFlags::kNone;
|
||||
if (this->doAA()) {
|
||||
pipelineFlags |= GrPipeline::InputFlags::kHWAntialias;
|
||||
}
|
||||
|
||||
auto pipeline = GrSimpleMeshDrawOpHelper::CreatePipeline(flushState,
|
||||
this->detachProcessorSet(),
|
||||
pipelineFlags);
|
||||
|
||||
sk_sp<GrPathProcessor> pathProc(GrPathProcessor::Create(this->color(), this->viewMatrix()));
|
||||
|
||||
GrProgramInfo programInfo(flushState->writeView(),
|
||||
pipeline,
|
||||
&kCoverPass,
|
||||
pathProc.get(),
|
||||
GrPrimitiveType::kPath,
|
||||
0,
|
||||
flushState->renderPassBarriers(),
|
||||
flushState->colorLoadOp());
|
||||
|
||||
flushState->bindPipelineAndScissorClip(programInfo, this->bounds());
|
||||
flushState->bindTextures(programInfo.primProc(), nullptr, programInfo.pipeline());
|
||||
|
||||
GrStencilSettings stencil;
|
||||
init_stencil_pass_settings(*flushState, this->fillType(), &stencil);
|
||||
flushState->gpu()->pathRendering()->drawPath(flushState->rtProxy()->peekRenderTarget(),
|
||||
programInfo, stencil, fPath.get());
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline void pre_translate_transform_values(const float* xforms,
|
||||
GrPathRendering::PathTransformType type, int count,
|
||||
SkScalar x, SkScalar y, float* dst) {
|
||||
if (0 == x && 0 == y) {
|
||||
memcpy(dst, xforms, count * GrPathRendering::PathTransformSize(type) * sizeof(float));
|
||||
return;
|
||||
}
|
||||
switch (type) {
|
||||
case GrPathRendering::kNone_PathTransformType:
|
||||
SK_ABORT("Cannot pre-translate kNone_PathTransformType.");
|
||||
break;
|
||||
case GrPathRendering::kTranslateX_PathTransformType:
|
||||
SkASSERT(0 == y);
|
||||
for (int i = 0; i < count; i++) {
|
||||
dst[i] = xforms[i] + x;
|
||||
}
|
||||
break;
|
||||
case GrPathRendering::kTranslateY_PathTransformType:
|
||||
SkASSERT(0 == x);
|
||||
for (int i = 0; i < count; i++) {
|
||||
dst[i] = xforms[i] + y;
|
||||
}
|
||||
break;
|
||||
case GrPathRendering::kTranslate_PathTransformType:
|
||||
for (int i = 0; i < 2 * count; i += 2) {
|
||||
dst[i] = xforms[i] + x;
|
||||
dst[i + 1] = xforms[i + 1] + y;
|
||||
}
|
||||
break;
|
||||
case GrPathRendering::kAffine_PathTransformType:
|
||||
for (int i = 0; i < 6 * count; i += 6) {
|
||||
dst[i] = xforms[i];
|
||||
dst[i + 1] = xforms[i + 1];
|
||||
dst[i + 2] = xforms[i] * x + xforms[i + 1] * y + xforms[i + 2];
|
||||
dst[i + 3] = xforms[i + 3];
|
||||
dst[i + 4] = xforms[i + 4];
|
||||
dst[i + 5] = xforms[i + 3] * x + xforms[i + 4] * y + xforms[i + 5];
|
||||
}
|
||||
break;
|
||||
default:
|
||||
SK_ABORT("Unknown transform type.");
|
||||
break;
|
||||
}
|
||||
}
|
@ -1,106 +0,0 @@
|
||||
/*
|
||||
* 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 GrDrawPathOp_DEFINED
|
||||
#define GrDrawPathOp_DEFINED
|
||||
|
||||
#include "src/gpu/GrOpFlushState.h"
|
||||
#include "src/gpu/GrPath.h"
|
||||
#include "src/gpu/GrPathProcessor.h"
|
||||
#include "src/gpu/GrPathRendering.h"
|
||||
#include "src/gpu/GrProcessorSet.h"
|
||||
#include "src/gpu/GrStencilSettings.h"
|
||||
#include "src/gpu/ops/GrDrawOp.h"
|
||||
|
||||
class GrPaint;
|
||||
class GrRecordingContext;
|
||||
|
||||
class GrDrawPathOpBase : public GrDrawOp {
|
||||
protected:
|
||||
GrDrawPathOpBase(uint32_t classID, const SkMatrix& viewMatrix, GrPaint&&,
|
||||
GrPathRendering::FillType, GrAA);
|
||||
|
||||
FixedFunctionFlags fixedFunctionFlags() const override {
|
||||
return (fDoAA)
|
||||
? FixedFunctionFlags::kUsesHWAA | FixedFunctionFlags::kUsesStencil
|
||||
: FixedFunctionFlags::kUsesStencil;
|
||||
}
|
||||
GrProcessorSet::Analysis finalize(
|
||||
const GrCaps& caps, const GrAppliedClip* clip, bool hasMixedSampledCoverage,
|
||||
GrClampType clampType) override {
|
||||
return this->doProcessorAnalysis(caps, clip, hasMixedSampledCoverage, clampType);
|
||||
}
|
||||
|
||||
void visitProxies(const VisitProxyFunc& func) const override {
|
||||
fProcessorSet.visitProxies(func);
|
||||
}
|
||||
|
||||
protected:
|
||||
const SkMatrix& viewMatrix() const { return fViewMatrix; }
|
||||
const SkPMColor4f& color() const { return fInputColor; }
|
||||
GrPathRendering::FillType fillType() const { return fFillType; }
|
||||
bool doAA() const { return fDoAA; }
|
||||
const GrProcessorSet& processors() const { return fProcessorSet; }
|
||||
GrProcessorSet detachProcessorSet() { return std::move(fProcessorSet); }
|
||||
const GrProcessorSet::Analysis& doProcessorAnalysis(
|
||||
const GrCaps&, const GrAppliedClip*, bool hasMixedSampledCoverage, GrClampType);
|
||||
const GrProcessorSet::Analysis& processorAnalysis() const {
|
||||
SkASSERT(fAnalysis.isInitialized());
|
||||
return fAnalysis;
|
||||
}
|
||||
|
||||
private:
|
||||
void onPrePrepare(GrRecordingContext*,
|
||||
const GrSurfaceProxyView& writeView,
|
||||
GrAppliedClip*,
|
||||
const GrXferProcessor::DstProxyView&,
|
||||
GrXferBarrierFlags renderPassXferBarriers,
|
||||
GrLoadOp colorLoadOp) final {}
|
||||
|
||||
void onPrepare(GrOpFlushState*) final {}
|
||||
|
||||
SkMatrix fViewMatrix;
|
||||
SkPMColor4f fInputColor;
|
||||
GrProcessorSet::Analysis fAnalysis;
|
||||
GrPathRendering::FillType fFillType;
|
||||
bool fDoAA;
|
||||
GrProcessorSet fProcessorSet;
|
||||
|
||||
using INHERITED = GrDrawOp;
|
||||
};
|
||||
|
||||
class GrDrawPathOp final : public GrDrawPathOpBase {
|
||||
public:
|
||||
DEFINE_OP_CLASS_ID
|
||||
|
||||
static GrOp::Owner Make(
|
||||
GrRecordingContext*, const SkMatrix& viewMatrix, GrPaint&&, GrAA, sk_sp<const GrPath>);
|
||||
|
||||
const char* name() const override { return "DrawPath"; }
|
||||
|
||||
private:
|
||||
friend class GrOp; // for ctor
|
||||
|
||||
GrDrawPathOp(const SkMatrix& viewMatrix, GrPaint&& paint, GrAA aa, sk_sp<const GrPath> path)
|
||||
: GrDrawPathOpBase(
|
||||
ClassID(), viewMatrix, std::move(paint), path->getFillType(), aa)
|
||||
, fPath(std::move(path)) {
|
||||
this->setTransformedBounds(fPath->getBounds(), viewMatrix, HasAABloat::kNo,
|
||||
IsHairline::kNo);
|
||||
}
|
||||
|
||||
void onExecute(GrOpFlushState*, const SkRect& chainBounds) override;
|
||||
#if GR_TEST_UTILS
|
||||
SkString onDumpInfo() const override;
|
||||
#endif
|
||||
|
||||
sk_sp<const GrPath> fPath;
|
||||
|
||||
using INHERITED = GrDrawPathOpBase;
|
||||
};
|
||||
|
||||
#endif
|
@ -1,189 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "include/gpu/GrRecordingContext.h"
|
||||
#include "src/gpu/GrCaps.h"
|
||||
#include "src/gpu/GrGpu.h"
|
||||
#include "src/gpu/GrPath.h"
|
||||
#include "src/gpu/GrResourceProvider.h"
|
||||
#include "src/gpu/GrStencilClip.h"
|
||||
#include "src/gpu/GrStyle.h"
|
||||
#include "src/gpu/geometry/GrStyledShape.h"
|
||||
#include "src/gpu/ops/GrDrawPathOp.h"
|
||||
#include "src/gpu/ops/GrStencilAndCoverPathRenderer.h"
|
||||
#include "src/gpu/ops/GrStencilPathOp.h"
|
||||
|
||||
GrPathRenderer* GrStencilAndCoverPathRenderer::Create(GrResourceProvider* resourceProvider,
|
||||
const GrCaps& caps) {
|
||||
if (caps.shaderCaps()->pathRenderingSupport() && !caps.avoidStencilBuffers()) {
|
||||
return new GrStencilAndCoverPathRenderer(resourceProvider);
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
GrStencilAndCoverPathRenderer::GrStencilAndCoverPathRenderer(GrResourceProvider* resourceProvider)
|
||||
: fResourceProvider(resourceProvider) {
|
||||
}
|
||||
|
||||
static bool has_matrix(const GrFragmentProcessor& fp) {
|
||||
if (fp.sampleUsage().hasMatrix()) {
|
||||
return true;
|
||||
}
|
||||
for (int i = fp.numChildProcessors() - 1; i >= 0; --i) {
|
||||
if (fp.childProcessor(i) && has_matrix(*fp.childProcessor(i))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
GrPathRenderer::CanDrawPath
|
||||
GrStencilAndCoverPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
|
||||
SkASSERT(!args.fTargetIsWrappedVkSecondaryCB);
|
||||
// GrPath doesn't support hairline paths. An arbitrary path effect could produce a hairline
|
||||
// path.
|
||||
if (args.fShape->style().strokeRec().isHairlineStyle() ||
|
||||
args.fShape->style().hasNonDashPathEffect() ||
|
||||
args.fHasUserStencilSettings ||
|
||||
!args.fShape->hasUnstyledKey()) {
|
||||
return CanDrawPath::kNo;
|
||||
}
|
||||
if (GrAAType::kCoverage == args.fAAType && !args.fProxy->canUseMixedSamples(*args.fCaps)) {
|
||||
// We rely on a mixed sampled stencil buffer to implement coverage AA.
|
||||
return CanDrawPath::kNo;
|
||||
}
|
||||
// The lack of vertex shaders means we can't move transform matrices into the vertex shader. We
|
||||
// could do the transform in the fragment processor, but that would be very slow, so instead we
|
||||
// just avoid using this path renderer in the face of transformed FPs.
|
||||
if (args.fPaint && args.fPaint->hasColorFragmentProcessor()) {
|
||||
if (has_matrix(*args.fPaint->getColorFragmentProcessor())) {
|
||||
return CanDrawPath::kNo;
|
||||
}
|
||||
}
|
||||
return CanDrawPath::kYes;
|
||||
}
|
||||
|
||||
static sk_sp<GrPath> get_gr_path(GrResourceProvider* resourceProvider, const GrStyledShape& shape) {
|
||||
GrUniqueKey key;
|
||||
bool isVolatile;
|
||||
GrPath::ComputeKey(shape, &key, &isVolatile);
|
||||
sk_sp<GrPath> path;
|
||||
if (!isVolatile) {
|
||||
path = resourceProvider->findByUniqueKey<GrPath>(key);
|
||||
}
|
||||
if (!path) {
|
||||
SkPath skPath;
|
||||
shape.asPath(&skPath);
|
||||
path = resourceProvider->createPath(skPath, shape.style());
|
||||
if (!isVolatile) {
|
||||
resourceProvider->assignUniqueKeyToResource(key, path.get());
|
||||
}
|
||||
} else {
|
||||
#ifdef SK_DEBUG
|
||||
SkPath skPath;
|
||||
shape.asPath(&skPath);
|
||||
SkASSERT(path->isEqualTo(skPath, shape.style()));
|
||||
#endif
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
void GrStencilAndCoverPathRenderer::onStencilPath(const StencilPathArgs& args) {
|
||||
GR_AUDIT_TRAIL_AUTO_FRAME(args.fRenderTargetContext->auditTrail(),
|
||||
"GrStencilAndCoverPathRenderer::onStencilPath");
|
||||
sk_sp<GrPath> p(get_gr_path(fResourceProvider, *args.fShape));
|
||||
args.fRenderTargetContext->stencilPath(args.fClip, args.fDoStencilMSAA, *args.fViewMatrix,
|
||||
std::move(p));
|
||||
}
|
||||
|
||||
bool GrStencilAndCoverPathRenderer::onDrawPath(const DrawPathArgs& args) {
|
||||
GR_AUDIT_TRAIL_AUTO_FRAME(args.fRenderTargetContext->auditTrail(),
|
||||
"GrStencilAndCoverPathRenderer::onDrawPath");
|
||||
SkASSERT(!args.fShape->style().strokeRec().isHairlineStyle());
|
||||
|
||||
const SkMatrix& viewMatrix = *args.fViewMatrix;
|
||||
|
||||
// Any AA will use stencil MSAA
|
||||
GrAAType stencilAAType = GrAAType::kNone != args.fAAType ? GrAAType::kMSAA : GrAAType::kNone;
|
||||
|
||||
sk_sp<GrPath> path(get_gr_path(fResourceProvider, *args.fShape));
|
||||
|
||||
if (args.fShape->inverseFilled()) {
|
||||
SkMatrix vmi;
|
||||
if (!viewMatrix.invert(&vmi)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
SkRect devBounds = SkRect::MakeIWH(args.fRenderTargetContext->width(),
|
||||
args.fRenderTargetContext->height()); // Inverse fill.
|
||||
|
||||
// fake inverse with a stencil and cover
|
||||
GrAppliedClip appliedClip(args.fRenderTargetContext->dimensions());
|
||||
if (args.fClip && args.fClip->apply(
|
||||
args.fContext, args.fRenderTargetContext, stencilAAType, true, &appliedClip,
|
||||
&devBounds) == GrClip::Effect::kClippedOut) {
|
||||
return true;
|
||||
}
|
||||
GrStencilClip stencilClip(args.fRenderTargetContext->dimensions(),
|
||||
appliedClip.stencilStackID());
|
||||
if (appliedClip.scissorState().enabled()) {
|
||||
SkAssertResult(stencilClip.fixedClip().setScissor(appliedClip.scissorState().rect()));
|
||||
}
|
||||
if (appliedClip.windowRectsState().enabled()) {
|
||||
stencilClip.fixedClip().setWindowRectangles(appliedClip.windowRectsState().windows(),
|
||||
appliedClip.windowRectsState().mode());
|
||||
}
|
||||
// Just ignore the analytic FPs (if any) during the stencil pass. They will still clip the
|
||||
// final draw and it is meaningless to multiply by coverage when drawing to stencil.
|
||||
args.fRenderTargetContext->stencilPath(&stencilClip, GrAA(stencilAAType == GrAAType::kMSAA),
|
||||
viewMatrix, std::move(path));
|
||||
|
||||
{
|
||||
static constexpr GrUserStencilSettings kInvertedCoverPass(
|
||||
GrUserStencilSettings::StaticInit<
|
||||
0x0000,
|
||||
// We know our rect will hit pixels outside the clip and the user bits will
|
||||
// be 0 outside the clip. So we can't just fill where the user bits are 0. We
|
||||
// also need to check that the clip bit is set.
|
||||
GrUserStencilTest::kEqualIfInClip,
|
||||
0xffff,
|
||||
GrUserStencilOp::kKeep,
|
||||
GrUserStencilOp::kZero,
|
||||
0xffff>()
|
||||
);
|
||||
|
||||
SkRect coverBounds;
|
||||
// mapRect through persp matrix may not be correct
|
||||
if (!viewMatrix.hasPerspective()) {
|
||||
vmi.mapRect(&coverBounds, devBounds);
|
||||
// theoretically could set bloat = 0, instead leave it because of matrix inversion
|
||||
// precision.
|
||||
SkScalar bloat = viewMatrix.getMaxScale() * SK_ScalarHalf;
|
||||
coverBounds.outset(bloat, bloat);
|
||||
} else {
|
||||
coverBounds = devBounds;
|
||||
}
|
||||
const SkMatrix& coverMatrix = !viewMatrix.hasPerspective() ? viewMatrix : SkMatrix::I();
|
||||
const SkMatrix& localMatrix = !viewMatrix.hasPerspective() ? SkMatrix::I() : vmi;
|
||||
|
||||
// We have to suppress enabling MSAA for mixed samples or we will get seams due to
|
||||
// coverage modulation along the edge where two triangles making up the rect meet.
|
||||
GrAA coverAA = GrAA(args.fAAType == GrAAType::kMSAA);
|
||||
args.fRenderTargetContext->stencilRect(args.fClip, &kInvertedCoverPass,
|
||||
std::move(args.fPaint), coverAA, coverMatrix,
|
||||
coverBounds, &localMatrix);
|
||||
}
|
||||
} else {
|
||||
GrOp::Owner op = GrDrawPathOp::Make(
|
||||
args.fContext, viewMatrix, std::move(args.fPaint),
|
||||
GrAA(stencilAAType == GrAAType::kMSAA), std::move(path));
|
||||
args.fRenderTargetContext->addDrawOp(args.fClip, std::move(op));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
@ -1,45 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef GrBuiltInPathRenderer_DEFINED
|
||||
#define GrBuiltInPathRenderer_DEFINED
|
||||
|
||||
#include "src/gpu/GrPathRenderer.h"
|
||||
|
||||
class GrGpu;
|
||||
class GrResourceProvider;
|
||||
|
||||
/**
|
||||
* Uses GrGpu::stencilPath followed by a cover rectangle. This subclass doesn't apply AA; it relies
|
||||
* on the target having MSAA if AA is desired.
|
||||
*/
|
||||
class GrStencilAndCoverPathRenderer : public GrPathRenderer {
|
||||
public:
|
||||
const char* name() const final { return "NVPR"; }
|
||||
|
||||
static GrPathRenderer* Create(GrResourceProvider*, const GrCaps&);
|
||||
|
||||
|
||||
private:
|
||||
StencilSupport onGetStencilSupport(const GrStyledShape&) const override {
|
||||
return GrPathRenderer::kStencilOnly_StencilSupport;
|
||||
}
|
||||
|
||||
CanDrawPath onCanDrawPath(const CanDrawPathArgs&) const override;
|
||||
|
||||
bool onDrawPath(const DrawPathArgs&) override;
|
||||
|
||||
void onStencilPath(const StencilPathArgs&) override;
|
||||
|
||||
GrStencilAndCoverPathRenderer(GrResourceProvider*);
|
||||
|
||||
GrResourceProvider* fResourceProvider;
|
||||
|
||||
using INHERITED = GrPathRenderer;
|
||||
};
|
||||
|
||||
#endif
|
@ -1,39 +0,0 @@
|
||||
/*
|
||||
* Copyright 2017 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "src/gpu/ops/GrStencilPathOp.h"
|
||||
|
||||
#include "include/gpu/GrRecordingContext.h"
|
||||
#include "src/gpu/GrGpu.h"
|
||||
#include "src/gpu/GrMemoryPool.h"
|
||||
#include "src/gpu/GrOpFlushState.h"
|
||||
#include "src/gpu/GrRecordingContextPriv.h"
|
||||
#include "src/gpu/GrRenderTarget.h"
|
||||
|
||||
GrOp::Owner GrStencilPathOp::Make(GrRecordingContext* context,
|
||||
const SkMatrix& viewMatrix,
|
||||
bool useHWAA,
|
||||
bool hasStencilClip,
|
||||
const GrScissorState& scissor,
|
||||
sk_sp<const GrPath> path) {
|
||||
return GrOp::Make<GrStencilPathOp>(context, viewMatrix, useHWAA,
|
||||
hasStencilClip, scissor, std::move(path));
|
||||
}
|
||||
|
||||
void GrStencilPathOp::onExecute(GrOpFlushState* state, const SkRect& chainBounds) {
|
||||
GrRenderTarget* rt = state->drawOpArgs().rtProxy()->peekRenderTarget();
|
||||
SkASSERT(rt);
|
||||
|
||||
int numStencilBits = rt->numStencilBits();
|
||||
GrStencilSettings stencil(GrPathRendering::GetStencilPassSettings(fPath->getFillType()),
|
||||
fHasStencilClip, numStencilBits);
|
||||
|
||||
GrPathRendering::StencilPathArgs args(fUseHWAA, state->drawOpArgs().rtProxy(),
|
||||
state->drawOpArgs().writeView().origin(),
|
||||
&fViewMatrix, &fScissor, &stencil);
|
||||
state->gpu()->pathRendering()->stencilPath(args, fPath.get());
|
||||
}
|
@ -1,76 +0,0 @@
|
||||
/*
|
||||
* 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 GrStencilPathOp_DEFINED
|
||||
#define GrStencilPathOp_DEFINED
|
||||
|
||||
#include "src/gpu/GrPath.h"
|
||||
#include "src/gpu/GrPathRendering.h"
|
||||
#include "src/gpu/GrScissorState.h"
|
||||
#include "src/gpu/GrStencilSettings.h"
|
||||
#include "src/gpu/ops/GrOp.h"
|
||||
|
||||
class GrOpFlushState;
|
||||
class GrRecordingContext;
|
||||
|
||||
class GrStencilPathOp final : public GrOp {
|
||||
public:
|
||||
DEFINE_OP_CLASS_ID
|
||||
|
||||
static GrOp::Owner Make(GrRecordingContext* context,
|
||||
const SkMatrix& viewMatrix,
|
||||
bool useHWAA,
|
||||
bool hasStencilClip,
|
||||
const GrScissorState& scissor,
|
||||
sk_sp<const GrPath> path);
|
||||
|
||||
const char* name() const override { return "StencilPathOp"; }
|
||||
|
||||
private:
|
||||
friend class GrOp; // for ctor
|
||||
|
||||
GrStencilPathOp(const SkMatrix& viewMatrix,
|
||||
bool useHWAA,
|
||||
bool hasStencilClip,
|
||||
const GrScissorState& scissor,
|
||||
sk_sp<const GrPath> path)
|
||||
: INHERITED(ClassID())
|
||||
, fViewMatrix(viewMatrix)
|
||||
, fUseHWAA(useHWAA)
|
||||
, fHasStencilClip(hasStencilClip)
|
||||
, fScissor(scissor)
|
||||
, fPath(std::move(path)) {
|
||||
this->setBounds(fPath->getBounds(), HasAABloat::kNo, IsHairline::kNo);
|
||||
}
|
||||
|
||||
void onPrePrepare(GrRecordingContext*,
|
||||
const GrSurfaceProxyView& writeView,
|
||||
GrAppliedClip*,
|
||||
const GrXferProcessor::DstProxyView&,
|
||||
GrXferBarrierFlags renderPassXferBarriers,
|
||||
GrLoadOp colorLoadOp) override {}
|
||||
|
||||
void onPrepare(GrOpFlushState*) override {}
|
||||
|
||||
void onExecute(GrOpFlushState*, const SkRect& chainBounds) override;
|
||||
|
||||
#if GR_TEST_UTILS
|
||||
SkString onDumpInfo() const override {
|
||||
return SkStringPrintf("Path: 0x%p, AA: %d", fPath.get(), fUseHWAA);
|
||||
}
|
||||
#endif
|
||||
|
||||
SkMatrix fViewMatrix;
|
||||
bool fUseHWAA;
|
||||
bool fHasStencilClip;
|
||||
GrScissorState fScissor;
|
||||
sk_sp<const GrPath> fPath;
|
||||
|
||||
using INHERITED = GrOp;
|
||||
};
|
||||
|
||||
#endif
|
@ -17,7 +17,6 @@
|
||||
#include "include/core/SkSurface.h"
|
||||
#include "include/effects/SkDashPathEffect.h"
|
||||
#include "include/gpu/GrDirectContext.h"
|
||||
#include "src/gpu/GrPath.h"
|
||||
#include "src/gpu/geometry/GrStyledShape.h"
|
||||
#include "tests/Test.h"
|
||||
|
||||
@ -113,76 +112,3 @@ DEF_GPUTEST_FOR_ALL_CONTEXTS(GrDrawCollapsedPath, reporter, ctxInfo) {
|
||||
surface->getCanvas()->drawPath(path, paint);
|
||||
surface->flushAndSubmit();
|
||||
}
|
||||
|
||||
DEF_GPUTEST(GrPathKeys, reporter, /* options */) {
|
||||
SkPaint strokePaint;
|
||||
strokePaint.setStyle(SkPaint::kStroke_Style);
|
||||
strokePaint.setStrokeWidth(10.f);
|
||||
GrStyle styles[] = {
|
||||
GrStyle::SimpleFill(),
|
||||
GrStyle::SimpleHairline(),
|
||||
GrStyle(strokePaint)
|
||||
};
|
||||
|
||||
for (const GrStyle& style : styles) {
|
||||
// Keys should not ignore conic weights.
|
||||
SkPath path1, path2;
|
||||
SkPoint p0 = SkPoint::Make(100, 0);
|
||||
SkPoint p1 = SkPoint::Make(100, 100);
|
||||
|
||||
path1.conicTo(p0, p1, .5f);
|
||||
path2.conicTo(p0, p1, .7f);
|
||||
|
||||
GrUniqueKey key1, key2;
|
||||
// We expect these small paths to be keyed based on their data.
|
||||
bool isVolatile;
|
||||
GrPath::ComputeKey(GrStyledShape(path1, GrStyle::SimpleFill()), &key1, &isVolatile);
|
||||
REPORTER_ASSERT(reporter, !isVolatile);
|
||||
REPORTER_ASSERT(reporter, key1.isValid());
|
||||
GrPath::ComputeKey(GrStyledShape(path2, GrStyle::SimpleFill()), &key2, &isVolatile);
|
||||
REPORTER_ASSERT(reporter, !isVolatile);
|
||||
REPORTER_ASSERT(reporter, key1.isValid());
|
||||
REPORTER_ASSERT(reporter, key1 != key2);
|
||||
{
|
||||
GrUniqueKey tempKey;
|
||||
path1.setIsVolatile(true);
|
||||
GrPath::ComputeKey(GrStyledShape(path1, style), &key1, &isVolatile);
|
||||
REPORTER_ASSERT(reporter, isVolatile);
|
||||
REPORTER_ASSERT(reporter, !tempKey.isValid());
|
||||
}
|
||||
|
||||
// Ensure that recreating the GrStyledShape doesn't change the key.
|
||||
{
|
||||
GrUniqueKey tempKey;
|
||||
GrPath::ComputeKey(GrStyledShape(path2, GrStyle::SimpleFill()), &tempKey, &isVolatile);
|
||||
REPORTER_ASSERT(reporter, key2 == tempKey);
|
||||
}
|
||||
|
||||
// Try a large path that is too big to be keyed off its data.
|
||||
SkPath path3;
|
||||
SkPath path4;
|
||||
for (int i = 0; i < 1000; ++i) {
|
||||
SkScalar s = SkIntToScalar(i);
|
||||
path3.conicTo(s, 3.f * s / 4, s + 1.f, s, 0.5f + s / 2000.f);
|
||||
path4.conicTo(s, 3.f * s / 4, s + 1.f, s, 0.3f + s / 2000.f);
|
||||
}
|
||||
|
||||
GrUniqueKey key3, key4;
|
||||
// These aren't marked volatile and so should have keys
|
||||
GrPath::ComputeKey(GrStyledShape(path3, style), &key3, &isVolatile);
|
||||
REPORTER_ASSERT(reporter, !isVolatile);
|
||||
REPORTER_ASSERT(reporter, key3.isValid());
|
||||
GrPath::ComputeKey(GrStyledShape(path4, style), &key4, &isVolatile);
|
||||
REPORTER_ASSERT(reporter, !isVolatile);
|
||||
REPORTER_ASSERT(reporter, key4.isValid());
|
||||
REPORTER_ASSERT(reporter, key3 != key4);
|
||||
|
||||
{
|
||||
GrUniqueKey tempKey;
|
||||
path3.setIsVolatile(true);
|
||||
GrPath::ComputeKey(GrStyledShape(path3, style), &key1, &isVolatile);
|
||||
REPORTER_ASSERT(reporter, isVolatile);
|
||||
REPORTER_ASSERT(reporter, !tempKey.isValid());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -44,8 +44,6 @@ static GpuPathRenderers get_named_pathrenderers_flags(const char* name) {
|
||||
return GpuPathRenderers::kNone;
|
||||
} else if (!strcmp(name, "dashline")) {
|
||||
return GpuPathRenderers::kDashLine;
|
||||
} else if (!strcmp(name, "nvpr")) {
|
||||
return GpuPathRenderers::kStencilAndCover;
|
||||
} else if (!strcmp(name, "ccpr")) {
|
||||
return GpuPathRenderers::kCoverageCounting;
|
||||
} else if (!strcmp(name, "aahairline")) {
|
||||
|
@ -531,27 +531,42 @@
|
||||
],
|
||||
},
|
||||
{
|
||||
"GL": [{"ext": "GL_NV_path_rendering"}],
|
||||
"GLES": [{"ext": "GL_CHROMIUM_path_rendering"},
|
||||
{"ext": "GL_NV_path_rendering"}],
|
||||
"GL": [ { "ext": "GL_NV_path_rendering" } ],
|
||||
"GLES": [
|
||||
{ "ext": "GL_CHROMIUM_path_rendering" },
|
||||
{ "ext": "GL_NV_path_rendering" }
|
||||
],
|
||||
"WebGL": null,
|
||||
|
||||
"functions": [
|
||||
"CoverFillPath", "CoverFillPathInstanced", "CoverStrokePath",
|
||||
"CoverStrokePathInstanced", "DeletePaths", "GenPaths",
|
||||
"IsPath", "PathCommands", "PathParameterf", "PathParameteri",
|
||||
"PathStencilFunc", "ProgramPathFragmentInputGen", "StencilFillPath",
|
||||
"StencilFillPathInstanced", "StencilStrokePath", "StencilStrokePathInstanced",
|
||||
"StencilThenCoverFillPath", "StencilThenCoverFillPathInstanced",
|
||||
"StencilThenCoverStrokePath", "StencilThenCoverStrokePathInstanced",
|
||||
"CoverFillPath",
|
||||
"CoverFillPathInstanced",
|
||||
"CoverStrokePath",
|
||||
"CoverStrokePathInstanced",
|
||||
"DeletePaths",
|
||||
"GenPaths",
|
||||
"IsPath",
|
||||
"PathCommands",
|
||||
"PathParameterf",
|
||||
"PathParameteri",
|
||||
"PathStencilFunc",
|
||||
"ProgramPathFragmentInputGen",
|
||||
"StencilFillPath",
|
||||
"StencilFillPathInstanced",
|
||||
"StencilStrokePath",
|
||||
"StencilStrokePathInstanced",
|
||||
"StencilThenCoverFillPath",
|
||||
"StencilThenCoverFillPathInstanced",
|
||||
"StencilThenCoverStrokePath",
|
||||
"StencilThenCoverStrokePathInstanced",
|
||||
],
|
||||
// List of functions that Skia uses, but which have been added since the initial release
|
||||
// of NV_path_rendering driver. We do not want to fail interface validation due to
|
||||
// missing features, we will just not use the extension.
|
||||
// If one updates this list, then update GrGLCaps::hasPathRenderingSupport too.
|
||||
// TODO: remove these functions. Since Skia no longer supports NV_path_rendering
|
||||
// these will never be used.
|
||||
"optional": [
|
||||
"ProgramPathFragmentInputGen", "StencilThenCoverFillPath",
|
||||
"StencilThenCoverFillPathInstanced", "StencilThenCoverStrokePath",
|
||||
"ProgramPathFragmentInputGen",
|
||||
"StencilThenCoverFillPath",
|
||||
"StencilThenCoverFillPathInstanced",
|
||||
"StencilThenCoverStrokePath",
|
||||
"StencilThenCoverStrokePathInstanced",
|
||||
],
|
||||
},
|
||||
|
@ -341,7 +341,6 @@ Viewer::Viewer(int argc, char** argv, void* platformData)
|
||||
|
||||
gPathRendererNames[GpuPathRenderers::kDefault] = "Default Path Renderers";
|
||||
gPathRendererNames[GpuPathRenderers::kTessellation] = "Tessellation";
|
||||
gPathRendererNames[GpuPathRenderers::kStencilAndCover] = "NV_path_rendering";
|
||||
gPathRendererNames[GpuPathRenderers::kSmall] = "Small paths (cached sdf or alpha masks)";
|
||||
gPathRendererNames[GpuPathRenderers::kCoverageCounting] = "CCPR";
|
||||
gPathRendererNames[GpuPathRenderers::kTriangulating] = "Triangulating";
|
||||
@ -1913,9 +1912,6 @@ void Viewer::drawImGui() {
|
||||
if (GrTessellationPathRenderer::IsSupported(*caps)) {
|
||||
prButton(GpuPathRenderers::kTessellation);
|
||||
}
|
||||
if (caps->shaderCaps()->pathRenderingSupport()) {
|
||||
prButton(GpuPathRenderers::kStencilAndCover);
|
||||
}
|
||||
}
|
||||
if (1 == fWindow->sampleCount()) {
|
||||
if (GrCoverageCountingPathRenderer::IsSupported(*caps)) {
|
||||
@ -2738,10 +2734,6 @@ void Viewer::updateUIState() {
|
||||
writer.appendString(
|
||||
gPathRendererNames[GpuPathRenderers::kTessellation].c_str());
|
||||
}
|
||||
if (caps->shaderCaps()->pathRenderingSupport()) {
|
||||
writer.appendString(
|
||||
gPathRendererNames[GpuPathRenderers::kStencilAndCover].c_str());
|
||||
}
|
||||
}
|
||||
if (1 == fWindow->sampleCount()) {
|
||||
if(GrCoverageCountingPathRenderer::IsSupported(*caps)) {
|
||||
|
Loading…
Reference in New Issue
Block a user