2018-07-20 18:50:44 +00:00
|
|
|
/*
|
|
|
|
* Copyright 2016 Google Inc.
|
|
|
|
*
|
|
|
|
* Use of this source code is governed by a BSD-style license that can be
|
|
|
|
* found in the LICENSE file.
|
|
|
|
*/
|
|
|
|
|
2019-04-23 17:05:21 +00:00
|
|
|
#include "bench/Benchmark.h"
|
2018-07-20 18:50:44 +00:00
|
|
|
|
2019-04-23 17:05:21 +00:00
|
|
|
#include "include/core/SkString.h"
|
|
|
|
#include "include/gpu/GrContext.h"
|
|
|
|
#include "include/private/SkHalf.h"
|
|
|
|
#include "src/core/SkColorSpacePriv.h"
|
|
|
|
#include "src/gpu/GrContextPriv.h"
|
|
|
|
#include "src/gpu/GrGeometryProcessor.h"
|
|
|
|
#include "src/gpu/GrMemoryPool.h"
|
|
|
|
#include "src/gpu/GrRenderTargetContext.h"
|
|
|
|
#include "src/gpu/GrRenderTargetContextPriv.h"
|
|
|
|
#include "src/gpu/SkGr.h"
|
|
|
|
#include "src/gpu/glsl/GrGLSLColorSpaceXformHelper.h"
|
|
|
|
#include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
|
|
|
|
#include "src/gpu/glsl/GrGLSLGeometryProcessor.h"
|
|
|
|
#include "src/gpu/glsl/GrGLSLVarying.h"
|
|
|
|
#include "src/gpu/glsl/GrGLSLVertexGeoBuilder.h"
|
|
|
|
#include "src/gpu/ops/GrMeshDrawOp.h"
|
2018-07-20 18:50:44 +00:00
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
enum Mode {
|
|
|
|
kBaseline_Mode, // Do the wrong thing, but quickly.
|
|
|
|
kFloat_Mode, // Transform colors on CPU, use float4 attributes.
|
2018-09-17 15:32:42 +00:00
|
|
|
kHalf_Mode, // Transform colors on CPU, use half4 attributes.
|
2018-07-20 18:50:44 +00:00
|
|
|
kShader_Mode, // Use ubyte4 attributes, transform colors on GPU (vertex shader).
|
|
|
|
};
|
|
|
|
|
|
|
|
class GP : public GrGeometryProcessor {
|
|
|
|
public:
|
|
|
|
GP(Mode mode, sk_sp<GrColorSpaceXform> colorSpaceXform)
|
|
|
|
: INHERITED(kVertexColorSpaceBenchGP_ClassID)
|
|
|
|
, fMode(mode)
|
|
|
|
, fColorSpaceXform(std::move(colorSpaceXform)) {
|
2018-09-14 20:16:55 +00:00
|
|
|
fInPosition = {"inPosition", kFloat2_GrVertexAttribType, kFloat2_GrSLType};
|
2018-09-17 15:32:42 +00:00
|
|
|
switch (fMode) {
|
|
|
|
case kBaseline_Mode:
|
|
|
|
case kShader_Mode:
|
|
|
|
fInColor = {"inColor", kUByte4_norm_GrVertexAttribType, kHalf4_GrSLType};
|
|
|
|
break;
|
|
|
|
case kFloat_Mode:
|
|
|
|
fInColor = {"inColor", kFloat4_GrVertexAttribType, kHalf4_GrSLType};
|
|
|
|
break;
|
|
|
|
case kHalf_Mode:
|
|
|
|
fInColor = {"inColor", kHalf4_GrVertexAttribType, kHalf4_GrSLType};
|
|
|
|
break;
|
2018-07-20 18:50:44 +00:00
|
|
|
}
|
Change how GPs configure attributes
Adds setVertexAttributes and setInstanceAttributes. These take a pointer
to the first attribute, and a count. The count is the total number of
possible attributes, though some may not be initialized. The base class
computes the number of initialized attributes, pre-computes the strides,
and only allows subsequent access to the initialized attributes.
The attributes need to be allocated contiguously. Some GPs place them in
an array, though most just place them as consecutive members, and pass
a pointer to the first one.
Indexed access would be possible, but now it makes more sense to iterate
over all attributes, so enable that, and use range-based for everywhere.
Completely remove the per-attribute offset helper (again - possible, but
not real helpful), and make the stride always available. In many ops,
just use the GP's computed stride, rather than re-computing it.
Bug: skia:
Change-Id: Ie4cccb7969a98ee5a10b373e714fbd702e875b3e
Reviewed-on: https://skia-review.googlesource.com/c/169241
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Brian Osman <brianosman@google.com>
2018-11-12 20:34:00 +00:00
|
|
|
this->setVertexAttributes(&fInPosition, 2);
|
2018-07-20 18:50:44 +00:00
|
|
|
}
|
|
|
|
const char* name() const override { return "VertexColorXformGP"; }
|
|
|
|
|
|
|
|
GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const override {
|
|
|
|
class GLSLGP : public GrGLSLGeometryProcessor {
|
|
|
|
public:
|
|
|
|
void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override {
|
|
|
|
const GP& gp = args.fGP.cast<GP>();
|
|
|
|
GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder;
|
|
|
|
GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
|
|
|
|
GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
|
|
|
|
GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
|
|
|
|
|
|
|
|
varyingHandler->emitAttributes(gp);
|
|
|
|
|
|
|
|
// Setup color
|
|
|
|
GrGLSLVarying varying(kHalf4_GrSLType);
|
|
|
|
varyingHandler->addVarying("color", &varying);
|
|
|
|
vertBuilder->codeAppendf("half4 color = %s;", gp.fInColor.name());
|
|
|
|
|
|
|
|
if (kShader_Mode == gp.fMode) {
|
|
|
|
fColorSpaceHelper.emitCode(uniformHandler, gp.fColorSpaceXform.get(),
|
|
|
|
kVertex_GrShaderFlag);
|
|
|
|
SkString xformedColor;
|
|
|
|
vertBuilder->appendColorGamutXform(&xformedColor, "color", &fColorSpaceHelper);
|
|
|
|
vertBuilder->codeAppendf("color = %s;", xformedColor.c_str());
|
|
|
|
vertBuilder->codeAppend("color = half4(color.rgb * color.a, color.a);");
|
|
|
|
}
|
|
|
|
|
|
|
|
vertBuilder->codeAppendf("%s = color;", varying.vsOut());
|
|
|
|
fragBuilder->codeAppendf("%s = %s;", args.fOutputColor, varying.fsIn());
|
|
|
|
|
|
|
|
// Position
|
|
|
|
this->writeOutputPosition(args.fVertBuilder, gpArgs, gp.fInPosition.name());
|
|
|
|
|
|
|
|
// Coverage
|
|
|
|
fragBuilder->codeAppendf("%s = half4(1);", args.fOutputCoverage);
|
|
|
|
}
|
|
|
|
void setData(const GrGLSLProgramDataManager& pdman,
|
|
|
|
const GrPrimitiveProcessor& primProc,
|
|
|
|
FPCoordTransformIter&&) override {
|
|
|
|
const GP& gp = primProc.cast<GP>();
|
|
|
|
fColorSpaceHelper.setData(pdman, gp.fColorSpaceXform.get());
|
|
|
|
}
|
|
|
|
|
|
|
|
GrGLSLColorSpaceXformHelper fColorSpaceHelper;
|
|
|
|
};
|
|
|
|
return new GLSLGP();
|
|
|
|
}
|
|
|
|
|
|
|
|
void getGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder* b) const override {
|
|
|
|
b->add32(fMode);
|
|
|
|
b->add32(GrColorSpaceXform::XformKey(fColorSpaceXform.get()));
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
Mode fMode;
|
|
|
|
sk_sp<GrColorSpaceXform> fColorSpaceXform;
|
|
|
|
|
|
|
|
Attribute fInPosition;
|
|
|
|
Attribute fInColor;
|
|
|
|
|
|
|
|
typedef GrGeometryProcessor INHERITED;
|
|
|
|
};
|
|
|
|
|
|
|
|
class Op : public GrMeshDrawOp {
|
|
|
|
public:
|
|
|
|
DEFINE_OP_CLASS_ID
|
|
|
|
|
|
|
|
const char* name() const override { return "VertColorXformOp"; }
|
|
|
|
|
|
|
|
Op(GrColor color)
|
|
|
|
: INHERITED(ClassID())
|
|
|
|
, fMode(kBaseline_Mode)
|
|
|
|
, fColor(color) {
|
|
|
|
this->setBounds(SkRect::MakeWH(100.f, 100.f), HasAABloat::kNo, IsZeroArea::kNo);
|
|
|
|
}
|
|
|
|
|
2018-10-16 19:19:28 +00:00
|
|
|
Op(const SkColor4f& color4f, Mode mode)
|
2018-07-20 18:50:44 +00:00
|
|
|
: INHERITED(ClassID())
|
2018-09-17 15:32:42 +00:00
|
|
|
, fMode(mode)
|
2018-07-20 18:50:44 +00:00
|
|
|
, fColor4f(color4f) {
|
2018-10-26 18:57:35 +00:00
|
|
|
SkASSERT(kFloat_Mode == fMode || kHalf_Mode == mode);
|
2018-07-20 18:50:44 +00:00
|
|
|
this->setBounds(SkRect::MakeWH(100.f, 100.f), HasAABloat::kNo, IsZeroArea::kNo);
|
|
|
|
}
|
|
|
|
|
|
|
|
Op(GrColor color, sk_sp<GrColorSpaceXform> colorSpaceXform)
|
|
|
|
: INHERITED(ClassID())
|
|
|
|
, fMode(kShader_Mode)
|
|
|
|
, fColor(color)
|
|
|
|
, fColorSpaceXform(std::move(colorSpaceXform)) {
|
|
|
|
this->setBounds(SkRect::MakeWH(100.f, 100.f), HasAABloat::kNo, IsZeroArea::kNo);
|
|
|
|
}
|
|
|
|
|
|
|
|
FixedFunctionFlags fixedFunctionFlags() const override {
|
|
|
|
return FixedFunctionFlags::kNone;
|
|
|
|
}
|
|
|
|
|
2019-06-24 00:07:38 +00:00
|
|
|
GrProcessorSet::Analysis finalize(const GrCaps&, const GrAppliedClip*,
|
|
|
|
bool hasMixedSampledCoverage, GrClampType) override {
|
2019-01-15 18:53:00 +00:00
|
|
|
return GrProcessorSet::EmptySetAnalysis();
|
2018-07-20 18:50:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
friend class ::GrOpMemoryPool;
|
|
|
|
|
|
|
|
void onPrepareDraws(Target* target) override {
|
|
|
|
sk_sp<GrGeometryProcessor> gp(new GP(fMode, fColorSpaceXform));
|
|
|
|
|
Change how GPs configure attributes
Adds setVertexAttributes and setInstanceAttributes. These take a pointer
to the first attribute, and a count. The count is the total number of
possible attributes, though some may not be initialized. The base class
computes the number of initialized attributes, pre-computes the strides,
and only allows subsequent access to the initialized attributes.
The attributes need to be allocated contiguously. Some GPs place them in
an array, though most just place them as consecutive members, and pass
a pointer to the first one.
Indexed access would be possible, but now it makes more sense to iterate
over all attributes, so enable that, and use range-based for everywhere.
Completely remove the per-attribute offset helper (again - possible, but
not real helpful), and make the stride always available. In many ops,
just use the GP's computed stride, rather than re-computing it.
Bug: skia:
Change-Id: Ie4cccb7969a98ee5a10b373e714fbd702e875b3e
Reviewed-on: https://skia-review.googlesource.com/c/169241
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Brian Osman <brianosman@google.com>
2018-11-12 20:34:00 +00:00
|
|
|
size_t vertexStride = gp->vertexStride();
|
2018-07-20 18:50:44 +00:00
|
|
|
const int kVertexCount = 1024;
|
2019-01-29 19:38:50 +00:00
|
|
|
sk_sp<const GrBuffer> vertexBuffer;
|
2018-07-20 18:50:44 +00:00
|
|
|
int firstVertex = 0;
|
|
|
|
void* verts = target->makeVertexSpace(vertexStride, kVertexCount, &vertexBuffer,
|
|
|
|
&firstVertex);
|
|
|
|
if (!verts) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const float dx = 100.0f / kVertexCount;
|
|
|
|
if (kFloat_Mode == fMode) {
|
|
|
|
struct V {
|
|
|
|
SkPoint fPos;
|
2018-10-16 19:19:28 +00:00
|
|
|
SkColor4f fColor;
|
2018-07-20 18:50:44 +00:00
|
|
|
};
|
|
|
|
SkASSERT(sizeof(V) == vertexStride);
|
|
|
|
V* v = (V*)verts;
|
|
|
|
for (int i = 0; i < kVertexCount; i += 2) {
|
|
|
|
v[i + 0].fPos.set(dx * i, 0.0f);
|
|
|
|
v[i + 0].fColor = fColor4f;
|
|
|
|
v[i + 1].fPos.set(dx * i, 100.0f);
|
|
|
|
v[i + 1].fColor = fColor4f;
|
|
|
|
}
|
2018-09-17 15:32:42 +00:00
|
|
|
} else if (kHalf_Mode == fMode) {
|
|
|
|
struct V {
|
|
|
|
SkPoint fPos;
|
|
|
|
uint64_t fColor;
|
|
|
|
};
|
|
|
|
SkASSERT(sizeof(V) == vertexStride);
|
|
|
|
uint64_t color;
|
2018-09-19 18:19:02 +00:00
|
|
|
Sk4h halfColor = SkFloatToHalf_finite_ftz(Sk4f::Load(&fColor4f));
|
2018-09-17 15:32:42 +00:00
|
|
|
color = (uint64_t)halfColor[0] << 48 |
|
|
|
|
(uint64_t)halfColor[1] << 32 |
|
|
|
|
(uint64_t)halfColor[2] << 16 |
|
|
|
|
(uint64_t)halfColor[3] << 0;
|
|
|
|
V* v = (V*)verts;
|
|
|
|
for (int i = 0; i < kVertexCount; i += 2) {
|
|
|
|
v[i + 0].fPos.set(dx * i, 0.0f);
|
|
|
|
v[i + 0].fColor = color;
|
|
|
|
v[i + 1].fPos.set(dx * i, 100.0f);
|
|
|
|
v[i + 1].fColor = color;
|
|
|
|
}
|
2018-07-20 18:50:44 +00:00
|
|
|
} else {
|
|
|
|
struct V {
|
|
|
|
SkPoint fPos;
|
|
|
|
GrColor fColor;
|
|
|
|
};
|
|
|
|
SkASSERT(sizeof(V) == vertexStride);
|
|
|
|
V* v = (V*)verts;
|
|
|
|
for (int i = 0; i < kVertexCount; i += 2) {
|
|
|
|
v[i + 0].fPos.set(dx * i, 0.0f);
|
|
|
|
v[i + 0].fColor = fColor;
|
|
|
|
v[i + 1].fPos.set(dx * i, 100.0f);
|
|
|
|
v[i + 1].fColor = fColor;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-07 14:02:38 +00:00
|
|
|
GrMesh* mesh = target->allocMesh(GrPrimitiveType::kTriangleStrip);
|
|
|
|
mesh->setNonIndexedNonInstanced(kVertexCount);
|
2019-01-29 19:38:50 +00:00
|
|
|
mesh->setVertexData(std::move(vertexBuffer), firstVertex);
|
2019-02-26 18:13:22 +00:00
|
|
|
target->recordDraw(gp, mesh);
|
|
|
|
}
|
|
|
|
|
|
|
|
void onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) override {
|
|
|
|
flushState->executeDrawsAndUploadsForMeshDrawOp(
|
|
|
|
this, chainBounds, GrProcessorSet::MakeEmptySet());
|
2018-07-20 18:50:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Mode fMode;
|
|
|
|
GrColor fColor;
|
2018-10-16 19:19:28 +00:00
|
|
|
SkColor4f fColor4f;
|
2018-07-20 18:50:44 +00:00
|
|
|
sk_sp<GrColorSpaceXform> fColorSpaceXform;
|
|
|
|
|
|
|
|
typedef GrMeshDrawOp INHERITED;
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
class VertexColorSpaceBench : public Benchmark {
|
|
|
|
public:
|
|
|
|
VertexColorSpaceBench(Mode mode, const char* name) : fMode(mode) {
|
|
|
|
fName = "vertexcolorspace";
|
|
|
|
fName.appendf("_%s", name);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool isSuitableFor(Backend backend) override { return kGPU_Backend == backend; }
|
|
|
|
const char* onGetName() override { return fName.c_str(); }
|
|
|
|
|
|
|
|
void onDraw(int loops, SkCanvas* canvas) override {
|
|
|
|
GrContext* context = canvas->getGrContext();
|
2018-09-17 15:32:42 +00:00
|
|
|
SkASSERT(context);
|
|
|
|
|
|
|
|
if (kHalf_Mode == fMode &&
|
2019-02-04 18:26:26 +00:00
|
|
|
!context->priv().caps()->halfFloatVertexAttributeSupport()) {
|
2018-09-17 15:32:42 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-02-04 18:26:26 +00:00
|
|
|
GrOpMemoryPool* pool = context->priv().opMemoryPool();
|
2018-07-20 18:50:44 +00:00
|
|
|
|
2019-01-04 22:03:00 +00:00
|
|
|
auto p3 = SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB,
|
|
|
|
SkNamedGamut::kDCIP3);
|
2018-08-22 15:52:16 +00:00
|
|
|
auto xform = GrColorSpaceXform::Make(sk_srgb_singleton(), kUnpremul_SkAlphaType,
|
|
|
|
p3.get(), kUnpremul_SkAlphaType);
|
2018-07-20 18:50:44 +00:00
|
|
|
|
|
|
|
SkRandom r;
|
|
|
|
const int kDrawsPerLoop = 32;
|
|
|
|
|
|
|
|
for (int i = 0; i < loops; ++i) {
|
2019-06-24 19:50:07 +00:00
|
|
|
sk_sp<GrRenderTargetContext> rtc(context->priv().makeDeferredRenderTargetContext(
|
2019-07-03 15:27:44 +00:00
|
|
|
SkBackingFit::kApprox, 100, 100, GrColorType::kRGBA_8888, p3));
|
2018-07-20 18:50:44 +00:00
|
|
|
SkASSERT(rtc);
|
|
|
|
|
|
|
|
for (int j = 0; j < kDrawsPerLoop; ++j) {
|
|
|
|
SkColor c = r.nextU();
|
|
|
|
std::unique_ptr<GrDrawOp> op = nullptr;
|
|
|
|
|
|
|
|
switch (fMode) {
|
|
|
|
case kBaseline_Mode:
|
|
|
|
op = pool->allocate<Op>(SkColorToPremulGrColor(c));
|
|
|
|
break;
|
|
|
|
case kShader_Mode:
|
|
|
|
op = pool->allocate<Op>(SkColorToUnpremulGrColor(c), xform);
|
|
|
|
break;
|
2018-09-17 15:32:42 +00:00
|
|
|
case kHalf_Mode:
|
2018-07-20 18:50:44 +00:00
|
|
|
case kFloat_Mode: {
|
2018-10-16 19:19:28 +00:00
|
|
|
SkColor4f c4f = SkColor4f::FromColor(c);
|
2018-07-20 18:50:44 +00:00
|
|
|
c4f = xform->apply(c4f);
|
2018-09-17 15:32:42 +00:00
|
|
|
op = pool->allocate<Op>(c4f, fMode);
|
2018-07-20 18:50:44 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
rtc->priv().testingOnly_addDrawOp(std::move(op));
|
|
|
|
}
|
|
|
|
|
|
|
|
context->flush();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
SkString fName;
|
|
|
|
Mode fMode;
|
|
|
|
|
|
|
|
typedef Benchmark INHERITED;
|
|
|
|
};
|
|
|
|
|
|
|
|
DEF_BENCH(return new VertexColorSpaceBench(kBaseline_Mode, "baseline"));
|
|
|
|
DEF_BENCH(return new VertexColorSpaceBench(kFloat_Mode, "float"));
|
2018-09-17 15:32:42 +00:00
|
|
|
DEF_BENCH(return new VertexColorSpaceBench(kHalf_Mode, "half"));
|
2018-07-20 18:50:44 +00:00
|
|
|
DEF_BENCH(return new VertexColorSpaceBench(kShader_Mode, "shader"));
|