Add a writer class for indirect draw commands

This enforces write-only access to the mapped buffers, will enable
chaining of indirect strokes, and gives us the ability to reorder the
fields for Metal.

Bug: chromium:1172543
Bug: skia:11291
Bug: skia:10419
Change-Id: I4449ff85dd0019f6d6d6781ede52bcf26dee8b02
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/367416
Reviewed-by: Greg Daniel <egdaniel@google.com>
Commit-Queue: Chris Dalton <csmartdalton@google.com>
This commit is contained in:
Chris Dalton 2021-02-07 20:56:36 -07:00 committed by Skia Commit-Bot
parent fc017c7c7e
commit a6a3d05ffb
15 changed files with 201 additions and 131 deletions

View File

@ -92,6 +92,7 @@ skia_gpu_sources = [
"$_src/gpu/GrDirectContextPriv.h",
"$_src/gpu/GrDistanceFieldGenFromVector.cpp",
"$_src/gpu/GrDistanceFieldGenFromVector.h",
"$_src/gpu/GrDrawIndirectCommand.h",
"$_src/gpu/GrDrawOpAtlas.cpp",
"$_src/gpu/GrDrawOpAtlas.h",
"$_src/gpu/GrDrawOpTest.cpp",

View File

@ -66,26 +66,6 @@ enum class GrPrimitiveRestart : bool {
kYes = true
};
struct GrDrawIndirectCommand {
uint32_t fVertexCount;
uint32_t fInstanceCount;
uint32_t fBaseVertex;
uint32_t fBaseInstance;
};
static_assert(sizeof(GrDrawIndirectCommand) == 16, "GrDrawIndirectCommand must be tightly packed");
struct GrDrawIndexedIndirectCommand {
uint32_t fIndexCount;
uint32_t fInstanceCount;
uint32_t fBaseIndex;
int32_t fBaseVertex;
uint32_t fBaseInstance;
};
static_assert(sizeof(GrDrawIndexedIndirectCommand) == 20,
"GrDrawIndexedIndirectCommand must be tightly packed");
/**
* Should a created surface be texturable?
*/

View File

@ -14,6 +14,7 @@
#include "include/private/SkTArray.h"
#include "include/private/SkTDArray.h"
#include "src/gpu/GrCpuBuffer.h"
#include "src/gpu/GrDrawIndirectCommand.h"
#include "src/gpu/GrNonAtomicRef.h"
class GrGpu;
@ -319,23 +320,23 @@ public:
GrDrawIndirectBufferAllocPool(GrGpu* gpu, sk_sp<CpuBufferCache> cpuBufferCache)
: GrBufferAllocPool(gpu, GrGpuBufferType::kDrawIndirect, std::move(cpuBufferCache)) {}
GrDrawIndirectCommand* makeSpace(int drawCount, sk_sp<const GrBuffer>* buffer, size_t* offset) {
return static_cast<GrDrawIndirectCommand*>(this->GrBufferAllocPool::makeSpace(
(size_t)drawCount * sizeof(GrDrawIndirectCommand), 4, buffer, offset));
GrDrawIndirectWriter makeSpace(int drawCount, sk_sp<const GrBuffer>* buffer, size_t* offset) {
return this->GrBufferAllocPool::makeSpace(drawCount * sizeof(GrDrawIndirectCommand), 4,
buffer, offset);
}
void putBack(int drawCount) {
this->GrBufferAllocPool::putBack((size_t)drawCount * sizeof(GrDrawIndirectCommand));
this->GrBufferAllocPool::putBack(drawCount * sizeof(GrDrawIndirectCommand));
}
GrDrawIndexedIndirectCommand* makeIndexedSpace(int drawCount, sk_sp<const GrBuffer>* buffer,
GrDrawIndexedIndirectWriter makeIndexedSpace(int drawCount, sk_sp<const GrBuffer>* buffer,
size_t* offset) {
return static_cast<GrDrawIndexedIndirectCommand*>(this->GrBufferAllocPool::makeSpace(
(size_t)drawCount * sizeof(GrDrawIndexedIndirectCommand), 4, buffer, offset));
return this->GrBufferAllocPool::makeSpace(
drawCount * sizeof(GrDrawIndexedIndirectCommand), 4, buffer, offset);
}
void putBackIndexed(int drawCount) {
this->GrBufferAllocPool::putBack((size_t)drawCount * sizeof(GrDrawIndexedIndirectCommand));
this->GrBufferAllocPool::putBack(drawCount * sizeof(GrDrawIndexedIndirectCommand));
}
using GrBufferAllocPool::unmap;

View File

@ -0,0 +1,79 @@
/*
* Copyright 2021 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef GrDrawIndirectCommand_DEFINED
#define GrDrawIndirectCommand_DEFINED
#include "src/gpu/GrCaps.h"
#include <array>
// Draw commands on the GPU are simple tuples of uint32_t. The ordering is backend-specific.
using GrDrawIndirectCommand = std::array<uint32_t, 4>;
using GrDrawIndexedIndirectCommand = std::array<uint32_t, 5>;
// Helper for writing commands to an indirect draw buffer. Usage:
//
// GrDrawIndirectWriter indirectWriter = target->makeDrawIndirectSpace(...);
// indirectWriter.write(...);
// indirectWriter.write(...);
struct GrDrawIndirectWriter {
public:
GrDrawIndirectWriter() = default;
GrDrawIndirectWriter(void* data) : fData(static_cast<GrDrawIndirectCommand*>(data)) {}
GrDrawIndirectWriter(const GrDrawIndirectWriter&) = delete;
GrDrawIndirectWriter(GrDrawIndirectWriter&& that) { *this = std::move(that); }
GrDrawIndirectWriter& operator=(const GrDrawIndirectWriter&) = delete;
GrDrawIndirectWriter& operator=(GrDrawIndirectWriter&& that) {
fData = that.fData;
that.fData = nullptr;
return *this;
}
bool isValid() const { return fData != nullptr; }
inline void write(uint32_t instanceCount, uint32_t baseInstance, uint32_t vertexCount,
uint32_t baseVertex, const GrCaps&) {
*fData++ = {vertexCount, instanceCount, baseVertex, baseInstance};
}
private:
GrDrawIndirectCommand* fData;
};
// Helper for writing commands to an indexed indirect draw buffer. Usage:
//
// GrDrawIndexedIndirectWriter indirectWriter = target->makeDrawIndexedIndirectSpace(...);
// indirectWriter.writeIndexed(...);
// indirectWriter.writeIndexed(...);
struct GrDrawIndexedIndirectWriter {
public:
GrDrawIndexedIndirectWriter() = default;
GrDrawIndexedIndirectWriter(void* data)
: fData(static_cast<GrDrawIndexedIndirectCommand*>(data)) {}
GrDrawIndexedIndirectWriter(const GrDrawIndexedIndirectWriter&) = delete;
GrDrawIndexedIndirectWriter(GrDrawIndexedIndirectWriter&& that) { *this = std::move(that); }
GrDrawIndexedIndirectWriter& operator=(const GrDrawIndexedIndirectWriter&) = delete;
GrDrawIndexedIndirectWriter& operator=(GrDrawIndexedIndirectWriter&& that) {
fData = that.fData;
that.fData = nullptr;
return *this;
}
bool isValid() const { return fData != nullptr; }
inline void writeIndexed(uint32_t indexCount, uint32_t baseIndex, uint32_t instanceCount,
uint32_t baseInstance, uint32_t baseVertex, const GrCaps&) {
*fData++ = {indexCount, instanceCount, baseIndex, baseVertex, baseInstance};
}
private:
GrDrawIndexedIndirectCommand* fData;
};
#endif

View File

@ -134,12 +134,13 @@ public:
uint16_t* makeIndexSpaceAtLeast(int minIndexCount, int fallbackIndexCount,
sk_sp<const GrBuffer>*, int* startIndex,
int* actualIndexCount) final;
GrDrawIndirectCommand* makeDrawIndirectSpace(int drawCount, sk_sp<const GrBuffer>* buffer,
GrDrawIndirectWriter makeDrawIndirectSpace(int drawCount, sk_sp<const GrBuffer>* buffer,
size_t* offset) override {
return fDrawIndirectPool.makeSpace(drawCount, buffer, offset);
}
GrDrawIndexedIndirectCommand* makeDrawIndexedIndirectSpace(
int drawCount, sk_sp<const GrBuffer>* buffer, size_t* offset) override {
GrDrawIndexedIndirectWriter makeDrawIndexedIndirectSpace(int drawCount,
sk_sp<const GrBuffer>* buffer,
size_t* offset) override {
return fDrawIndirectPool.makeIndexedSpace(drawCount, buffer, offset);
}
void putBackIndices(int indexCount) final;

View File

@ -10,6 +10,7 @@
#include "include/core/SkRect.h"
#include "src/gpu/GrCaps.h"
#include "src/gpu/GrCpuBuffer.h"
#include "src/gpu/GrDrawIndirectCommand.h"
#include "src/gpu/GrGpu.h"
#include "src/gpu/GrPrimitiveProcessor.h"
#include "src/gpu/GrProgramInfo.h"
@ -284,13 +285,13 @@ void GrOpsRenderPass::drawIndirect(const GrBuffer* drawIndirectBuffer, size_t bu
if (!this->gpu()->caps()->nativeDrawIndirectSupport()) {
// Polyfill indirect draws with looping instanced calls.
SkASSERT(drawIndirectBuffer->isCpuBuffer());
auto cpuIndirectBuffer = static_cast<const GrCpuBuffer*>(drawIndirectBuffer);
auto cmd = reinterpret_cast<const GrDrawIndirectCommand*>(
auto* cpuIndirectBuffer = static_cast<const GrCpuBuffer*>(drawIndirectBuffer);
auto* cmds = reinterpret_cast<const GrDrawIndirectCommand*>(
cpuIndirectBuffer->data() + bufferOffset);
auto end = cmd + drawCount;
for (; cmd != end; ++cmd) {
this->onDrawInstanced(cmd->fInstanceCount, cmd->fBaseInstance, cmd->fVertexCount,
cmd->fBaseVertex);
for (int i = 0; i < drawCount; ++i) {
// TODO: SkASSERT(caps.drawIndirectSignature() == standard);
auto [vertexCount, instanceCount, baseVertex, baseInstance] = cmds[i];
this->onDrawInstanced(instanceCount, baseInstance, vertexCount, baseVertex);
}
return;
}
@ -312,13 +313,14 @@ void GrOpsRenderPass::drawIndexedIndirect(const GrBuffer* drawIndirectBuffer, si
this->gpu()->caps()->nativeDrawIndexedIndirectIsBroken()) {
// Polyfill indexedIndirect draws with looping indexedInstanced calls.
SkASSERT(drawIndirectBuffer->isCpuBuffer());
auto cpuIndirectBuffer = static_cast<const GrCpuBuffer*>(drawIndirectBuffer);
auto cmd = reinterpret_cast<const GrDrawIndexedIndirectCommand*>(
auto* cpuIndirectBuffer = static_cast<const GrCpuBuffer*>(drawIndirectBuffer);
auto* cmds = reinterpret_cast<const GrDrawIndexedIndirectCommand*>(
cpuIndirectBuffer->data() + bufferOffset);
auto end = cmd + drawCount;
for (; cmd != end; ++cmd) {
this->onDrawIndexedInstanced(cmd->fIndexCount, cmd->fBaseIndex, cmd->fInstanceCount,
cmd->fBaseInstance, cmd->fBaseVertex);
for (int i = 0; i < drawCount; ++i) {
// TODO: SkASSERT(caps.drawIndirectSignature() == standard);
auto [indexCount, instanceCount, baseIndex, baseVertex, baseInstance] = cmds[i];
this->onDrawIndexedInstanced(indexCount, baseIndex, instanceCount, baseInstance,
baseVertex);
}
return;
}

View File

@ -286,11 +286,12 @@ void GrGLOpsRenderPass::multiDrawArraysANGLEOrWebGL(const GrBuffer* drawIndirect
while (drawCount) {
int countInBatch = std::min(drawCount, kMaxDrawCountPerBatch);
for (int i = 0; i < countInBatch; ++i) {
const auto& cmd = cmds[i];
fFirsts[i] = cmd.fBaseVertex;
fCounts[i] = cmd.fVertexCount;
fInstanceCounts[i] = cmd.fInstanceCount;
fBaseInstances[i] = cmd.fBaseInstance;
// TODO: SkASSERT(caps.drawIndirectSignature() == standard);
auto [vertexCount, instanceCount, baseVertex, baseInstance] = cmds[i];
fFirsts[i] = baseVertex;
fCounts[i] = vertexCount;
fInstanceCounts[i] = instanceCount;
fBaseInstances[i] = baseInstance;
}
if (countInBatch == 1) {
GL_CALL(DrawArraysInstancedBaseInstance(glPrimType, fFirsts[0], fCounts[0],
@ -359,12 +360,13 @@ void GrGLOpsRenderPass::multiDrawElementsANGLEOrWebGL(const GrBuffer* drawIndire
while (drawCount) {
int countInBatch = std::min(drawCount, kMaxDrawCountPerBatch);
for (int i = 0; i < countInBatch; ++i) {
const auto& cmd = cmds[i];
fCounts[i] = cmd.fIndexCount;
fIndices[i] = this->offsetForBaseIndex(cmd.fBaseIndex);
fInstanceCounts[i] = cmd.fInstanceCount;
fBaseVertices[i] = cmd.fBaseVertex;
fBaseInstances[i] = cmd.fBaseInstance;
// TODO: SkASSERT(caps.drawIndirectSignature() == standard);
auto [indexCount, instanceCount, baseIndex, baseVertex, baseInstance] = cmds[i];
fCounts[i] = indexCount;
fIndices[i] = this->offsetForBaseIndex(baseIndex);
fInstanceCounts[i] = instanceCount;
fBaseVertices[i] = baseVertex;
fBaseInstances[i] = baseInstance;
}
if (countInBatch == 1) {
GL_CALL(DrawElementsInstancedBaseVertexBaseInstance(glPrimType, fCounts[0],

View File

@ -56,32 +56,35 @@ public:
return fStaticVertexData;
}
GrDrawIndirectCommand* makeDrawIndirectSpace(int drawCount, sk_sp<const GrBuffer>* buffer,
GrDrawIndirectWriter makeDrawIndirectSpace(int drawCount, sk_sp<const GrBuffer>* buffer,
size_t* offsetInBytes) override {
int staticBufferCount = (int)SK_ARRAY_COUNT(fStaticDrawIndirectData);
if (drawCount > staticBufferCount) {
SK_ABORT("FATAL: wanted %i static drawIndirect elements; only have %i.\n",
drawCount, staticBufferCount);
if (sizeof(GrDrawIndirectCommand) * drawCount > sizeof(fStaticIndirectData)) {
SK_ABORT("FATAL: wanted %zu bytes of static indirect data; only have %zu.\n",
sizeof(GrDrawIndirectCommand) * drawCount, sizeof(fStaticIndirectData));
}
*offsetInBytes = 0;
return fStaticDrawIndirectData;
return fStaticIndirectData;
}
void putBackIndirectDraws(int count) override { /* no-op */ }
GrDrawIndexedIndirectCommand* makeDrawIndexedIndirectSpace(
int drawCount, sk_sp<const GrBuffer>* buffer, size_t* offsetInBytes) override {
int staticBufferCount = (int)SK_ARRAY_COUNT(fStaticDrawIndexedIndirectData);
if (drawCount > staticBufferCount) {
SK_ABORT("FATAL: wanted %i static drawIndexedIndirect elements; only have %i.\n",
drawCount, staticBufferCount);
GrDrawIndexedIndirectWriter makeDrawIndexedIndirectSpace(int drawCount,
sk_sp<const GrBuffer>* buffer,
size_t* offsetInBytes) override {
if (sizeof(GrDrawIndexedIndirectCommand) * drawCount > sizeof(fStaticIndirectData)) {
SK_ABORT("FATAL: wanted %zu bytes of static indirect data; only have %zu.\n",
sizeof(GrDrawIndexedIndirectCommand) * drawCount, sizeof(fStaticIndirectData));
}
*offsetInBytes = 0;
return fStaticDrawIndexedIndirectData;
return fStaticIndirectData;
}
void putBackIndexedIndirectDraws(int count) override { /* no-op */ }
// Call these methods to see what got written after the previous call to make*Space.
const void* peekStaticVertexData() const { return fStaticVertexData; }
const void* peekStaticIndirectData() const { return fStaticIndirectData; }
#define UNIMPL(...) __VA_ARGS__ override { SK_ABORT("unimplemented."); }
UNIMPL(void recordDraw(const GrGeometryProcessor*, const GrSimpleMesh[], int,
const GrSurfaceProxy* const[], GrPrimitiveType))
@ -100,8 +103,7 @@ public:
private:
sk_sp<GrDirectContext> fMockContext;
char fStaticVertexData[6 * 1024 * 1024];
GrDrawIndirectCommand fStaticDrawIndirectData[32];
GrDrawIndexedIndirectCommand fStaticDrawIndexedIndirectData[32];
char fStaticIndirectData[sizeof(GrDrawIndexedIndirectCommand) * 32];
SkSTArenaAllocWithReset<1024 * 1024> fAllocator;
GrXferProcessor::DstProxyView fDstProxyView;
};

View File

@ -10,6 +10,7 @@
#include "src/core/SkArenaAlloc.h"
#include "src/gpu/GrAppliedClip.h"
#include "src/gpu/GrDrawIndirectCommand.h"
#include "src/gpu/GrGeometryProcessor.h"
#include "src/gpu/GrSimpleMesh.h"
#include "src/gpu/ops/GrDrawOp.h"
@ -199,16 +200,16 @@ public:
* Makes space for elements in a draw-indirect buffer. Upon success, the returned pointer is a
* CPU mapping where the data should be written.
*/
virtual GrDrawIndirectCommand* makeDrawIndirectSpace(int drawCount,
sk_sp<const GrBuffer>* buffer,
virtual GrDrawIndirectWriter makeDrawIndirectSpace(int drawCount, sk_sp<const GrBuffer>* buffer,
size_t* offsetInBytes) = 0;
/**
* Makes space for elements in a draw-indexed-indirect buffer. Upon success, the returned
* pointer is a CPU mapping where the data should be written.
*/
virtual GrDrawIndexedIndirectCommand* makeDrawIndexedIndirectSpace(
int drawCount, sk_sp<const GrBuffer>* buffer, size_t* offsetInBytes) = 0;
virtual GrDrawIndexedIndirectWriter makeDrawIndexedIndirectSpace(int drawCount,
sk_sp<const GrBuffer>*,
size_t* offsetInBytes) = 0;
/** Helpers for ops which over-allocate and then return excess data to the pool. */
virtual void putBackIndices(int indices) = 0;

View File

@ -49,9 +49,10 @@ GrPathIndirectTessellator::GrPathIndirectTessellator(const SkMatrix& viewMatrix,
void GrPathIndirectTessellator::prepare(GrMeshDrawOp::Target* target, const SkMatrix& viewMatrix,
const SkPath& path,
const BreadcrumbTriangleList* breadcrumbTriangleList) {
const GrCaps& caps = target->caps();
SkASSERT(fTotalInstanceCount == 0);
SkASSERT(fIndirectDrawCount == 0);
SkASSERT(target->caps().drawInstancedSupport());
SkASSERT(caps.drawInstancedSupport());
int instanceLockCount = fOuterCurveInstanceCount;
if (fDrawInnerFan) {
@ -110,9 +111,9 @@ void GrPathIndirectTessellator::prepare(GrMeshDrawOp::Target* target, const SkMa
// possible resolve level (kMaxResolveLevel; resolveLevel=0 never has any instances), plus one
// more for the optional inner fan triangles.
int indirectLockCnt = kMaxResolveLevel + 1;
GrDrawIndexedIndirectCommand* indirectData = target->makeDrawIndexedIndirectSpace(
GrDrawIndexedIndirectWriter indirectWriter = target->makeDrawIndexedIndirectSpace(
indirectLockCnt, &fIndirectDrawBuffer, &fIndirectDrawOffset);
if (!indirectData) {
if (!indirectWriter.isValid()) {
SkASSERT(!fIndirectDrawBuffer);
return;
}
@ -126,8 +127,10 @@ void GrPathIndirectTessellator::prepare(GrMeshDrawOp::Target* target, const SkMa
// at the beginning of the instance buffer. Add a special-case indirect draw here that will
// emit the triangles [P0, P1, P2] from these 4-point instances.
SkASSERT(fIndirectDrawCount < indirectLockCnt);
indirectData[fIndirectDrawCount++] = GrMiddleOutCubicShader::MakeDrawTrianglesIndirectCmd(
numTrianglesAtBeginningOfData, fBaseInstance);
GrMiddleOutCubicShader::WriteDrawTrianglesIndirectCmd(&indirectWriter,
numTrianglesAtBeginningOfData,
fBaseInstance, caps);
++fIndirectDrawCount;
runningInstanceCount = numTrianglesAtBeginningOfData;
}
SkASSERT(fResolveLevelCounts[0] == 0);
@ -139,8 +142,11 @@ void GrPathIndirectTessellator::prepare(GrMeshDrawOp::Target* target, const SkMa
}
instanceLocations[resolveLevel] = instanceData + runningInstanceCount * 4;
SkASSERT(fIndirectDrawCount < indirectLockCnt);
indirectData[fIndirectDrawCount++] = GrMiddleOutCubicShader::MakeDrawCubicsIndirectCmd(
resolveLevel, instanceCountAtCurrLevel, fBaseInstance + runningInstanceCount);
GrMiddleOutCubicShader::WriteDrawCubicsIndirectCmd(&indirectWriter, resolveLevel,
instanceCountAtCurrLevel,
fBaseInstance + runningInstanceCount,
caps);
++fIndirectDrawCount;
runningInstanceCount += instanceCountAtCurrLevel;
}

View File

@ -8,6 +8,7 @@
#ifndef GrStencilPathShader_DEFINED
#define GrStencilPathShader_DEFINED
#include "src/gpu/GrDrawIndirectCommand.h"
#include "src/gpu/tessellate/GrPathShader.h"
#include "src/gpu/tessellate/GrTessellationPathRenderer.h"
@ -165,25 +166,26 @@ public:
// Configures an indirect draw to render cubic instances with 2^resolveLevel evenly-spaced (in
// the parametric sense) line segments.
static GrDrawIndexedIndirectCommand MakeDrawCubicsIndirectCmd(int resolveLevel,
uint32_t instanceCount,
uint32_t baseInstance) {
static void WriteDrawCubicsIndirectCmd(GrDrawIndexedIndirectWriter* indirectWriter,
int resolveLevel, uint32_t instanceCount,
uint32_t baseInstance, const GrCaps& caps) {
SkASSERT(resolveLevel > 0 && resolveLevel <= GrTessellationPathRenderer::kMaxResolveLevel);
// Starting at baseIndex=3, the index buffer triangulates a cubic with 2^kMaxResolveLevel
// line segments. Each index value corresponds to a parametric T value on the curve. Since
// the triangles are arranged in "middle-out" order, we can conveniently control the
// resolveLevel by changing only the indexCount.
uint32_t indexCount = NumVerticesAtResolveLevel(resolveLevel);
return {indexCount, instanceCount, 3, 0, baseInstance};
indirectWriter->writeIndexed(indexCount, 3, instanceCount, baseInstance, 0, caps);
}
// For performance reasons we can often express triangles as an indirect cubic draw and sneak
// them in alongside the other indirect draws. This method configures an indirect draw to emit
// the triangle [P0, P1, P2] from a 4-point instance.
static GrDrawIndexedIndirectCommand MakeDrawTrianglesIndirectCmd(uint32_t instanceCount,
uint32_t baseInstance) {
static void WriteDrawTrianglesIndirectCmd(GrDrawIndexedIndirectWriter* indirectWriter,
uint32_t instanceCount, uint32_t baseInstance,
const GrCaps& caps) {
// Indices 0,1,2 have special index values that emit points P0, P1, and P2 respectively.
return {3, instanceCount, 0, 0, baseInstance};
indirectWriter->writeIndexed(3, 0, instanceCount, baseInstance, 0, caps);
}
// Returns the index buffer that should be bound when drawing with this shader.

View File

@ -599,11 +599,14 @@ void GrStrokeIndirectTessellator::prepare(GrMeshDrawOp::Target* target, const Sk
return;
}
const GrCaps& caps = target->caps();
// Allocate enough indirect commands for every resolve level. We will putBack the unused ones
// at the end.
GrDrawIndirectCommand* drawIndirectData = target->makeDrawIndirectSpace(
kMaxResolveLevel + 1, &fDrawIndirectBuffer, &fDrawIndirectOffset);
if (!drawIndirectData) {
GrDrawIndirectWriter indirectWriter = target->makeDrawIndirectSpace(kMaxResolveLevel + 1,
&fDrawIndirectBuffer,
&fDrawIndirectOffset);
if (!indirectWriter.isValid()) {
SkASSERT(!fDrawIndirectBuffer);
return;
}
@ -627,11 +630,9 @@ void GrStrokeIndirectTessellator::prepare(GrMeshDrawOp::Target* target, const Sk
for (int i = 0; i <= kMaxResolveLevel; ++i) {
if (fResolveLevelCounts[i]) {
int numEdges = numExtraEdgesInJoin + num_edges_in_resolve_level(i);
auto& cmd = drawIndirectData[fDrawIndirectCount++];
cmd.fVertexCount = numEdges * 2;
cmd.fInstanceCount = fResolveLevelCounts[i];
cmd.fBaseVertex = 0;
cmd.fBaseInstance = baseInstance + currentInstanceIdx;
indirectWriter.write(fResolveLevelCounts[i], baseInstance + currentInstanceIdx,
numEdges * 2, 0, caps);
++fDrawIndirectCount;
numEdgesPerResolveLevel[i] = numEdges;
nextInstanceLocations[i] = instanceData + currentInstanceIdx;
#ifdef SK_DEBUG

View File

@ -61,9 +61,9 @@ private:
#if GR_TEST_UTILS
public:
void verifyResolveLevels(skiatest::Reporter*, GrMeshDrawOp::Target*, const SkMatrix&,
void verifyResolveLevels(skiatest::Reporter*, class GrMockOpTarget*, const SkMatrix&,
const SkPath&, const SkStrokeRec&);
void verifyBuffers(skiatest::Reporter*, GrMeshDrawOp::Target*, const SkMatrix&,
void verifyBuffers(skiatest::Reporter*, class GrMockOpTarget*, const SkMatrix&,
const SkStrokeRec&);
class Benchmark;
#endif

View File

@ -324,8 +324,8 @@ DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrMeshTest, reporter, ctxInfo) {
-1,-1, 0,0, 0,1, 1,0, 1,1, -1,-1, 0,0, 1,0, 0,1, 1,1});
VALIDATE(helper->fVertBuffer);
GrDrawIndirectCommand* drawIndirect = nullptr;
GrDrawIndexedIndirectCommand* drawIndexedIndirect = nullptr;
GrDrawIndirectWriter indirectWriter;
GrDrawIndexedIndirectWriter indexedIndirectWriter;
if (indexed) {
// Make helper->fDrawIndirectBufferOffset nonzero.
sk_sp<const GrBuffer> dummyBuff;
@ -333,7 +333,7 @@ DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrMeshTest, reporter, ctxInfo) {
// Make a superfluous call to makeDrawIndirectSpace in order to test
// "offsetInBytes!=0" for the actual call to makeDrawIndexedIndirectSpace.
helper->target()->makeDrawIndirectSpace(29, &dummyBuff, &dummyOffset);
drawIndexedIndirect = helper->target()->makeDrawIndexedIndirectSpace(
indexedIndirectWriter = helper->target()->makeDrawIndexedIndirectSpace(
kBoxCountY, &helper->fDrawIndirectBuffer,
&helper->fDrawIndirectBufferOffset);
} else {
@ -342,8 +342,9 @@ DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrMeshTest, reporter, ctxInfo) {
size_t dummyOffset;
// Make a superfluous call to makeDrawIndexedIndirectSpace in order to test
// "offsetInBytes!=0" for the actual call to makeDrawIndirectSpace.
helper->target()->makeDrawIndexedIndirectSpace(7, &dummyBuff, &dummyOffset);
drawIndirect = helper->target()->makeDrawIndirectSpace(
helper->target()->makeDrawIndexedIndirectSpace(7, &dummyBuff,
&dummyOffset);
indirectWriter = helper->target()->makeDrawIndirectSpace(
kBoxCountY, &helper->fDrawIndirectBuffer,
&helper->fDrawIndirectBufferOffset);
}
@ -353,18 +354,12 @@ DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrMeshTest, reporter, ctxInfo) {
int baseVertex = (y % 2) ? 1 : 6;
if (indexed) {
int baseIndex = 1 + y * 6;
drawIndexedIndirect->fIndexCount = 6;
drawIndexedIndirect->fBaseIndex = baseIndex;
drawIndexedIndirect->fInstanceCount = kBoxCountX;
drawIndexedIndirect->fBaseInstance = y * kBoxCountX;
drawIndexedIndirect->fBaseVertex = baseVertex;
++drawIndexedIndirect;
indexedIndirectWriter.writeIndexed(6, baseIndex, kBoxCountX,
y * kBoxCountX, baseVertex,
*dContext->priv().caps());
} else {
drawIndirect->fInstanceCount = kBoxCountX;
drawIndirect->fBaseInstance = y * kBoxCountX;
drawIndirect->fVertexCount = 4;
drawIndirect->fBaseVertex = baseVertex;
++drawIndirect;
indirectWriter.write(kBoxCountX, y * kBoxCountX, 4, baseVertex,
*dContext->priv().caps());
}
}
},

View File

@ -32,7 +32,7 @@ static sk_sp<GrDirectContext> make_mock_context() {
return GrDirectContext::MakeMock(&mockOptions, ctxOptions);
}
static void test_stroke(skiatest::Reporter* r, GrDirectContext* ctx, GrMeshDrawOp::Target* target,
static void test_stroke(skiatest::Reporter* r, GrDirectContext* ctx, GrMockOpTarget* target,
const SkPath& path, SkRandom& rand) {
SkStrokeRec stroke(SkStrokeRec::kFill_InitStyle);
stroke.setStrokeStyle(.1f);
@ -263,7 +263,7 @@ static float test_tolerance(SkPaint::Join joinType) {
}
void GrStrokeIndirectTessellator::verifyResolveLevels(skiatest::Reporter* r,
GrMeshDrawOp::Target* target,
GrMockOpTarget* target,
const SkMatrix& viewMatrix,
const SkPath& path,
const SkStrokeRec& stroke) {
@ -421,29 +421,27 @@ void GrStrokeIndirectTessellator::verifyResolveLevels(skiatest::Reporter* r,
SkASSERT(nextResolveLevel == fResolveLevels + fResolveLevelArrayCount);
}
void GrStrokeIndirectTessellator::verifyBuffers(skiatest::Reporter* r,
GrMeshDrawOp::Target* target,
void GrStrokeIndirectTessellator::verifyBuffers(skiatest::Reporter* r, GrMockOpTarget* target,
const SkMatrix& viewMatrix,
const SkStrokeRec& stroke) {
// Make sure the resolve level we assigned to each instance agrees with the actual data.
using IndirectInstance = GrStrokeTessellateShader::IndirectInstance;
auto instance = static_cast<const IndirectInstance*>(target->peekStaticVertexData());
auto* indirect = static_cast<const GrDrawIndirectCommand*>(target->peekStaticIndirectData());
GrStrokeTessellateShader::Tolerances tolerances(viewMatrix.getMaxScale(), stroke.getWidth());
float tolerance = test_tolerance(stroke.getJoin());
// Make sure the resolve level we assign to each instance agrees with the actual data.
// GrMockOpTarget returns the same pointers every time.
int _;
auto instance = (const IndirectInstance*)target->makeVertexSpace(0, 0, nullptr, &_);
size_t __;
auto indirect = target->makeDrawIndirectSpace(0, nullptr, &__);
for (int i = 0; i < fDrawIndirectCount; ++i) {
// TODO: SkASSERT(caps.drawIndirectCmdSignature() == standard);
auto [vertexCount, instanceCount, baseVertex, baseInstance] = *indirect++;
int numExtraEdgesInJoin = (stroke.getJoin() == SkPaint::kMiter_Join) ? 4 : 3;
int numStrokeEdges = indirect->fVertexCount/2 - numExtraEdgesInJoin;
int numStrokeEdges = vertexCount/2 - numExtraEdgesInJoin;
int numSegments = numStrokeEdges - 1;
bool isPow2 = !(numSegments & (numSegments - 1));
REPORTER_ASSERT(r, isPow2);
int resolveLevel = sk_float_nextlog2(numSegments);
REPORTER_ASSERT(r, 1 << resolveLevel == numSegments);
for (unsigned j = 0; j < indirect->fInstanceCount; ++j) {
SkASSERT(fabsf(instance->fNumTotalEdges) == indirect->fVertexCount/2);
for (unsigned j = 0; j < instanceCount; ++j) {
SkASSERT(fabsf(instance->fNumTotalEdges) == vertexCount/2);
const SkPoint* p = instance->fPts.data();
float numParametricSegments = GrWangsFormula::cubic(
tolerances.fParametricIntolerance, p);
@ -476,6 +474,5 @@ void GrStrokeIndirectTessellator::verifyBuffers(skiatest::Reporter* r,
}
++instance;
}
++indirect;
}
}