blob: f8c19e31714fe3d57509d281adcfb0b6c8f80b4c [file] [log] [blame]
/*
* 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
#include "SkTypes.h"
#include "Test.h"
#if SK_SUPPORT_GPU
#include "GrBatchFlushState.h"
#include "GrDrawContext.h"
#include "GrDrawContextPriv.h"
#include "GrContext.h"
#include "GrGeometryProcessor.h"
#include "GrGpu.h"
#include "GrTextureProvider.h"
#include "glsl/GrGLSLGeometryProcessor.h"
#include "glsl/GrGLSLVarying.h"
#include "batches/GrVertexBatch.h"
#include "SkString.h"
namespace {
class Batch : public GrVertexBatch {
public:
DEFINE_BATCH_CLASS_ID
const char* name() const override { return "Dummy Batch"; }
void computePipelineOptimizations(GrInitInvariantOutput* color,
GrInitInvariantOutput* coverage,
GrBatchToXPOverrides* overrides) const override {
color->setUnknownFourComponents();
coverage->setUnknownSingleComponent();
}
void initBatchTracker(const GrXPOverridesForBatch& overrides) override {}
Batch(int numAttribs)
: INHERITED(ClassID())
, fNumAttribs(numAttribs) {
this->setBounds(SkRect::MakeWH(1.f, 1.f));
}
private:
bool onCombineIfPossible(GrBatch*, const GrCaps&) override { return false; }
void onPrepareDraws(Target* target) const override {
class GP : public GrGeometryProcessor {
public:
GP(int numAttribs) {
this->initClassID<GP>();
SkASSERT(numAttribs > 1);
for (auto i = 0; i < numAttribs; ++i) {
fAttribNames.push_back().printf("attr%d", i);
}
for (auto i = 0; i < numAttribs; ++i) {
Attribute attribute;
attribute.fType = kVec2f_GrVertexAttribType;
attribute.fName = fAttribNames[i].c_str();
attribute.fOffset = 2 * sizeof(float) * i;
attribute.fPrecision = kDefault_GrSLPrecision;
this->addVertexAttrib(attribute);
}
};
const char* name() const override { return "Dummy GP"; }
GrGLSLPrimitiveProcessor* createGLSLInstance(const GrGLSLCaps&) const override {
class GLSLGP : public GrGLSLGeometryProcessor {
public:
void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override {
const GP& gp = args.fGP.cast<GP>();
args.fVaryingHandler->emitAttributes(gp);
this->setupPosition(args.fVertBuilder, gpArgs, gp.fAttribs[0].fName);
}
void setData(const GrGLSLProgramDataManager& pdman,
const GrPrimitiveProcessor& primProc) override {}
};
return new GLSLGP();
}
void getGLSLProcessorKey(const GrGLSLCaps&,
GrProcessorKeyBuilder* builder) const override {
builder->add32(this->numAttribs());
}
private:
SkTArray<SkString> fAttribNames;
};
SkAutoTUnref<GrGeometryProcessor> gp(new GP(fNumAttribs));
QuadHelper helper;
size_t vertexStride = gp->getVertexStride();
SkPoint* vertices = reinterpret_cast<SkPoint*>(helper.init(target, vertexStride, 1));
vertices->setRectFan(0.f, 0.f, 1.f, 1.f, vertexStride);
helper.recordDraw(target, gp);
}
int fNumAttribs;
typedef GrVertexBatch INHERITED;
};
}
DEF_GPUTEST_FOR_ALL_GL_CONTEXTS(VertexAttributeCount, reporter, ctxInfo) {
GrContext* context = ctxInfo.fGrContext;
GrTextureDesc desc;
desc.fHeight = 1;
desc.fWidth = 1;
desc.fFlags = kRenderTarget_GrSurfaceFlag;
desc.fConfig = kRGBA_8888_GrPixelConfig;
SkAutoTUnref<GrTexture> target(context->textureProvider()->createTexture(desc,
SkBudgeted::kYes));
if (!target) {
ERRORF(reporter, "Could not create render target.");
return;
}
SkAutoTUnref<GrDrawContext> dc(context->drawContext(target->asRenderTarget()));
if (!dc) {
ERRORF(reporter, "Could not create draw context.");
return;
}
int attribCnt = context->caps()->maxVertexAttributes();
if (!attribCnt) {
ERRORF(reporter, "No attributes allowed?!");
return;
}
context->flush();
context->resetGpuStats();
#if GR_GPU_STATS
REPORTER_ASSERT(reporter, context->getGpu()->stats()->numDraws() == 0);
REPORTER_ASSERT(reporter, context->getGpu()->stats()->numFailedDraws() == 0);
#endif
SkAutoTUnref<GrDrawBatch> batch;
GrPipelineBuilder pb;
pb.setRenderTarget(target->asRenderTarget());
// This one should succeed.
batch.reset(new Batch(attribCnt));
dc->drawContextPriv().testingOnly_drawBatch(pb, batch);
context->flush();
#if GR_GPU_STATS
REPORTER_ASSERT(reporter, context->getGpu()->stats()->numDraws() == 1);
REPORTER_ASSERT(reporter, context->getGpu()->stats()->numFailedDraws() == 0);
#endif
context->resetGpuStats();
// This one should fail.
batch.reset(new Batch(attribCnt+1));
dc->drawContextPriv().testingOnly_drawBatch(pb, batch);
context->flush();
#if GR_GPU_STATS
REPORTER_ASSERT(reporter, context->getGpu()->stats()->numDraws() == 0);
REPORTER_ASSERT(reporter, context->getGpu()->stats()->numFailedDraws() == 1);
#endif
}
#endif