2016-03-23 18:50:26 +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.
|
|
|
|
*/
|
|
|
|
|
|
|
|
// This is a GPU-backend specific test. It relies on static intializers to work
|
|
|
|
|
2019-04-23 17:05:21 +00:00
|
|
|
#include "include/core/SkTypes.h"
|
|
|
|
#include "tests/Test.h"
|
2016-03-23 18:50:26 +00:00
|
|
|
|
2019-04-23 17:05:21 +00:00
|
|
|
#include "include/core/SkString.h"
|
|
|
|
#include "include/gpu/GrContext.h"
|
|
|
|
#include "src/core/SkPointPriv.h"
|
|
|
|
#include "src/gpu/GrContextPriv.h"
|
|
|
|
#include "src/gpu/GrGeometryProcessor.h"
|
|
|
|
#include "src/gpu/GrGpu.h"
|
|
|
|
#include "src/gpu/GrMemoryPool.h"
|
|
|
|
#include "src/gpu/GrOpFlushState.h"
|
|
|
|
#include "src/gpu/GrRenderTargetContext.h"
|
|
|
|
#include "src/gpu/GrRenderTargetContextPriv.h"
|
|
|
|
#include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
|
|
|
|
#include "src/gpu/glsl/GrGLSLGeometryProcessor.h"
|
|
|
|
#include "src/gpu/glsl/GrGLSLVarying.h"
|
|
|
|
#include "src/gpu/ops/GrMeshDrawOp.h"
|
2016-03-23 18:50:26 +00:00
|
|
|
|
|
|
|
namespace {
|
2017-07-13 19:29:47 +00:00
|
|
|
class Op : public GrMeshDrawOp {
|
2016-03-23 18:50:26 +00:00
|
|
|
public:
|
2016-12-01 14:36:50 +00:00
|
|
|
DEFINE_OP_CLASS_ID
|
2016-03-23 18:50:26 +00:00
|
|
|
|
2016-12-21 16:14:46 +00:00
|
|
|
const char* name() const override { return "Dummy Op"; }
|
2016-03-23 18:50:26 +00:00
|
|
|
|
2018-06-12 14:11:12 +00:00
|
|
|
static std::unique_ptr<GrDrawOp> Make(GrContext* context, int numAttribs) {
|
2019-02-04 18:26:26 +00:00
|
|
|
GrOpMemoryPool* pool = context->priv().opMemoryPool();
|
2018-06-19 17:09:54 +00:00
|
|
|
|
|
|
|
return pool->allocate<Op>(numAttribs);
|
2017-07-13 19:29:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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();
|
2017-01-03 14:42:58 +00:00
|
|
|
}
|
2016-12-21 16:14:46 +00:00
|
|
|
|
|
|
|
private:
|
2018-06-12 14:11:12 +00:00
|
|
|
friend class ::GrOpMemoryPool;
|
|
|
|
|
2016-12-21 16:14:46 +00:00
|
|
|
Op(int numAttribs) : INHERITED(ClassID()), fNumAttribs(numAttribs) {
|
2016-07-08 13:40:56 +00:00
|
|
|
this->setBounds(SkRect::MakeWH(1.f, 1.f), HasAABloat::kNo, IsZeroArea::kNo);
|
2016-03-23 18:50:26 +00:00
|
|
|
}
|
|
|
|
|
2017-08-09 20:02:19 +00:00
|
|
|
void onPrepareDraws(Target* target) override {
|
2016-03-23 18:50:26 +00:00
|
|
|
class GP : public GrGeometryProcessor {
|
|
|
|
public:
|
2018-06-19 18:33:47 +00:00
|
|
|
GP(int numAttribs) : INHERITED(kGP_ClassID), fNumAttribs(numAttribs) {
|
2016-03-23 18:50:26 +00:00
|
|
|
SkASSERT(numAttribs > 1);
|
2018-06-19 18:33:47 +00:00
|
|
|
fAttribNames.reset(new SkString[numAttribs]);
|
|
|
|
fAttributes.reset(new Attribute[numAttribs]);
|
2016-03-23 18:50:26 +00:00
|
|
|
for (auto i = 0; i < numAttribs; ++i) {
|
2018-06-19 18:33:47 +00:00
|
|
|
fAttribNames[i].printf("attr%d", i);
|
2019-03-15 19:22:39 +00:00
|
|
|
// This gives us more of a mix of attribute types, and allows the
|
|
|
|
// component count to fit within the limits for iOS Metal.
|
|
|
|
if (i & 0x1) {
|
|
|
|
fAttributes[i] = {fAttribNames[i].c_str(), kFloat_GrVertexAttribType,
|
|
|
|
kFloat_GrSLType};
|
|
|
|
} else {
|
|
|
|
fAttributes[i] = {fAttribNames[i].c_str(), kFloat2_GrVertexAttribType,
|
|
|
|
kFloat2_GrSLType};
|
|
|
|
}
|
2016-03-23 18:50:26 +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(fAttributes.get(), numAttribs);
|
2016-09-27 13:34:10 +00:00
|
|
|
}
|
2016-03-23 18:50:26 +00:00
|
|
|
const char* name() const override { return "Dummy GP"; }
|
|
|
|
|
2016-11-29 18:43:05 +00:00
|
|
|
GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const override {
|
2016-03-23 18:50:26 +00:00
|
|
|
class GLSLGP : public GrGLSLGeometryProcessor {
|
|
|
|
public:
|
|
|
|
void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override {
|
|
|
|
const GP& gp = args.fGP.cast<GP>();
|
|
|
|
args.fVaryingHandler->emitAttributes(gp);
|
2018-05-29 19:33:06 +00:00
|
|
|
this->writeOutputPosition(args.fVertBuilder, gpArgs,
|
2018-06-19 18:33:47 +00:00
|
|
|
gp.fAttributes[0].name());
|
2018-02-14 20:38:14 +00:00
|
|
|
GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
|
2017-09-18 18:10:39 +00:00
|
|
|
fragBuilder->codeAppendf("%s = half4(1);", args.fOutputColor);
|
|
|
|
fragBuilder->codeAppendf("%s = half4(1);", args.fOutputCoverage);
|
2016-03-23 18:50:26 +00:00
|
|
|
}
|
|
|
|
void setData(const GrGLSLProgramDataManager& pdman,
|
2016-09-20 16:12:47 +00:00
|
|
|
const GrPrimitiveProcessor& primProc,
|
|
|
|
FPCoordTransformIter&&) override {}
|
2016-03-23 18:50:26 +00:00
|
|
|
};
|
|
|
|
return new GLSLGP();
|
|
|
|
}
|
2016-11-29 18:43:05 +00:00
|
|
|
void getGLSLProcessorKey(const GrShaderCaps&,
|
2016-03-23 18:50:26 +00:00
|
|
|
GrProcessorKeyBuilder* builder) const override {
|
2018-06-19 18:33:47 +00:00
|
|
|
builder->add32(fNumAttribs);
|
2016-03-23 18:50:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
2018-06-19 18:33:47 +00:00
|
|
|
int fNumAttribs;
|
|
|
|
std::unique_ptr<SkString[]> fAttribNames;
|
|
|
|
std::unique_ptr<Attribute[]> fAttributes;
|
2017-10-09 14:54:08 +00:00
|
|
|
|
|
|
|
typedef GrGeometryProcessor INHERITED;
|
2016-03-23 18:50:26 +00:00
|
|
|
};
|
2016-11-04 15:49:42 +00:00
|
|
|
sk_sp<GrGeometryProcessor> gp(new GP(fNumAttribs));
|
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-08-07 14:02:38 +00:00
|
|
|
QuadHelper helper(target, vertexStride, 1);
|
|
|
|
SkPoint* vertices = reinterpret_cast<SkPoint*>(helper.vertices());
|
2017-11-07 01:02:02 +00:00
|
|
|
SkPointPriv::SetRectTriStrip(vertices, 0.f, 0.f, 1.f, 1.f, vertexStride);
|
2019-02-26 18:13:22 +00:00
|
|
|
helper.recordDraw(target, std::move(gp));
|
|
|
|
}
|
|
|
|
|
|
|
|
void onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) override {
|
|
|
|
flushState->executeDrawsAndUploadsForMeshDrawOp(
|
|
|
|
this, chainBounds, GrProcessorSet::MakeEmptySet());
|
2016-03-23 18:50:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int fNumAttribs;
|
|
|
|
|
2017-07-13 19:29:47 +00:00
|
|
|
typedef GrMeshDrawOp INHERITED;
|
2016-03-23 18:50:26 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2016-06-27 14:15:20 +00:00
|
|
|
DEF_GPUTEST_FOR_ALL_CONTEXTS(VertexAttributeCount, reporter, ctxInfo) {
|
2016-05-11 13:33:06 +00:00
|
|
|
GrContext* context = ctxInfo.grContext();
|
2018-01-22 15:48:15 +00:00
|
|
|
#if GR_GPU_STATS
|
2019-02-04 18:26:26 +00:00
|
|
|
GrGpu* gpu = context->priv().getGpu();
|
2018-01-22 15:48:15 +00:00
|
|
|
#endif
|
2016-04-28 16:55:15 +00:00
|
|
|
|
2018-03-06 13:20:37 +00:00
|
|
|
sk_sp<GrRenderTargetContext> renderTargetContext(
|
2019-07-03 15:27:44 +00:00
|
|
|
context->priv().makeDeferredRenderTargetContext(SkBackingFit::kApprox, 1, 1,
|
2019-06-24 19:50:07 +00:00
|
|
|
GrColorType::kRGBA_8888, nullptr));
|
2016-10-27 18:47:55 +00:00
|
|
|
if (!renderTargetContext) {
|
|
|
|
ERRORF(reporter, "Could not create render target context.");
|
2016-03-23 18:50:26 +00:00
|
|
|
return;
|
|
|
|
}
|
2019-02-04 18:26:26 +00:00
|
|
|
int attribCnt = context->priv().caps()->maxVertexAttributes();
|
2016-03-23 18:50:26 +00:00
|
|
|
if (!attribCnt) {
|
|
|
|
ERRORF(reporter, "No attributes allowed?!");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
context->flush();
|
2019-02-04 18:26:26 +00:00
|
|
|
context->priv().resetGpuStats();
|
2016-03-23 18:50:26 +00:00
|
|
|
#if GR_GPU_STATS
|
2018-01-22 15:48:15 +00:00
|
|
|
REPORTER_ASSERT(reporter, gpu->stats()->numDraws() == 0);
|
|
|
|
REPORTER_ASSERT(reporter, gpu->stats()->numFailedDraws() == 0);
|
2016-03-23 18:50:26 +00:00
|
|
|
#endif
|
2018-02-27 19:26:32 +00:00
|
|
|
// Adding discard to appease vulkan validation warning about loading uninitialized data on draw
|
|
|
|
renderTargetContext->discard();
|
|
|
|
|
2016-06-23 21:07:00 +00:00
|
|
|
GrPaint grPaint;
|
2016-03-23 18:50:26 +00:00
|
|
|
// This one should succeed.
|
2018-06-12 14:11:12 +00:00
|
|
|
renderTargetContext->priv().testingOnly_addDrawOp(Op::Make(context, attribCnt));
|
2016-03-23 18:50:26 +00:00
|
|
|
context->flush();
|
|
|
|
#if GR_GPU_STATS
|
2018-01-22 15:48:15 +00:00
|
|
|
REPORTER_ASSERT(reporter, gpu->stats()->numDraws() == 1);
|
|
|
|
REPORTER_ASSERT(reporter, gpu->stats()->numFailedDraws() == 0);
|
2016-03-23 18:50:26 +00:00
|
|
|
#endif
|
2019-02-04 18:26:26 +00:00
|
|
|
context->priv().resetGpuStats();
|
2018-06-12 14:11:12 +00:00
|
|
|
renderTargetContext->priv().testingOnly_addDrawOp(Op::Make(context, attribCnt + 1));
|
2016-03-23 18:50:26 +00:00
|
|
|
context->flush();
|
|
|
|
#if GR_GPU_STATS
|
2018-01-22 15:48:15 +00:00
|
|
|
REPORTER_ASSERT(reporter, gpu->stats()->numDraws() == 0);
|
|
|
|
REPORTER_ASSERT(reporter, gpu->stats()->numFailedDraws() == 1);
|
2016-03-23 18:50:26 +00:00
|
|
|
#endif
|
|
|
|
}
|