aboutsummaryrefslogtreecommitdiffhomepage
path: root/tests
diff options
context:
space:
mode:
authorGravatar Chris Dalton <csmartdalton@google.com>2017-05-31 12:51:23 -0600
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2017-05-31 20:40:20 +0000
commit1d6163577c8a4f1372208e2c9e03b1a69906d385 (patch)
treefdacaa2e860d507bafca16cef0cb6e6e7861a1aa /tests
parentfa6d865215b48fac4ee24c120736e500d418f641 (diff)
Add support for instanced draws
Adds an instance buffer to GrMesh and instance attribs to GrPrimitiveProcessor. Implements support in GL and Vulkan. Adds unit tests for instanced rendering with GrMesh. Bug: skia: Change-Id: If1a9920feb9366f346b8c37cf914713c49129b3a Reviewed-on: https://skia-review.googlesource.com/16200 Reviewed-by: Brian Salomon <bsalomon@google.com> Commit-Queue: Chris Dalton <csmartdalton@google.com>
Diffstat (limited to 'tests')
-rw-r--r--tests/GrMeshTest.cpp99
-rw-r--r--tests/PrimitiveProcessorTest.cpp2
2 files changed, 90 insertions, 11 deletions
diff --git a/tests/GrMeshTest.cpp b/tests/GrMeshTest.cpp
index e8e3aeb36f..3a2be784a5 100644
--- a/tests/GrMeshTest.cpp
+++ b/tests/GrMeshTest.cpp
@@ -23,6 +23,7 @@
#include "glsl/GrGLSLGeometryProcessor.h"
#include "glsl/GrGLSLVarying.h"
#include <array>
+#include <vector>
GR_DECLARE_STATIC_UNIQUE_KEY(gIndexBufferKey);
@@ -48,6 +49,9 @@ public:
template<typename T> sk_sp<const GrBuffer> makeVertexBuffer(const SkTArray<T>& data) {
return this->makeVertexBuffer(data.begin(), data.count());
}
+ template<typename T> sk_sp<const GrBuffer> makeVertexBuffer(const std::vector<T>& data) {
+ return this->makeVertexBuffer(data.data(), data.size());
+ }
template<typename T> sk_sp<const GrBuffer> makeVertexBuffer(const T* data, int count);
void drawMesh(const GrMesh& mesh);
@@ -144,7 +148,7 @@ DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrMeshTest, reporter, ctxInfo) {
VALIDATE(vbuff);
for (int y = 0; y < kBoxCountY; ++y) {
GrMesh mesh(kTriangles_GrPrimitiveType);
- mesh.setNonIndexed(kBoxCountX * 6);
+ mesh.setNonIndexedNonInstanced(kBoxCountX * 6);
mesh.setVertexData(vbuff.get(), y * kBoxCountX * 6);
helper->drawMesh(mesh);
}
@@ -189,6 +193,55 @@ DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrMeshTest, reporter, ctxInfo) {
helper->drawMesh(mesh);
}
});
+
+ for (bool indexed : {false, true}) {
+ if (!context->caps()->instanceAttribSupport()) {
+ break;
+ }
+
+ run_test(indexed ? "setIndexedInstanced" : "setInstanced",
+ reporter, rtc, gold, [&](DrawMeshHelper* helper) {
+ auto idxbuff = indexed ? helper->getIndexBuffer() : nullptr;
+ auto instbuff = helper->makeVertexBuffer(boxes);
+ VALIDATE(instbuff);
+ auto vbuff = helper->makeVertexBuffer(std::vector<float>{0,0, 0,1, 1,0, 1,1});
+ VALIDATE(vbuff);
+ auto vbuff2 = helper->makeVertexBuffer( // for testing base vertex.
+ std::vector<float>{-1,-1, -1,-1, 0,0, 0,1, 1,0, 1,1});
+ VALIDATE(vbuff2);
+
+ // Draw boxes one line at a time to exercise base instance, base vertex, and null vertex
+ // buffer. setIndexedInstanced intentionally does not support a base index.
+ for (int y = 0; y < kBoxCountY; ++y) {
+ GrMesh mesh(indexed ? kTriangles_GrPrimitiveType : kTriangleStrip_GrPrimitiveType);
+ if (indexed) {
+ VALIDATE(idxbuff);
+ mesh.setIndexedInstanced(idxbuff.get(), 6,
+ instbuff.get(), kBoxCountX, y * kBoxCountX);
+ } else {
+ mesh.setInstanced(instbuff.get(), kBoxCountX, y * kBoxCountX, 4);
+ }
+ switch (y % 3) {
+ case 0:
+ if (context->caps()->shaderCaps()->vertexIDSupport()) {
+ if (y % 2) {
+ // We don't need this call because it's the initial state of GrMesh.
+ mesh.setVertexData(nullptr);
+ }
+ break;
+ }
+ // Fallthru.
+ case 1:
+ mesh.setVertexData(vbuff.get());
+ break;
+ case 2:
+ mesh.setVertexData(vbuff2.get(), 2);
+ break;
+ }
+ helper->drawMesh(mesh);
+ }
+ });
+ }
}
////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -222,21 +275,36 @@ private:
class GrMeshTestProcessor : public GrGeometryProcessor {
public:
- GrMeshTestProcessor()
- : fVertex(this->addVertexAttrib("vertex", kVec2f_GrVertexAttribType))
- , fColor(this->addVertexAttrib("color", kVec4ub_GrVertexAttribType)) {
+ GrMeshTestProcessor(bool instanced, bool hasVertexBuffer)
+ : fInstanceLocation(nullptr)
+ , fVertex(nullptr)
+ , fColor(nullptr) {
+ if (instanced) {
+ fInstanceLocation = &this->addInstanceAttrib("location", kVec2f_GrVertexAttribType);
+ if (hasVertexBuffer) {
+ fVertex = &this->addVertexAttrib("vertex", kVec2f_GrVertexAttribType);
+ }
+ fColor = &this->addInstanceAttrib("color", kVec4ub_GrVertexAttribType);
+ } else {
+ fVertex = &this->addVertexAttrib("vertex", kVec2f_GrVertexAttribType);
+ fColor = &this->addVertexAttrib("color", kVec4ub_GrVertexAttribType);
+ }
this->initClassID<GrMeshTestProcessor>();
}
const char* name() const override { return "GrMeshTest Processor"; }
- void getGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const final {}
+ void getGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder* b) const final {
+ b->add32(SkToBool(fInstanceLocation));
+ b->add32(SkToBool(fVertex));
+ }
GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const final;
protected:
- const Attribute& fVertex;
- const Attribute& fColor;
+ const Attribute* fInstanceLocation;
+ const Attribute* fVertex;
+ const Attribute* fColor;
friend class GLSLMeshTestProcessor;
typedef GrGeometryProcessor INHERITED;
@@ -251,10 +319,20 @@ class GLSLMeshTestProcessor : public GrGLSLGeometryProcessor {
GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
varyingHandler->emitAttributes(mp);
- varyingHandler->addPassThroughAttribute(&mp.fColor, args.fOutputColor);
+ varyingHandler->addPassThroughAttribute(mp.fColor, args.fOutputColor);
GrGLSLVertexBuilder* v = args.fVertBuilder;
- v->codeAppendf("vec2 vertex = %s;", mp.fVertex.fName);
+ if (!mp.fInstanceLocation) {
+ v->codeAppendf("vec2 vertex = %s;", mp.fVertex->fName);
+ } else {
+ if (mp.fVertex) {
+ v->codeAppendf("vec2 offset = %s;", mp.fVertex->fName);
+ } else {
+ v->codeAppend ("vec2 offset = vec2(sk_VertexID / 2, sk_VertexID % 2);");
+ }
+ v->codeAppendf("vec2 vertex = %s + offset * %i;",
+ mp.fInstanceLocation->fName, kBoxSize);
+ }
gpArgs->fPositionVar.set(kVec2f_GrSLType, "vertex");
GrGLSLPPFragmentBuilder* f = args.fFragBuilder;
@@ -287,7 +365,8 @@ sk_sp<const GrBuffer> DrawMeshHelper::getIndexBuffer() {
void DrawMeshHelper::drawMesh(const GrMesh& mesh) {
GrRenderTarget* rt = fState->drawOpArgs().fRenderTarget;
GrPipeline pipeline(rt, SkBlendMode::kSrc);
- fState->commandBuffer()->draw(pipeline, GrMeshTestProcessor(), &mesh, 1,
+ GrMeshTestProcessor mtp(mesh.isInstanced(), mesh.hasVertexData());
+ fState->commandBuffer()->draw(pipeline, mtp, &mesh, 1,
SkRect::MakeIWH(kImageWidth, kImageHeight));
}
diff --git a/tests/PrimitiveProcessorTest.cpp b/tests/PrimitiveProcessorTest.cpp
index 6afc3acec8..66b96f7b93 100644
--- a/tests/PrimitiveProcessorTest.cpp
+++ b/tests/PrimitiveProcessorTest.cpp
@@ -69,7 +69,7 @@ private:
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);
+ this->setupPosition(args.fVertBuilder, gpArgs, gp.getAttrib(0).fName);
GrGLSLPPFragmentBuilder* fragBuilder = args.fFragBuilder;
fragBuilder->codeAppendf("%s = vec4(1);", args.fOutputColor);
fragBuilder->codeAppendf("%s = vec4(1);", args.fOutputCoverage);