converted GrSimpleTextureEffect to sksl
Bug: skia: Change-Id: If556c6baad75f22135f429759feabaaec095b900 Reviewed-on: https://skia-review.googlesource.com/21720 Commit-Queue: Ethan Nicholas <ethannicholas@google.com> Reviewed-by: Greg Daniel <egdaniel@google.com>
This commit is contained in:
parent
6ee2965820
commit
46b654df9e
@ -27,4 +27,5 @@ skia_gpu_processor_sources = [
|
||||
"$_src/effects/GrAlphaThresholdFragmentProcessor.fp",
|
||||
"$_src/effects/GrCircleBlurFragmentProcessor.fp",
|
||||
"$_src/gpu/effects/GrDitherEffect.fp",
|
||||
"$_src/gpu/effects/GrSimpleTextureEffect.fp",
|
||||
]
|
||||
|
@ -28,20 +28,12 @@ in uniform float outerThreshold;
|
||||
}
|
||||
}
|
||||
|
||||
@fields {
|
||||
GrCoordTransform fImageCoordTransform;
|
||||
GrCoordTransform fMaskCoordTransform;
|
||||
@coordTransform(image) {
|
||||
SkMatrix::I()
|
||||
}
|
||||
|
||||
@initializers {
|
||||
fImageCoordTransform(SkMatrix::I(), image.get()),
|
||||
fMaskCoordTransform(SkMatrix::MakeTrans(SkIntToScalar(-bounds.x()), SkIntToScalar(-bounds.y())),
|
||||
mask.get())
|
||||
}
|
||||
|
||||
@constructorCode {
|
||||
this->addCoordTransform(&fImageCoordTransform);
|
||||
this->addCoordTransform(&fMaskCoordTransform);
|
||||
@coordTransform(mask) {
|
||||
SkMatrix::MakeTrans(SkIntToScalar(-bounds.x()), SkIntToScalar(-bounds.y()))
|
||||
}
|
||||
|
||||
@header {
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include "GrColorSpaceXform.h"
|
||||
#include "GrFragmentProcessor.h"
|
||||
#include "GrCoordTransform.h"
|
||||
#include "GrColorSpaceXform.h"
|
||||
#include "effects/GrProxyMove.h"
|
||||
class GrAlphaThresholdFragmentProcessor : public GrFragmentProcessor {
|
||||
public:
|
||||
@ -44,35 +45,34 @@ private:
|
||||
const SkIRect& bounds
|
||||
)
|
||||
: INHERITED(kNone_OptimizationFlags)
|
||||
,
|
||||
fImageCoordTransform(SkMatrix::I(), image.get()),
|
||||
fMaskCoordTransform(SkMatrix::MakeTrans(SkIntToScalar(-bounds.x()), SkIntToScalar(-bounds.y())),
|
||||
mask.get())
|
||||
|
||||
, fImage(std::move(image))
|
||||
, fColorXform(colorXform)
|
||||
, fMask(std::move(mask))
|
||||
, fInnerThreshold(innerThreshold)
|
||||
, fOuterThreshold(outerThreshold) {
|
||||
|
||||
this->addCoordTransform(&fImageCoordTransform);
|
||||
this->addCoordTransform(&fMaskCoordTransform);
|
||||
, fOuterThreshold(outerThreshold)
|
||||
, fImageCoordTransform(
|
||||
SkMatrix::I()
|
||||
, fImage.proxy())
|
||||
, fMaskCoordTransform(
|
||||
SkMatrix::MakeTrans(SkIntToScalar(-bounds.x()), SkIntToScalar(-bounds.y()))
|
||||
, fMask.proxy()) {
|
||||
this->addTextureSampler(&fImage);
|
||||
this->addTextureSampler(&fMask);
|
||||
this->addCoordTransform(&fImageCoordTransform);
|
||||
this->addCoordTransform(&fMaskCoordTransform);
|
||||
this->initClassID<GrAlphaThresholdFragmentProcessor>();
|
||||
}
|
||||
GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
|
||||
void onGetGLSLProcessorKey(const GrShaderCaps&,GrProcessorKeyBuilder*) const override;
|
||||
bool onIsEqual(const GrFragmentProcessor&) const override;
|
||||
GR_DECLARE_FRAGMENT_PROCESSOR_TEST
|
||||
|
||||
GrCoordTransform fImageCoordTransform;
|
||||
GrCoordTransform fMaskCoordTransform;
|
||||
TextureSampler fImage;
|
||||
sk_sp<GrColorSpaceXform> fColorXform;
|
||||
TextureSampler fMask;
|
||||
float fInnerThreshold;
|
||||
float fOuterThreshold;
|
||||
GrCoordTransform fImageCoordTransform;
|
||||
GrCoordTransform fMaskCoordTransform;
|
||||
typedef GrFragmentProcessor INHERITED;
|
||||
};
|
||||
#endif
|
||||
|
@ -14,6 +14,7 @@
|
||||
#if SK_SUPPORT_GPU
|
||||
#include "GrFragmentProcessor.h"
|
||||
#include "GrCoordTransform.h"
|
||||
#include "GrColorSpaceXform.h"
|
||||
#include "effects/GrProxyMove.h"
|
||||
class GrCircleBlurFragmentProcessor : public GrFragmentProcessor {
|
||||
public:
|
||||
|
@ -14,6 +14,7 @@
|
||||
#if SK_SUPPORT_GPU
|
||||
#include "GrFragmentProcessor.h"
|
||||
#include "GrCoordTransform.h"
|
||||
#include "GrColorSpaceXform.h"
|
||||
#include "effects/GrProxyMove.h"
|
||||
class GrDitherEffect : public GrFragmentProcessor {
|
||||
public:
|
||||
|
@ -1,111 +1,81 @@
|
||||
/*
|
||||
* Copyright 2012 Google Inc.
|
||||
* Copyright 2017 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file was autogenerated from GrSimpleTextureEffect.fp; do not modify.
|
||||
*/
|
||||
#include "GrSimpleTextureEffect.h"
|
||||
#include "GrProxyMove.h"
|
||||
#if SK_SUPPORT_GPU
|
||||
#include "glsl/GrGLSLColorSpaceXformHelper.h"
|
||||
#include "glsl/GrGLSLFragmentProcessor.h"
|
||||
#include "glsl/GrGLSLFragmentShaderBuilder.h"
|
||||
|
||||
GrSimpleTextureEffect::GrSimpleTextureEffect(sk_sp<GrTextureProxy> proxy,
|
||||
sk_sp<GrColorSpaceXform> colorSpaceXform,
|
||||
const SkMatrix& matrix,
|
||||
GrSamplerParams::FilterMode filterMode)
|
||||
: INHERITED{ModulationFlags(proxy->config()),
|
||||
GR_PROXY_MOVE(proxy),
|
||||
std::move(colorSpaceXform),
|
||||
matrix,
|
||||
filterMode} {
|
||||
this->initClassID<GrSimpleTextureEffect>();
|
||||
}
|
||||
|
||||
GrSimpleTextureEffect::GrSimpleTextureEffect(sk_sp<GrTextureProxy> proxy,
|
||||
sk_sp<GrColorSpaceXform> colorSpaceXform,
|
||||
const SkMatrix& matrix,
|
||||
const GrSamplerParams& params)
|
||||
: INHERITED{ModulationFlags(proxy->config()),
|
||||
GR_PROXY_MOVE(proxy),
|
||||
std::move(colorSpaceXform),
|
||||
matrix,
|
||||
params} {
|
||||
this->initClassID<GrSimpleTextureEffect>();
|
||||
}
|
||||
|
||||
class GrGLSimpleTextureEffect : public GrGLSLFragmentProcessor {
|
||||
#include "glsl/GrGLSLProgramBuilder.h"
|
||||
#include "SkSLCPP.h"
|
||||
#include "SkSLUtil.h"
|
||||
class GrGLSLSimpleTextureEffect : public GrGLSLFragmentProcessor {
|
||||
public:
|
||||
GrGLSLSimpleTextureEffect() {}
|
||||
void emitCode(EmitArgs& args) override {
|
||||
const GrSimpleTextureEffect& textureEffect = args.fFp.cast<GrSimpleTextureEffect>();
|
||||
fColorSpaceHelper.emitCode(args.fUniformHandler, textureEffect.colorSpaceXform());
|
||||
|
||||
GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
|
||||
fragBuilder->codeAppendf("%s = ", args.fOutputColor);
|
||||
fragBuilder->appendTextureLookupAndModulate(args.fInputColor,
|
||||
args.fTexSamplers[0],
|
||||
args.fTransformedCoords[0].c_str(),
|
||||
args.fTransformedCoords[0].getType(),
|
||||
&fColorSpaceHelper);
|
||||
fragBuilder->codeAppend(";");
|
||||
const GrSimpleTextureEffect& _outer = args.fFp.cast<GrSimpleTextureEffect>();
|
||||
(void) _outer;
|
||||
fColorSpaceHelper.emitCode(args.fUniformHandler, _outer.colorXform().get());
|
||||
SkSL::String sk_TransformedCoords2D_0 = fragBuilder->ensureCoords2D(args.fTransformedCoords[0]);
|
||||
fragBuilder->codeAppendf("vec4 _tmp0;\n%s = %s * (_tmp0 = texture(%s, %s).%s , %s != mat4(1.0) ? vec4(clamp((%s * vec4(_tmp0.xyz, 1.0)).xyz, 0.0, _tmp0.w), _tmp0.w) : _tmp0);\n", args.fOutputColor, args.fInputColor ? args.fInputColor : "vec4(1)", fragBuilder->getProgramBuilder()->samplerVariable(args.fTexSamplers[0]).c_str(), sk_TransformedCoords2D_0.c_str(), fragBuilder->getProgramBuilder()->samplerSwizzle(args.fTexSamplers[0]).c_str(), fColorSpaceHelper.isValid() ? args.fUniformHandler->getUniformCStr(fColorSpaceHelper.gamutXformUniform()) : "mat4(1.0)", fColorSpaceHelper.isValid() ? args.fUniformHandler->getUniformCStr(fColorSpaceHelper.gamutXformUniform()) : "mat4(1.0)");
|
||||
}
|
||||
|
||||
static inline void GenKey(const GrProcessor& effect, const GrShaderCaps&,
|
||||
GrProcessorKeyBuilder* b) {
|
||||
const GrSimpleTextureEffect& textureEffect = effect.cast<GrSimpleTextureEffect>();
|
||||
b->add32(GrColorSpaceXform::XformKey(textureEffect.colorSpaceXform()));
|
||||
}
|
||||
|
||||
protected:
|
||||
void onSetData(const GrGLSLProgramDataManager& pdman,
|
||||
const GrFragmentProcessor& processor) override {
|
||||
const GrSimpleTextureEffect& textureEffect = processor.cast<GrSimpleTextureEffect>();
|
||||
if (SkToBool(textureEffect.colorSpaceXform())) {
|
||||
fColorSpaceHelper.setData(pdman, textureEffect.colorSpaceXform());
|
||||
private:
|
||||
void onSetData(const GrGLSLProgramDataManager& pdman, const GrFragmentProcessor& _proc) override {
|
||||
const GrSimpleTextureEffect& _outer = _proc.cast<GrSimpleTextureEffect>();
|
||||
{
|
||||
if (fColorSpaceHelper.isValid()) {
|
||||
fColorSpaceHelper.setData(pdman, _outer.colorXform().get());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
typedef GrGLSLFragmentProcessor INHERITED;
|
||||
|
||||
UniformHandle fImageVar;
|
||||
GrGLSLColorSpaceXformHelper fColorSpaceHelper;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void GrSimpleTextureEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps,
|
||||
GrProcessorKeyBuilder* b) const {
|
||||
GrGLSimpleTextureEffect::GenKey(*this, caps, b);
|
||||
GrGLSLFragmentProcessor* GrSimpleTextureEffect::onCreateGLSLInstance() const {
|
||||
return new GrGLSLSimpleTextureEffect();
|
||||
}
|
||||
|
||||
GrGLSLFragmentProcessor* GrSimpleTextureEffect::onCreateGLSLInstance() const {
|
||||
return new GrGLSimpleTextureEffect;
|
||||
void GrSimpleTextureEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const {
|
||||
b->add32(GrColorSpaceXform::XformKey(fColorXform.get()));
|
||||
}
|
||||
bool GrSimpleTextureEffect::onIsEqual(const GrFragmentProcessor& other) const {
|
||||
const GrSimpleTextureEffect& that = other.cast<GrSimpleTextureEffect>();
|
||||
(void) that;
|
||||
if (fImage != that.fImage) return false;
|
||||
if (fColorXform != that.fColorXform) return false;
|
||||
if (fMatrix != that.fMatrix) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrSimpleTextureEffect);
|
||||
|
||||
#if GR_TEST_UTILS
|
||||
sk_sp<GrFragmentProcessor> GrSimpleTextureEffect::TestCreate(GrProcessorTestData* d) {
|
||||
int texIdx = d->fRandom->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx
|
||||
: GrProcessorUnitTest::kAlphaTextureIdx;
|
||||
sk_sp<GrFragmentProcessor> GrSimpleTextureEffect::TestCreate(GrProcessorTestData* testData) {
|
||||
|
||||
int texIdx = testData->fRandom->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx
|
||||
: GrProcessorUnitTest::kAlphaTextureIdx;
|
||||
static const SkShader::TileMode kTileModes[] = {
|
||||
SkShader::kClamp_TileMode,
|
||||
SkShader::kRepeat_TileMode,
|
||||
SkShader::kMirror_TileMode,
|
||||
};
|
||||
SkShader::TileMode tileModes[] = {
|
||||
kTileModes[d->fRandom->nextULessThan(SK_ARRAY_COUNT(kTileModes))],
|
||||
kTileModes[d->fRandom->nextULessThan(SK_ARRAY_COUNT(kTileModes))],
|
||||
kTileModes[testData->fRandom->nextULessThan(SK_ARRAY_COUNT(kTileModes))],
|
||||
kTileModes[testData->fRandom->nextULessThan(SK_ARRAY_COUNT(kTileModes))],
|
||||
};
|
||||
GrSamplerParams params(tileModes, d->fRandom->nextBool() ? GrSamplerParams::kBilerp_FilterMode
|
||||
: GrSamplerParams::kNone_FilterMode);
|
||||
GrSamplerParams params(tileModes, testData->fRandom->nextBool()
|
||||
? GrSamplerParams::kBilerp_FilterMode
|
||||
: GrSamplerParams::kNone_FilterMode);
|
||||
|
||||
const SkMatrix& matrix = GrTest::TestMatrix(d->fRandom);
|
||||
sk_sp<GrColorSpaceXform> colorSpaceXform = GrTest::TestColorXform(d->fRandom);
|
||||
return GrSimpleTextureEffect::Make(d->textureProxy(texIdx),
|
||||
std::move(colorSpaceXform), matrix);
|
||||
const SkMatrix& matrix = GrTest::TestMatrix(testData->fRandom);
|
||||
sk_sp<GrColorSpaceXform> colorSpaceXform = GrTest::TestColorXform(testData->fRandom);
|
||||
return GrSimpleTextureEffect::Make(testData->textureProxy(texIdx), std::move(colorSpaceXform),
|
||||
matrix);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
82
src/gpu/effects/GrSimpleTextureEffect.fp
Normal file
82
src/gpu/effects/GrSimpleTextureEffect.fp
Normal file
@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright 2017 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
in uniform sampler2D image;
|
||||
in uniform colorSpaceXform colorXform;
|
||||
in mat4 matrix;
|
||||
|
||||
@constructorParams {
|
||||
GrSamplerParams samplerParams
|
||||
}
|
||||
|
||||
@coordTransform(image) {
|
||||
matrix
|
||||
}
|
||||
|
||||
@samplerParams(image) {
|
||||
samplerParams
|
||||
}
|
||||
|
||||
@make {
|
||||
static sk_sp<GrFragmentProcessor> Make(sk_sp<GrTextureProxy> proxy,
|
||||
sk_sp<GrColorSpaceXform> colorSpaceXform,
|
||||
const SkMatrix& matrix) {
|
||||
return sk_sp<GrFragmentProcessor>(
|
||||
new GrSimpleTextureEffect(std::move(proxy), std::move(colorSpaceXform), matrix,
|
||||
GrSamplerParams(SkShader::kClamp_TileMode, GrSamplerParams::kNone_FilterMode)));
|
||||
}
|
||||
|
||||
/* clamp mode */
|
||||
static sk_sp<GrFragmentProcessor> Make(sk_sp<GrTextureProxy> proxy,
|
||||
sk_sp<GrColorSpaceXform> colorSpaceXform,
|
||||
const SkMatrix& matrix,
|
||||
GrSamplerParams::FilterMode filterMode) {
|
||||
return sk_sp<GrFragmentProcessor>(
|
||||
new GrSimpleTextureEffect(std::move(proxy), std::move(colorSpaceXform), matrix,
|
||||
GrSamplerParams(SkShader::kClamp_TileMode, filterMode)));
|
||||
}
|
||||
|
||||
static sk_sp<GrFragmentProcessor> Make(sk_sp<GrTextureProxy> proxy,
|
||||
sk_sp<GrColorSpaceXform> colorSpaceXform,
|
||||
const SkMatrix& matrix,
|
||||
const GrSamplerParams& p) {
|
||||
return sk_sp<GrFragmentProcessor>(
|
||||
new GrSimpleTextureEffect(std::move(proxy), std::move(colorSpaceXform), matrix, p));
|
||||
}
|
||||
}
|
||||
|
||||
@optimizationFlags {
|
||||
kCompatibleWithCoverageAsAlpha_OptimizationFlag |
|
||||
(GrPixelConfigIsOpaque(image->config()) ? kPreservesOpaqueInput_OptimizationFlag :
|
||||
kNone_OptimizationFlags)
|
||||
}
|
||||
|
||||
void main() {
|
||||
sk_OutColor = sk_InColor * texture(image, sk_TransformedCoords2D[0], colorXform);
|
||||
}
|
||||
|
||||
@test(testData) {
|
||||
int texIdx = testData->fRandom->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx
|
||||
: GrProcessorUnitTest::kAlphaTextureIdx;
|
||||
static const SkShader::TileMode kTileModes[] = {
|
||||
SkShader::kClamp_TileMode,
|
||||
SkShader::kRepeat_TileMode,
|
||||
SkShader::kMirror_TileMode,
|
||||
};
|
||||
SkShader::TileMode tileModes[] = {
|
||||
kTileModes[testData->fRandom->nextULessThan(SK_ARRAY_COUNT(kTileModes))],
|
||||
kTileModes[testData->fRandom->nextULessThan(SK_ARRAY_COUNT(kTileModes))],
|
||||
};
|
||||
GrSamplerParams params(tileModes, testData->fRandom->nextBool()
|
||||
? GrSamplerParams::kBilerp_FilterMode
|
||||
: GrSamplerParams::kNone_FilterMode);
|
||||
|
||||
const SkMatrix& matrix = GrTest::TestMatrix(testData->fRandom);
|
||||
sk_sp<GrColorSpaceXform> colorSpaceXform = GrTest::TestColorXform(testData->fRandom);
|
||||
return GrSimpleTextureEffect::Make(testData->textureProxy(texIdx), std::move(colorSpaceXform),
|
||||
matrix);
|
||||
}
|
@ -1,77 +1,82 @@
|
||||
/*
|
||||
* Copyright 2013 Google Inc.
|
||||
* Copyright 2017 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file was autogenerated from GrSimpleTextureEffect.fp; do not modify.
|
||||
*/
|
||||
#ifndef GrSimpleTextureEffect_DEFINED
|
||||
#define GrSimpleTextureEffect_DEFINED
|
||||
|
||||
#include "GrSingleTextureEffect.h"
|
||||
#include "GrTextureProxy.h"
|
||||
|
||||
class GrInvariantOutput;
|
||||
|
||||
/**
|
||||
* The output color of this effect is a modulation of the input color and a sample from a texture.
|
||||
* It allows explicit specification of the filtering and wrap modes (GrSamplerParams) and accepts
|
||||
* a matrix that is used to compute texture coordinates from local coordinates.
|
||||
*/
|
||||
class GrSimpleTextureEffect : public GrSingleTextureEffect {
|
||||
#include "SkTypes.h"
|
||||
#if SK_SUPPORT_GPU
|
||||
#include "GrFragmentProcessor.h"
|
||||
#include "GrCoordTransform.h"
|
||||
#include "GrColorSpaceXform.h"
|
||||
#include "effects/GrProxyMove.h"
|
||||
class GrSimpleTextureEffect : public GrFragmentProcessor {
|
||||
public:
|
||||
/* unfiltered, clamp mode */
|
||||
sk_sp<GrColorSpaceXform> colorXform() const { return fColorXform; }
|
||||
SkMatrix44 matrix() const { return fMatrix; }
|
||||
|
||||
static sk_sp<GrFragmentProcessor> Make(sk_sp<GrTextureProxy> proxy,
|
||||
sk_sp<GrColorSpaceXform> colorSpaceXform,
|
||||
const SkMatrix& matrix) {
|
||||
return sk_sp<GrFragmentProcessor>(
|
||||
new GrSimpleTextureEffect(std::move(proxy),
|
||||
std::move(colorSpaceXform), matrix,
|
||||
GrSamplerParams::kNone_FilterMode));
|
||||
new GrSimpleTextureEffect(std::move(proxy), std::move(colorSpaceXform), matrix,
|
||||
GrSamplerParams(SkShader::kClamp_TileMode, GrSamplerParams::kNone_FilterMode)));
|
||||
}
|
||||
|
||||
/* clamp mode */
|
||||
|
||||
static sk_sp<GrFragmentProcessor> Make(sk_sp<GrTextureProxy> proxy,
|
||||
sk_sp<GrColorSpaceXform> colorSpaceXform,
|
||||
const SkMatrix& matrix,
|
||||
GrSamplerParams::FilterMode filterMode) {
|
||||
return sk_sp<GrFragmentProcessor>(
|
||||
new GrSimpleTextureEffect(std::move(proxy),
|
||||
std::move(colorSpaceXform),
|
||||
matrix, filterMode));
|
||||
}
|
||||
new GrSimpleTextureEffect(std::move(proxy), std::move(colorSpaceXform), matrix,
|
||||
GrSamplerParams(SkShader::kClamp_TileMode, filterMode)));
|
||||
}
|
||||
|
||||
static sk_sp<GrFragmentProcessor> Make(sk_sp<GrTextureProxy> proxy,
|
||||
sk_sp<GrColorSpaceXform> colorSpaceXform,
|
||||
const SkMatrix& matrix,
|
||||
const GrSamplerParams& p) {
|
||||
return sk_sp<GrFragmentProcessor>(new GrSimpleTextureEffect(std::move(proxy),
|
||||
std::move(colorSpaceXform),
|
||||
matrix, p));
|
||||
return sk_sp<GrFragmentProcessor>(
|
||||
new GrSimpleTextureEffect(std::move(proxy), std::move(colorSpaceXform), matrix, p));
|
||||
}
|
||||
|
||||
~GrSimpleTextureEffect() override {}
|
||||
|
||||
const char* name() const override { return "SimpleTexture"; }
|
||||
|
||||
const char* name() const override { return "SimpleTextureEffect"; }
|
||||
private:
|
||||
GrSimpleTextureEffect(sk_sp<GrTextureProxy>,
|
||||
sk_sp<GrColorSpaceXform>, const SkMatrix& matrix,
|
||||
GrSamplerParams::FilterMode);
|
||||
|
||||
GrSimpleTextureEffect(sk_sp<GrTextureProxy>,
|
||||
sk_sp<GrColorSpaceXform>, const SkMatrix& matrix,
|
||||
const GrSamplerParams&);
|
||||
|
||||
GrSimpleTextureEffect(sk_sp<GrTextureProxy> image, sk_sp<GrColorSpaceXform> colorXform, SkMatrix44 matrix,
|
||||
GrSamplerParams samplerParams
|
||||
)
|
||||
: INHERITED((OptimizationFlags)
|
||||
kCompatibleWithCoverageAsAlpha_OptimizationFlag |
|
||||
(GrPixelConfigIsOpaque(image->config()) ? kPreservesOpaqueInput_OptimizationFlag :
|
||||
kNone_OptimizationFlags)
|
||||
)
|
||||
, fImage(std::move(image),
|
||||
samplerParams
|
||||
)
|
||||
, fColorXform(colorXform)
|
||||
, fMatrix(matrix)
|
||||
, fImageCoordTransform(
|
||||
matrix
|
||||
, fImage.proxy()) {
|
||||
this->addTextureSampler(&fImage);
|
||||
this->addCoordTransform(&fImageCoordTransform);
|
||||
this->initClassID<GrSimpleTextureEffect>();
|
||||
}
|
||||
GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
|
||||
|
||||
void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
|
||||
|
||||
bool onIsEqual(const GrFragmentProcessor& other) const override { return true; }
|
||||
|
||||
void onGetGLSLProcessorKey(const GrShaderCaps&,GrProcessorKeyBuilder*) const override;
|
||||
bool onIsEqual(const GrFragmentProcessor&) const override;
|
||||
GR_DECLARE_FRAGMENT_PROCESSOR_TEST
|
||||
|
||||
typedef GrSingleTextureEffect INHERITED;
|
||||
TextureSampler fImage;
|
||||
sk_sp<GrColorSpaceXform> fColorXform;
|
||||
SkMatrix44 fMatrix;
|
||||
GrCoordTransform fImageCoordTransform;
|
||||
typedef GrFragmentProcessor INHERITED;
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
@ -89,6 +89,11 @@ Within an '.fp' fragment processor file:
|
||||
the name of the GrGLSLProgramDataManager)
|
||||
@test(<testData>) (the body of the TestCreate function, where <testData> is
|
||||
the name of the GrProcessorTestData* parameter)
|
||||
@coordTransform(<sampler>)
|
||||
(the matrix to attach to the named sampler2D's
|
||||
GrCoordTransform)
|
||||
@samplerParams(<sampler>)
|
||||
(the sampler params to attach to the named sampler2D)
|
||||
* global 'in' variables represent data passed to the fragment processor at
|
||||
construction time. These variables become constructor parameters and are
|
||||
stored in fragment processor fields. vec2s map to SkPoints, and vec4s map to
|
||||
|
@ -163,7 +163,7 @@ void CPPCodeGenerator::writeVarInitializer(const Variable& var, const Expression
|
||||
|
||||
String CPPCodeGenerator::getSamplerHandle(const Variable& var) {
|
||||
int samplerCount = 0;
|
||||
for (const auto param : fSectionAndParameterHelper.fParameters) {
|
||||
for (const auto param : fSectionAndParameterHelper.getParameters()) {
|
||||
if (&var == param) {
|
||||
return "args.fTexSamplers[" + to_string(samplerCount) + "]";
|
||||
}
|
||||
@ -267,9 +267,9 @@ void CPPCodeGenerator::writeSetting(const Setting& s) {
|
||||
}
|
||||
|
||||
void CPPCodeGenerator::writeSection(const char* name, const char* prefix) {
|
||||
const auto found = fSectionAndParameterHelper.fSections.find(String(name));
|
||||
if (found != fSectionAndParameterHelper.fSections.end()) {
|
||||
this->writef("%s%s", prefix, found->second->fText.c_str());
|
||||
const Section* s = fSectionAndParameterHelper.getSection(name);
|
||||
if (s) {
|
||||
this->writef("%s%s", prefix, s->fText.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
@ -398,10 +398,8 @@ bool CPPCodeGenerator::writeEmitCode(std::vector<const Variable*>& uniforms) {
|
||||
|
||||
void CPPCodeGenerator::writeSetData(std::vector<const Variable*>& uniforms) {
|
||||
const char* fullName = fFullName.c_str();
|
||||
auto section = fSectionAndParameterHelper.fSections.find(String(SET_DATA_SECTION));
|
||||
const char* pdman = section != fSectionAndParameterHelper.fSections.end() ?
|
||||
section->second->fArgument.c_str() :
|
||||
"pdman";
|
||||
const Section* section = fSectionAndParameterHelper.getSection(SET_DATA_SECTION);
|
||||
const char* pdman = section ? section->fArgument.c_str() : "pdman";
|
||||
this->writef(" void onSetData(const GrGLSLProgramDataManager& %s, "
|
||||
"const GrFragmentProcessor& _proc) override {\n",
|
||||
pdman);
|
||||
@ -439,7 +437,7 @@ void CPPCodeGenerator::writeSetData(std::vector<const Variable*>& uniforms) {
|
||||
if (wroteProcessor) {
|
||||
this->writef(" }\n");
|
||||
}
|
||||
if (section != fSectionAndParameterHelper.fSections.end()) {
|
||||
if (section) {
|
||||
for (const auto& p : fProgram.fElements) {
|
||||
if (ProgramElement::kVar_Kind == p->fKind) {
|
||||
const VarDeclarations* decls = (const VarDeclarations*) p.get();
|
||||
@ -470,27 +468,25 @@ void CPPCodeGenerator::writeSetData(std::vector<const Variable*>& uniforms) {
|
||||
}
|
||||
|
||||
void CPPCodeGenerator::writeTest() {
|
||||
const auto found = fSectionAndParameterHelper.fSections.find(TEST_CODE_SECTION);
|
||||
if (found == fSectionAndParameterHelper.fSections.end()) {
|
||||
return;
|
||||
const Section* test = fSectionAndParameterHelper.getSection(TEST_CODE_SECTION);
|
||||
if (test) {
|
||||
this->writef("GR_DEFINE_FRAGMENT_PROCESSOR_TEST(%s);\n"
|
||||
"#if GR_TEST_UTILS\n"
|
||||
"sk_sp<GrFragmentProcessor> %s::TestCreate(GrProcessorTestData* %s) {\n",
|
||||
fFullName.c_str(),
|
||||
fFullName.c_str(),
|
||||
test->fArgument.c_str());
|
||||
this->writeSection(TEST_CODE_SECTION);
|
||||
this->write("}\n"
|
||||
"#endif\n");
|
||||
}
|
||||
const Section* test = found->second;
|
||||
this->writef("GR_DEFINE_FRAGMENT_PROCESSOR_TEST(%s);\n"
|
||||
"#if GR_TEST_UTILS\n"
|
||||
"sk_sp<GrFragmentProcessor> %s::TestCreate(GrProcessorTestData* %s) {\n",
|
||||
fFullName.c_str(),
|
||||
fFullName.c_str(),
|
||||
test->fArgument.c_str());
|
||||
this->writeSection(TEST_CODE_SECTION);
|
||||
this->write("}\n"
|
||||
"#endif\n");
|
||||
}
|
||||
|
||||
void CPPCodeGenerator::writeGetKey() {
|
||||
this->writef("void %s::onGetGLSLProcessorKey(const GrShaderCaps& caps, "
|
||||
"GrProcessorKeyBuilder* b) const {\n",
|
||||
fFullName.c_str());
|
||||
for (const auto& param : fSectionAndParameterHelper.fParameters) {
|
||||
for (const auto& param : fSectionAndParameterHelper.getParameters()) {
|
||||
const char* name = param->fName.c_str();
|
||||
if (param->fType == *fContext.fColorSpaceXform_Type) {
|
||||
this->writef(" b->add32(GrColorSpaceXform::XformKey(%s.get()));\n",
|
||||
@ -580,7 +576,7 @@ bool CPPCodeGenerator::generateCode() {
|
||||
this->writef(" UniformHandle %sVar;\n", HCodeGenerator::FieldName(name).c_str());
|
||||
}
|
||||
}
|
||||
for (const auto& param : fSectionAndParameterHelper.fParameters) {
|
||||
for (const auto& param : fSectionAndParameterHelper.getParameters()) {
|
||||
const char* name = param->fName.c_str();
|
||||
if (needs_uniform_var(*param)) {
|
||||
this->writef(" UniformHandle %sVar;\n", HCodeGenerator::FieldName(name).c_str());
|
||||
@ -599,7 +595,7 @@ bool CPPCodeGenerator::generateCode() {
|
||||
" const %s& that = other.cast<%s>();\n"
|
||||
" (void) that;\n",
|
||||
fullName, fullName, fullName);
|
||||
for (const auto& param : fSectionAndParameterHelper.fParameters) {
|
||||
for (const auto& param : fSectionAndParameterHelper.getParameters()) {
|
||||
const char* name = param->fName.c_str();
|
||||
this->writef(" if (%s != that.%s) return false;\n",
|
||||
HCodeGenerator::FieldName(name).c_str(),
|
||||
|
@ -69,9 +69,9 @@ void HCodeGenerator::writef(const char* s, ...) {
|
||||
}
|
||||
|
||||
bool HCodeGenerator::writeSection(const char* name, const char* prefix) {
|
||||
const auto found = fSectionAndParameterHelper.fSections.find(String(name));
|
||||
if (found != fSectionAndParameterHelper.fSections.end()) {
|
||||
this->writef("%s%s", prefix, found->second->fText.c_str());
|
||||
const Section* s = fSectionAndParameterHelper.getSection(name);
|
||||
if (s) {
|
||||
this->writef("%s%s", prefix, s->fText.c_str());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@ -81,10 +81,9 @@ void HCodeGenerator::writeExtraConstructorParams(const char* separator) {
|
||||
// super-simple parse, just assume the last token before a comma is the name of a parameter
|
||||
// (which is true as long as there are no multi-parameter template types involved). Will replace
|
||||
// this with something more robust if the need arises.
|
||||
const auto found = fSectionAndParameterHelper.fSections.find(
|
||||
String(CONSTRUCTOR_PARAMS_SECTION));
|
||||
if (found != fSectionAndParameterHelper.fSections.end()) {
|
||||
const char* s = found->second->fText.c_str();
|
||||
const Section* section = fSectionAndParameterHelper.getSection(CONSTRUCTOR_PARAMS_SECTION);
|
||||
if (section) {
|
||||
const char* s = section->fText.c_str();
|
||||
#define BUFFER_SIZE 64
|
||||
char lastIdentifier[BUFFER_SIZE];
|
||||
int lastIdentifierLength = 0;
|
||||
@ -126,7 +125,7 @@ void HCodeGenerator::writeMake() {
|
||||
if (!this->writeSection(MAKE_SECTION)) {
|
||||
this->writef(" static sk_sp<GrFragmentProcessor> Make(");
|
||||
separator = "";
|
||||
for (const auto& param : fSectionAndParameterHelper.fParameters) {
|
||||
for (const auto& param : fSectionAndParameterHelper.getParameters()) {
|
||||
this->writef("%s%s %s", separator, ParameterType(param->fType).c_str(),
|
||||
param->fName.c_str());
|
||||
separator = ", ";
|
||||
@ -136,7 +135,7 @@ void HCodeGenerator::writeMake() {
|
||||
" return sk_sp<GrFragmentProcessor>(new %s(",
|
||||
fFullName.c_str());
|
||||
separator = "";
|
||||
for (const auto& param : fSectionAndParameterHelper.fParameters) {
|
||||
for (const auto& param : fSectionAndParameterHelper.getParameters()) {
|
||||
this->writef("%s%s", separator, param->fName.c_str());
|
||||
separator = ", ";
|
||||
}
|
||||
@ -146,13 +145,25 @@ void HCodeGenerator::writeMake() {
|
||||
}
|
||||
}
|
||||
|
||||
void HCodeGenerator::failOnSection(const char* section, const char* msg) {
|
||||
std::vector<const Section*> s = fSectionAndParameterHelper.getSections(section);
|
||||
if (s.size()) {
|
||||
fErrors.error(s[0]->fPosition, String("@") + section + " " + msg);
|
||||
}
|
||||
}
|
||||
|
||||
void HCodeGenerator::writeConstructor() {
|
||||
if (this->writeSection(CONSTRUCTOR_SECTION)) {
|
||||
return;
|
||||
const char* msg = "may not be present when constructor is overridden";
|
||||
this->failOnSection(CONSTRUCTOR_CODE_SECTION, msg);
|
||||
this->failOnSection(CONSTRUCTOR_PARAMS_SECTION, msg);
|
||||
this->failOnSection(COORD_TRANSFORM_SECTION, msg);
|
||||
this->failOnSection(INITIALIZERS_SECTION, msg);
|
||||
this->failOnSection(OPTIMIZATION_FLAGS_SECTION, msg);
|
||||
}
|
||||
this->writef(" %s(", fFullName.c_str());
|
||||
const char* separator = "";
|
||||
for (const auto& param : fSectionAndParameterHelper.fParameters) {
|
||||
for (const auto& param : fSectionAndParameterHelper.getParameters()) {
|
||||
this->writef("%s%s %s", separator, ParameterType(param->fType).c_str(),
|
||||
param->fName.c_str());
|
||||
separator = ", ";
|
||||
@ -165,23 +176,38 @@ void HCodeGenerator::writeConstructor() {
|
||||
}
|
||||
this->writef(")");
|
||||
this->writeSection(INITIALIZERS_SECTION, "\n , ");
|
||||
for (const auto& param : fSectionAndParameterHelper.fParameters) {
|
||||
for (const auto& param : fSectionAndParameterHelper.getParameters()) {
|
||||
const char* name = param->fName.c_str();
|
||||
if (param->fType.kind() == Type::kSampler_Kind) {
|
||||
this->writef("\n , %s(std::move(%s))", FieldName(name).c_str(),
|
||||
name);
|
||||
this->writef("\n , %s(std::move(%s)", FieldName(name).c_str(), name);
|
||||
for (const Section* s : fSectionAndParameterHelper.getSections(
|
||||
SAMPLER_PARAMS_SECTION)) {
|
||||
if (s->fArgument == name) {
|
||||
this->writef(", %s", s->fText.c_str());
|
||||
}
|
||||
}
|
||||
this->writef(")");
|
||||
} else {
|
||||
this->writef("\n , %s(%s)", FieldName(name).c_str(), name);
|
||||
}
|
||||
}
|
||||
for (const Section* s : fSectionAndParameterHelper.getSections(COORD_TRANSFORM_SECTION)) {
|
||||
String field = FieldName(s->fArgument.c_str());
|
||||
this->writef("\n , %sCoordTransform(%s, %s.proxy())", field.c_str(), s->fText.c_str(),
|
||||
field.c_str());
|
||||
}
|
||||
this->writef(" {\n");
|
||||
this->writeSection(CONSTRUCTOR_CODE_SECTION);
|
||||
for (const auto& param : fSectionAndParameterHelper.fParameters) {
|
||||
for (const auto& param : fSectionAndParameterHelper.getParameters()) {
|
||||
if (param->fType.kind() == Type::kSampler_Kind) {
|
||||
this->writef(" this->addTextureSampler(&%s);\n",
|
||||
FieldName(param->fName.c_str()).c_str());
|
||||
}
|
||||
}
|
||||
for (const Section* s : fSectionAndParameterHelper.getSections(COORD_TRANSFORM_SECTION)) {
|
||||
String field = FieldName(s->fArgument.c_str());
|
||||
this->writef(" this->addCoordTransform(&%sCoordTransform);\n", field.c_str());
|
||||
}
|
||||
this->writef(" this->initClassID<%s>();\n"
|
||||
" }\n",
|
||||
fFullName.c_str());
|
||||
@ -189,10 +215,14 @@ void HCodeGenerator::writeConstructor() {
|
||||
|
||||
void HCodeGenerator::writeFields() {
|
||||
this->writeSection(FIELDS_SECTION);
|
||||
for (const auto& param : fSectionAndParameterHelper.fParameters) {
|
||||
for (const auto& param : fSectionAndParameterHelper.getParameters()) {
|
||||
const char* name = param->fName.c_str();
|
||||
this->writef(" %s %s;\n", FieldType(param->fType).c_str(), FieldName(name).c_str());
|
||||
}
|
||||
for (const Section* s : fSectionAndParameterHelper.getSections(COORD_TRANSFORM_SECTION)) {
|
||||
this->writef(" GrCoordTransform %sCoordTransform;\n",
|
||||
FieldName(s->fArgument.c_str()).c_str());
|
||||
}
|
||||
}
|
||||
|
||||
bool HCodeGenerator::generateCode() {
|
||||
@ -206,12 +236,13 @@ bool HCodeGenerator::generateCode() {
|
||||
this->writeSection(HEADER_SECTION);
|
||||
this->writef("#include \"GrFragmentProcessor.h\"\n"
|
||||
"#include \"GrCoordTransform.h\"\n"
|
||||
"#include \"GrColorSpaceXform.h\"\n"
|
||||
"#include \"effects/GrProxyMove.h\"\n");
|
||||
this->writef("class %s : public GrFragmentProcessor {\n"
|
||||
"public:\n",
|
||||
fFullName.c_str());
|
||||
this->writeSection(CLASS_SECTION);
|
||||
for (const auto& param : fSectionAndParameterHelper.fParameters) {
|
||||
for (const auto& param : fSectionAndParameterHelper.getParameters()) {
|
||||
if (param->fType.kind() == Type::kSampler_Kind) {
|
||||
continue;
|
||||
}
|
||||
|
@ -61,6 +61,8 @@ private:
|
||||
|
||||
void writeFields();
|
||||
|
||||
void failOnSection(const char* section, const char* msg);
|
||||
|
||||
String fName;
|
||||
String fFullName;
|
||||
SectionAndParameterHelper fSectionAndParameterHelper;
|
||||
|
@ -18,18 +18,20 @@
|
||||
namespace SkSL {
|
||||
|
||||
#define CLASS_SECTION "class"
|
||||
#define CONSTRUCTOR_SECTION "constructor"
|
||||
#define CONSTRUCTOR_CODE_SECTION "constructorCode"
|
||||
#define CONSTRUCTOR_PARAMS_SECTION "constructorParams"
|
||||
#define COORD_TRANSFORM_SECTION "coordTransform"
|
||||
#define CPP_SECTION "cpp"
|
||||
#define CPP_END_SECTION "cppEnd"
|
||||
#define HEADER_SECTION "header"
|
||||
#define HEADER_END_SECTION "headerEnd"
|
||||
#define CONSTRUCTOR_PARAMS_SECTION "constructorParams"
|
||||
#define CONSTRUCTOR_SECTION "constructor"
|
||||
#define CONSTRUCTOR_CODE_SECTION "constructorCode"
|
||||
#define INITIALIZERS_SECTION "initializers"
|
||||
#define EMIT_CODE_SECTION "emitCode"
|
||||
#define FIELDS_SECTION "fields"
|
||||
#define INITIALIZERS_SECTION "initializers"
|
||||
#define MAKE_SECTION "make"
|
||||
#define OPTIMIZATION_FLAGS_SECTION "optimizationFlags"
|
||||
#define SAMPLER_PARAMS_SECTION "samplerParams"
|
||||
#define SET_DATA_SECTION "setData"
|
||||
#define TEST_CODE_SECTION "test"
|
||||
|
||||
@ -65,11 +67,12 @@ public:
|
||||
errors.error(s->fPosition,
|
||||
("unsupported section '@" + s->fName + "'").c_str());
|
||||
}
|
||||
if (fSections.find(s->fName) != fSections.end()) {
|
||||
if (!SectionPermitsDuplicates(s->fName.c_str()) &&
|
||||
fSections.find(s->fName) != fSections.end()) {
|
||||
errors.error(s->fPosition,
|
||||
("duplicate section '@" + s->fName + "'").c_str());
|
||||
}
|
||||
fSections[s->fName] = s;
|
||||
fSections[s->fName].push_back(s);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@ -78,6 +81,28 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
const Section* getSection(const char* name) {
|
||||
ASSERT(!SectionPermitsDuplicates(name));
|
||||
auto found = fSections.find(name);
|
||||
if (found == fSections.end()) {
|
||||
return nullptr;
|
||||
}
|
||||
ASSERT(found->second.size() == 1);
|
||||
return found->second[0];
|
||||
}
|
||||
|
||||
std::vector<const Section*> getSections(const char* name) {
|
||||
auto found = fSections.find(name);
|
||||
if (found == fSections.end()) {
|
||||
return { };
|
||||
}
|
||||
return found->second;
|
||||
}
|
||||
|
||||
const std::vector<const Variable*>& getParameters() {
|
||||
return fParameters;
|
||||
}
|
||||
|
||||
static bool IsParameter(const Variable& var) {
|
||||
return (var.fModifiers.fFlags & Modifiers::kIn_Flag) &&
|
||||
-1 == var.fModifiers.fLayout.fBuiltin;
|
||||
@ -85,29 +110,39 @@ public:
|
||||
|
||||
static bool IsSupportedSection(const char* name) {
|
||||
return !strcmp(name, CLASS_SECTION) ||
|
||||
!strcmp(name, CPP_SECTION) ||
|
||||
!strcmp(name, CPP_END_SECTION) ||
|
||||
!strcmp(name, HEADER_SECTION) ||
|
||||
!strcmp(name, HEADER_END_SECTION) ||
|
||||
!strcmp(name, CONSTRUCTOR_SECTION) ||
|
||||
!strcmp(name, CONSTRUCTOR_CODE_SECTION) ||
|
||||
!strcmp(name, CONSTRUCTOR_PARAMS_SECTION) ||
|
||||
!strcmp(name, COORD_TRANSFORM_SECTION) ||
|
||||
!strcmp(name, CPP_SECTION) ||
|
||||
!strcmp(name, CPP_END_SECTION) ||
|
||||
!strcmp(name, EMIT_CODE_SECTION) ||
|
||||
!strcmp(name, FIELDS_SECTION) ||
|
||||
!strcmp(name, HEADER_SECTION) ||
|
||||
!strcmp(name, HEADER_END_SECTION) ||
|
||||
!strcmp(name, INITIALIZERS_SECTION) ||
|
||||
!strcmp(name, MAKE_SECTION) ||
|
||||
!strcmp(name, OPTIMIZATION_FLAGS_SECTION) ||
|
||||
!strcmp(name, SAMPLER_PARAMS_SECTION) ||
|
||||
!strcmp(name, SET_DATA_SECTION) ||
|
||||
!strcmp(name, TEST_CODE_SECTION);
|
||||
}
|
||||
|
||||
static bool SectionAcceptsArgument(const char* name) {
|
||||
return !strcmp(name, SET_DATA_SECTION) ||
|
||||
return !strcmp(name, COORD_TRANSFORM_SECTION) ||
|
||||
!strcmp(name, SAMPLER_PARAMS_SECTION) ||
|
||||
!strcmp(name, SET_DATA_SECTION) ||
|
||||
!strcmp(name, TEST_CODE_SECTION);
|
||||
}
|
||||
|
||||
static bool SectionPermitsDuplicates(const char* name) {
|
||||
return !strcmp(name, COORD_TRANSFORM_SECTION) ||
|
||||
!strcmp(name, SAMPLER_PARAMS_SECTION);
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<const Variable*> fParameters;
|
||||
std::unordered_map<String, const Section*> fSections;
|
||||
std::unordered_map<String, std::vector<const Section*>> fSections;
|
||||
};
|
||||
|
||||
} // namespace SkSL
|
||||
|
@ -82,6 +82,7 @@ DEF_TEST(SkSLFPHelloWorld, r) {
|
||||
"#if SK_SUPPORT_GPU\n"
|
||||
"#include \"GrFragmentProcessor.h\"\n"
|
||||
"#include \"GrCoordTransform.h\"\n"
|
||||
"#include \"GrColorSpaceXform.h\"\n"
|
||||
"#include \"effects/GrProxyMove.h\"\n"
|
||||
"class GrTest : public GrFragmentProcessor {\n"
|
||||
"public:\n"
|
||||
|
Loading…
Reference in New Issue
Block a user