aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--gn/tests.gni1
-rw-r--r--src/gpu/GrCaps.cpp2
-rw-r--r--src/gpu/gl/GrGLCaps.cpp9
-rw-r--r--src/gpu/gl/GrGLCaps.h10
-rw-r--r--src/gpu/gl/GrGLGpu.cpp12
-rw-r--r--tests/GrCCPRTest.cpp101
6 files changed, 131 insertions, 4 deletions
diff --git a/gn/tests.gni b/gn/tests.gni
index 34c10b53f1..a6135ed9c8 100644
--- a/gn/tests.gni
+++ b/gn/tests.gni
@@ -87,6 +87,7 @@ tests_sources = [
"$_tests/GpuSampleLocationsTest.cpp",
"$_tests/GradientTest.cpp",
"$_tests/GrAllocatorTest.cpp",
+ "$_tests/GrCCPRTest.cpp",
"$_tests/GrContextAbandonTest.cpp",
"$_tests/GrContextFactoryTest.cpp",
"$_tests/GrMemoryPoolTest.cpp",
diff --git a/src/gpu/GrCaps.cpp b/src/gpu/GrCaps.cpp
index a0e435a9c3..f4c7de7304 100644
--- a/src/gpu/GrCaps.cpp
+++ b/src/gpu/GrCaps.cpp
@@ -149,6 +149,8 @@ void GrCaps::dumpJSON(SkJSONWriter* writer) const {
writer->appendBool("Cross context texture support", fCrossContextTextureSupport);
writer->appendBool("Draw Instead of Clear [workaround]", fUseDrawInsteadOfClear);
+ writer->appendBool("Blacklist Coverage Counting Path Renderer [workaround]",
+ fBlacklistCoverageCounting);
writer->appendBool("Prefer VRAM Use over flushes [workaround]", fPreferVRAMUseOverFlushes);
if (this->advancedBlendEquationSupport()) {
diff --git a/src/gpu/gl/GrGLCaps.cpp b/src/gpu/gl/GrGLCaps.cpp
index 3b401e65a1..088e5cbbdd 100644
--- a/src/gpu/gl/GrGLCaps.cpp
+++ b/src/gpu/gl/GrGLCaps.cpp
@@ -62,6 +62,7 @@ GrGLCaps::GrGLCaps(const GrContextOptions& contextOptions,
fRequiresCullFaceEnableDisableWhenDrawingLinesAfterNonLines = false;
fBlitFramebufferFlags = kNoSupport_BlitFramebufferFlag;
+ fMaxInstancesPerDrawArraysWithoutCrashing = 0;
fShaderCaps.reset(new GrShaderCaps(contextOptions));
@@ -595,6 +596,12 @@ void GrGLCaps::init(const GrContextOptions& contextOptions,
fRequiresCullFaceEnableDisableWhenDrawingLinesAfterNonLines = true;
}
+ // Our Chromebook with kPowerVRRogue_GrGLRenderer seems to crash when glDrawArraysInstanced is
+ // given 1 << 15 or more instances.
+ if (kPowerVRRogue_GrGLRenderer == ctxInfo.renderer()) {
+ fMaxInstancesPerDrawArraysWithoutCrashing = 0x7fff;
+ }
+
// Texture uploads sometimes seem to be ignored to textures bound to FBOS on Tegra3.
if (kTegra3_GrGLRenderer == ctxInfo.renderer()) {
fDisallowTexSubImageForUnormConfigTexturesEverBoundToFBO = true;
@@ -1374,6 +1381,8 @@ void GrGLCaps::onDumpJSON(SkJSONWriter* writer) const {
fDisallowTexSubImageForUnormConfigTexturesEverBoundToFBO);
writer->appendBool("Intermediate texture for all updates of textures bound to FBOs",
fUseDrawInsteadOfAllRenderTargetWrites);
+ writer->appendBool("Max instances per glDrawArraysInstanced without crashing (or zero)",
+ fMaxInstancesPerDrawArraysWithoutCrashing);
writer->beginArray("configs");
diff --git a/src/gpu/gl/GrGLCaps.h b/src/gpu/gl/GrGLCaps.h
index 68cbc9bf16..5140aeea2f 100644
--- a/src/gpu/gl/GrGLCaps.h
+++ b/src/gpu/gl/GrGLCaps.h
@@ -399,6 +399,15 @@ public:
return fRequiresCullFaceEnableDisableWhenDrawingLinesAfterNonLines;
}
+ // Returns the observed maximum number of instances the driver can handle in a single call to
+ // glDrawArraysInstanced without crashing, or 'pendingInstanceCount' if this
+ // workaround is not necessary.
+ // NOTE: the return value may be larger than pendingInstanceCount.
+ int maxInstancesPerDrawArraysWithoutCrashing(int pendingInstanceCount) const {
+ return fMaxInstancesPerDrawArraysWithoutCrashing ? fMaxInstancesPerDrawArraysWithoutCrashing
+ : pendingInstanceCount;
+ }
+
bool initDescForDstCopy(const GrRenderTargetProxy* src, GrSurfaceDesc* desc,
bool* rectsMustMatch, bool* disallowSubrect) const override;
@@ -479,6 +488,7 @@ private:
bool fRequiresCullFaceEnableDisableWhenDrawingLinesAfterNonLines : 1;
uint32_t fBlitFramebufferFlags;
+ int fMaxInstancesPerDrawArraysWithoutCrashing;
/** Number type of the components (with out considering number of bits.) */
enum FormatType {
diff --git a/src/gpu/gl/GrGLGpu.cpp b/src/gpu/gl/GrGLGpu.cpp
index 8190206d8f..10dabe4629 100644
--- a/src/gpu/gl/GrGLGpu.cpp
+++ b/src/gpu/gl/GrGLGpu.cpp
@@ -2619,10 +2619,14 @@ void GrGLGpu::sendInstancedMeshToGpu(const GrPrimitiveProcessor& primProc, GrPri
int vertexCount, int baseVertex,
const GrBuffer* instanceBuffer, int instanceCount,
int baseInstance) {
- const GrGLenum glPrimType = gr_primitive_type_to_gl_mode(primitiveType);
- this->setupGeometry(primProc, nullptr, vertexBuffer, 0, instanceBuffer, baseInstance);
- GL_CALL(DrawArraysInstanced(glPrimType, baseVertex, vertexCount, instanceCount));
- fStats.incNumDraws();
+ GrGLenum glPrimType = gr_primitive_type_to_gl_mode(primitiveType);
+ int maxInstances = this->glCaps().maxInstancesPerDrawArraysWithoutCrashing(instanceCount);
+ for (int i = 0; i < instanceCount; i += maxInstances) {
+ this->setupGeometry(primProc, nullptr, vertexBuffer, 0, instanceBuffer, baseInstance + i);
+ GL_CALL(DrawArraysInstanced(glPrimType, baseVertex, vertexCount,
+ SkTMin(instanceCount - i, maxInstances)));
+ fStats.incNumDraws();
+ }
}
void GrGLGpu::sendIndexedInstancedMeshToGpu(const GrPrimitiveProcessor& primProc,
diff --git a/tests/GrCCPRTest.cpp b/tests/GrCCPRTest.cpp
new file mode 100644
index 0000000000..d8be726d6e
--- /dev/null
+++ b/tests/GrCCPRTest.cpp
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2017 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkTypes.h"
+#include "Test.h"
+
+#if SK_SUPPORT_GPU
+
+#include "GrContext.h"
+#include "GrContextPriv.h"
+#include "GrClip.h"
+#include "GrRenderTargetContext.h"
+#include "GrRenderTargetContextPriv.h"
+#include "GrShape.h"
+#include "GrPathRenderer.h"
+#include "GrPaint.h"
+#include "SkMatrix.h"
+#include "SkRect.h"
+#include "ccpr/GrCoverageCountingPathRenderer.h"
+#include <cmath>
+
+static constexpr int kCanvasSize = 100;
+
+class CCPRPathDrawer {
+public:
+ CCPRPathDrawer(GrContext* ctx)
+ : fCtx(ctx)
+ , fCCPR(GrCoverageCountingPathRenderer::CreateIfSupported(*fCtx->caps()))
+ , fRTC(fCtx->makeDeferredRenderTargetContext(SkBackingFit::kExact, kCanvasSize,
+ kCanvasSize, kRGBA_8888_GrPixelConfig,
+ nullptr)) {
+ if (fCCPR) {
+ fCtx->contextPriv().addOnFlushCallbackObject(fCCPR.get());
+ }
+ }
+
+ ~CCPRPathDrawer() {
+ if (fCCPR) {
+ fCtx->contextPriv().testingOnly_flushAndRemoveOnFlushCallbackObject(fCCPR.get());
+ }
+ }
+
+ bool valid() { return fCCPR && fRTC; }
+
+ void clear() { fRTC->clear(nullptr, 0, true); }
+
+ void drawPath(const SkPath& path, GrColor4f color = GrColor4f(0, 1, 0, 1)) {
+ GrPaint paint;
+ paint.setColor4f(color);
+ GrNoClip noClip;
+ SkIRect clipBounds = SkIRect::MakeWH(kCanvasSize, kCanvasSize);
+ SkMatrix matrix = SkMatrix::I();
+ GrShape shape(path);
+ fCCPR->drawPath({fCtx, std::move(paint), &GrUserStencilSettings::kUnused, fRTC.get(),
+ &noClip, &clipBounds, &matrix, &shape, GrAAType::kCoverage, false});
+ }
+
+ void flush() {
+ fCtx->flush();
+ }
+
+private:
+ GrContext* const fCtx;
+ sk_sp<GrCoverageCountingPathRenderer> fCCPR;
+ sk_sp<GrRenderTargetContext> fRTC;
+};
+
+DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrCCPRTest, reporter, ctxInfo) {
+ GrContext* const ctx = ctxInfo.grContext();
+ if (!GrCoverageCountingPathRenderer::IsSupported(*ctx->caps())) {
+ return;
+ }
+
+ CCPRPathDrawer ccpr(ctx);
+ if (!ccpr.valid()) {
+ ERRORF(reporter, "could not create render target context for ccpr.");
+ return;
+ }
+
+ // Test very busy paths.
+ static constexpr int kNumBusyVerbs = 1 << 17;
+ ccpr.clear();
+ SkPath busyPath;
+ busyPath.moveTo(0, 0); // top left
+ busyPath.lineTo(kCanvasSize, kCanvasSize); // bottom right
+ for (int i = 2; i < kNumBusyVerbs; ++i) {
+ float offset = i * ((float)kCanvasSize / kNumBusyVerbs);
+ busyPath.lineTo(kCanvasSize - offset, kCanvasSize + offset); // offscreen
+ }
+ ccpr.drawPath(busyPath);
+
+ ccpr.flush(); // If this doesn't crash, the test passed.
+ // If it does, maybe fiddle with fMaxInstancesPerDrawArraysWithoutCrashing in your
+ // platform's GrGLCaps.
+}
+
+#endif