Reland "Add support for explicit attribute offsets and strides."

This is a reland of 6927ab9311

Original change's description:
> Add support for explicit attribute offsets and strides.
>
> Previously attribute offsets were always computed based on their
> position in an attribute array and the stride was determined
> by the offset and size of the last attribute.
>
> Now a GP has the option to create attributes with explicit offsets
> and specify an explicit vertex stride. All attributes must either
> be implicit or explicit (enforced by assert).
>
> GrGeometryProcessor::AttributeSet is now responsible for handling
> implicitly determined attribute offsets and strides. The backends
> no longer compute them.
>
> Bug: skia:12720
> Change-Id: I0211673dc70d4797c2d66b2555d8f5fb430be056
> Reviewed-on: https://skia-review.googlesource.com/c/skia/+/484736
> Reviewed-by: Greg Daniel <egdaniel@google.com>
> Reviewed-by: Michael Ludwig <michaelludwig@google.com>
> Commit-Queue: Brian Salomon <bsalomon@google.com>

Bug: skia:12720
Change-Id: Ic4975b5b2e52f2d8213154da0e585eca6dfdd78d
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/486098
Reviewed-by: Ben Wagner <bungeman@google.com>
Commit-Queue: Brian Salomon <bsalomon@google.com>
This commit is contained in:
Brian Salomon 2021-12-16 16:14:56 -05:00 committed by SkCQ
parent f70746701c
commit dd9ef457d9
38 changed files with 564 additions and 188 deletions

View File

@ -117,7 +117,7 @@ private:
fInColor = {"inColor", kHalf4_GrVertexAttribType, kHalf4_GrSLType};
break;
}
this->setVertexAttributes(&fInPosition, 2);
this->setVertexAttributesWithImplicitOffsets(&fInPosition, 2);
}
Mode fMode;

300
gm/attributes.cpp Normal file
View File

@ -0,0 +1,300 @@
/*
* Copyright 2021 Google LLC
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "gm/gm.h"
#include "include/core/SkPoint.h"
#include "include/core/SkRect.h"
#include "include/gpu/GrRecordingContext.h"
#include "src/core/SkCanvasPriv.h"
#include "src/gpu/GrBuffer.h"
#include "src/gpu/GrGeometryProcessor.h"
#include "src/gpu/GrGpuBuffer.h"
#include "src/gpu/GrOpFlushState.h"
#include "src/gpu/GrProcessor.h"
#include "src/gpu/GrProcessorSet.h"
#include "src/gpu/GrProgramInfo.h"
#include "src/gpu/GrResourceProvider.h"
#include "src/gpu/GrShaderVar.h"
#include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
#include "src/gpu/glsl/GrGLSLVertexGeoBuilder.h"
#include "src/gpu/ops/GrDrawOp.h"
#include "src/gpu/ops/GrOp.h"
#include "src/gpu/v1/SurfaceDrawContext_v1.h"
#include "tools/gpu/ProxyUtils.h"
#include <memory>
#include <vector>
class GrAppliedClip;
class GrGLSLProgramDataManager;
namespace {
enum class AttrMode {
kAuto,
kManual,
kWacky
};
class AttributeTestProcessor : public GrGeometryProcessor {
public:
static GrGeometryProcessor* Make(SkArenaAlloc* arena, AttrMode mode) {
return arena->make([&](void* ptr) { return new (ptr) AttributeTestProcessor(mode); });
}
const char* name() const final { return "AttributeTestProcessor"; }
void addToKey(const GrShaderCaps&, GrProcessorKeyBuilder* b) const final {
b->add32(static_cast<uint32_t>(fMode));
}
std::unique_ptr<ProgramImpl> makeProgramImpl(const GrShaderCaps&) const final;
private:
AttributeTestProcessor(AttrMode mode)
: GrGeometryProcessor(kAttributeTestProcessor_ClassID), fMode(mode) {
switch (fMode) {
case AttrMode::kAuto:
fAttributes.emplace_back("pos", kFloat2_GrVertexAttribType, kFloat2_GrSLType);
fAttributes.emplace_back("color", kUByte4_norm_GrVertexAttribType, kHalf4_GrSLType);
this->setVertexAttributesWithImplicitOffsets(fAttributes.data(),
fAttributes.size());
break;
case AttrMode::kManual:
// Same result as kAuto but with explicitly specified offsets and stride.
fAttributes.emplace_back("pos", kFloat2_GrVertexAttribType, kFloat2_GrSLType, 0);
fAttributes.emplace_back(
"color", kUByte4_norm_GrVertexAttribType, kHalf4_GrSLType, 8);
this->setVertexAttributes(fAttributes.data(), fAttributes.size(), 12);
break;
case AttrMode::kWacky:
// 0 thru 7 : float2 aliased to "pos0" and "pos1"
// 8 thru 11: pad
// 12 thru 15: unorm4 "color"
// 16 thru 19: pad
fAttributes.emplace_back("pos0", kFloat2_GrVertexAttribType, kFloat2_GrSLType, 0);
fAttributes.emplace_back("pos1", kFloat2_GrVertexAttribType, kFloat2_GrSLType, 0);
fAttributes.emplace_back(
"color", kUByte4_norm_GrVertexAttribType, kHalf4_GrSLType, 12);
this->setVertexAttributes(fAttributes.data(), fAttributes.size(), 20);
break;
}
}
const AttrMode fMode;
std::vector<Attribute> fAttributes;
using INHERITED = GrGeometryProcessor;
};
std::unique_ptr<GrGeometryProcessor::ProgramImpl> AttributeTestProcessor::makeProgramImpl(
const GrShaderCaps&) const {
class Impl : public ProgramImpl {
public:
void setData(const GrGLSLProgramDataManager&,
const GrShaderCaps&,
const GrGeometryProcessor&) override {}
private:
void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override {
const AttributeTestProcessor& proc = args.fGeomProc.cast<AttributeTestProcessor>();
args.fVaryingHandler->emitAttributes(proc);
if (proc.fMode == AttrMode::kWacky) {
args.fVertBuilder->codeAppend("float2 pos = pos0 + pos1;");
}
args.fFragBuilder->codeAppendf("half4 %s;", args.fOutputColor);
args.fVaryingHandler->addPassThroughAttribute(GrShaderVar("color", kHalf4_GrSLType),
args.fOutputColor);
gpArgs->fPositionVar.set(kFloat2_GrSLType, "pos");
args.fFragBuilder->codeAppendf("const half4 %s = half4(1);", args.fOutputCoverage);
}
};
return std::make_unique<Impl>();
}
class AttributeTestOp : public GrDrawOp {
public:
DEFINE_OP_CLASS_ID
static GrOp::Owner Make(GrRecordingContext* context, AttrMode mode, const SkRect& r) {
return GrOp::Make<AttributeTestOp>(context, mode, r);
}
private:
AttributeTestOp(AttrMode mode, SkRect rect) : GrDrawOp(ClassID()), fMode(mode), fRect(rect) {
this->setBounds(fRect, HasAABloat::kNo, IsHairline::kNo);
}
const char* name() const override { return "AttributeTestOp"; }
FixedFunctionFlags fixedFunctionFlags() const override { return FixedFunctionFlags::kNone; }
GrProcessorSet::Analysis finalize(const GrCaps&, const GrAppliedClip*, GrClampType) override {
return GrProcessorSet::EmptySetAnalysis();
}
GrProgramInfo* createProgramInfo(const GrCaps* caps,
SkArenaAlloc* arena,
const GrSurfaceProxyView& writeView,
bool usesMSAASurface,
GrAppliedClip&& appliedClip,
const GrDstProxyView& dstProxyView,
GrXferBarrierFlags renderPassXferBarriers,
GrLoadOp colorLoadOp) const {
GrGeometryProcessor* geomProc = AttributeTestProcessor::Make(arena, fMode);
return sk_gpu_test::CreateProgramInfo(caps,
arena,
writeView,
usesMSAASurface,
std::move(appliedClip),
dstProxyView,
geomProc,
SkBlendMode::kSrcOver,
GrPrimitiveType::kTriangleStrip,
renderPassXferBarriers,
colorLoadOp);
}
GrProgramInfo* createProgramInfo(GrOpFlushState* flushState) const {
return this->createProgramInfo(&flushState->caps(),
flushState->allocator(),
flushState->writeView(),
flushState->usesMSAASurface(),
flushState->detachAppliedClip(),
flushState->dstProxyView(),
flushState->renderPassBarriers(),
flushState->colorLoadOp());
}
void onPrePrepare(GrRecordingContext* context,
const GrSurfaceProxyView& writeView,
GrAppliedClip* clip,
const GrDstProxyView& dstProxyView,
GrXferBarrierFlags renderPassXferBarriers,
GrLoadOp colorLoadOp) final {
SkArenaAlloc* arena = context->priv().recordTimeAllocator();
// DMSAA is not supported on DDL.
bool usesMSAASurface = writeView.asRenderTargetProxy()->numSamples() > 1;
// This is equivalent to a GrOpFlushState::detachAppliedClip
GrAppliedClip appliedClip = clip ? std::move(*clip) : GrAppliedClip::Disabled();
fProgramInfo = this->createProgramInfo(context->priv().caps(),
arena,
writeView,
usesMSAASurface,
std::move(appliedClip),
dstProxyView,
renderPassXferBarriers,
colorLoadOp);
context->priv().recordProgramInfo(fProgramInfo);
}
template <typename V> void makeVB(GrOpFlushState* flushState, const SkRect rect) {
V v[4];
v[0].p = {rect.left() , rect.top() };
v[1].p = {rect.right(), rect.top() };
v[2].p = {rect.left() , rect.bottom()};
v[3].p = {rect.right(), rect.bottom()};
v[0].color = SK_ColorRED;
v[1].color = SK_ColorGREEN;
v[2].color = SK_ColorYELLOW;
v[3].color = SK_ColorMAGENTA;
fVertexBuffer = flushState->resourceProvider()->createBuffer(
sizeof(v), GrGpuBufferType::kVertex, kStatic_GrAccessPattern, v);
}
void onPrepare(GrOpFlushState* flushState) override {
if (fMode == AttrMode::kWacky) {
struct V {
SkPoint p;
uint32_t pad0;
uint32_t color;
uint32_t pad1;
};
SkRect rect {fRect.fLeft/2.f, fRect.fTop/2.f, fRect.fRight/2.f, fRect.fBottom/2.f};
this->makeVB<V>(flushState, rect);
} else {
struct V {
SkPoint p;
uint32_t color;
};
this->makeVB<V>(flushState, fRect);
}
}
void onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) override {
if (!fVertexBuffer) {
return;
}
if (!fProgramInfo) {
fProgramInfo = this->createProgramInfo(flushState);
}
flushState->bindPipeline(*fProgramInfo, fRect);
flushState->bindBuffers(nullptr, nullptr, std::move(fVertexBuffer));
flushState->draw(4, 0);
}
sk_sp<GrBuffer> fVertexBuffer;
const AttrMode fMode;
const SkRect fRect;
// The program info (and both the GrPipeline and GrGeometryProcessor it relies on), when
// allocated, are allocated in either the ddl-record-time or flush-time arena. It is the
// arena's job to free up their memory so we just have a bare programInfo pointer here. We
// don't even store the GrPipeline and GrGeometryProcessor pointers here bc they are
// guaranteed to have the same lifetime as the program info.
GrProgramInfo* fProgramInfo = nullptr;
friend class ::GrOp; // for ctor
using INHERITED = GrDrawOp;
};
} // namespace
namespace skiagm {
/**
* This is a GPU-backend specific test that exercises explicit and implicit attribute offsets and
* strides.
*/
class AttributesGM : public GpuGM {
SkString onShortName() override { return SkString("attributes"); }
SkISize onISize() override { return {120, 340}; }
DrawResult onDraw(GrRecordingContext*, SkCanvas*, SkString* errorMsg) override;
};
DrawResult AttributesGM::onDraw(GrRecordingContext* rc, SkCanvas* canvas, SkString* errorMsg) {
auto sdc = SkCanvasPriv::TopDeviceSurfaceDrawContext(canvas);
if (!sdc) {
*errorMsg = kErrorMsg_DrawSkippedGpuOnly;
return DrawResult::kSkip;
}
sdc->clear(SK_PMColor4fBLACK);
// Draw the test directly to the frame buffer.
auto r = SkRect::MakeXYWH(10, 10, 100, 100);
for (AttrMode m : {AttrMode::kAuto, AttrMode::kManual, AttrMode::kWacky}) {
sdc->addDrawOp(AttributeTestOp::Make(rc, m, r));
r.offset(0, 110);
}
return DrawResult::kOk;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
DEF_GM( return new AttributesGM(); )
} // namespace skiagm

View File

@ -84,7 +84,7 @@ private:
ClockwiseTestProcessor(bool readSkFragCoord)
: GrGeometryProcessor(kClockwiseTestProcessor_ClassID)
, fReadSkFragCoord(readSkFragCoord) {
this->setVertexAttributes(&gVertex, 1);
this->setVertexAttributesWithImplicitOffsets(&gVertex, 1);
}
const bool fReadSkFragCoord;

View File

@ -77,7 +77,7 @@ private:
FwidthSquircleTestProcessor(const SkMatrix& viewMatrix)
: GrGeometryProcessor(kFwidthSquircleTestProcessor_ClassID)
, fViewMatrix(viewMatrix) {
this->setVertexAttributes(&gVertex, 1);
this->setVertexAttributesWithImplicitOffsets(&gVertex, 1);
}
const SkMatrix fViewMatrix;

View File

@ -55,7 +55,7 @@ class TessellationTestTriShader : public GrGeometryProcessor {
public:
TessellationTestTriShader(const SkMatrix& viewMatrix)
: GrGeometryProcessor(kTessellationTestTriShader_ClassID), fViewMatrix(viewMatrix) {
this->setVertexAttributes(&kPositionAttrib, 1);
this->setVertexAttributesWithImplicitOffsets(&kPositionAttrib, 1);
this->setWillUseTessellationShaders();
}

View File

@ -27,6 +27,7 @@ gm_sources = [
"$_gm/arcto.cpp",
"$_gm/arithmode.cpp",
"$_gm/asyncrescaleandread.cpp",
"$_gm/attributes.cpp",
"$_gm/b_119394958.cpp",
"$_gm/backdrop.cpp",
"$_gm/backdrop_imagefilter_croprect.cpp",

View File

@ -223,7 +223,7 @@ private:
if (fFlags & kCoverageAttribute_GPFlag) {
fInCoverage = {"inCoverage", kFloat_GrVertexAttribType, kHalf_GrSLType};
}
this->setVertexAttributes(&fInPosition, 4);
this->setVertexAttributesWithImplicitOffsets(&fInPosition, 4);
}
Attribute fInPosition;

View File

@ -486,3 +486,89 @@ void ProgramImpl::WriteLocalCoord(GrGLSLVertexBuilder* vertBuilder,
&gpArgs->fLocalCoordVar,
localMatrixUniform);
}
//////////////////////////////////////////////////////////////////////////////
using Attribute = GrGeometryProcessor::Attribute;
using AttributeSet = GrGeometryProcessor::AttributeSet;
GrGeometryProcessor::Attribute AttributeSet::Iter::operator*() const {
if (fCurr->offset().has_value()) {
return *fCurr;
}
return Attribute(fCurr->name(), fCurr->cpuType(), fCurr->gpuType(), fImplicitOffset);
}
void AttributeSet::Iter::operator++() {
if (fRemaining) {
fRemaining--;
fImplicitOffset += Attribute::AlignOffset(fCurr->size());
fCurr++;
this->skipUninitialized();
}
}
void AttributeSet::Iter::skipUninitialized() {
if (!fRemaining) {
fCurr = nullptr;
} else {
while (!fCurr->isInitialized()) {
++fCurr;
}
}
}
void AttributeSet::initImplicit(const Attribute* attrs, int count) {
fAttributes = attrs;
fRawCount = count;
fCount = 0;
fStride = 0;
for (int i = 0; i < count; ++i) {
if (attrs[i].isInitialized()) {
fCount++;
fStride += Attribute::AlignOffset(attrs[i].size());
}
}
}
void AttributeSet::initExplicit(const Attribute* attrs, int count, size_t stride) {
fAttributes = attrs;
fRawCount = count;
fCount = count;
fStride = stride;
SkASSERT(Attribute::AlignOffset(fStride) == fStride);
for (int i = 0; i < count; ++i) {
SkASSERT(attrs[i].isInitialized());
SkASSERT(attrs[i].offset().has_value());
SkASSERT(Attribute::AlignOffset(*attrs[i].offset()) == *attrs[i].offset());
SkASSERT(*attrs[i].offset() + attrs[i].size() <= fStride);
}
}
void AttributeSet::addToKey(GrProcessorKeyBuilder* b) const {
int rawCount = SkAbs32(fRawCount);
b->addBits(16, SkToU16(this->stride()), "stride");
b->addBits(16, rawCount, "attribute count");
size_t implicitOffset = 0;
for (int i = 0; i < rawCount; ++i) {
const Attribute& attr = fAttributes[i];
b->appendComment(attr.isInitialized() ? attr.name() : "unusedAttr");
static_assert(kGrVertexAttribTypeCount < (1 << 8), "");
static_assert(kGrSLTypeCount < (1 << 8), "");
b->addBits(8, attr.isInitialized() ? attr.cpuType() : 0xff, "attrType");
b->addBits(8 , attr.isInitialized() ? attr.gpuType() : 0xff, "attrGpuType");
int16_t offset = -1;
if (attr.isInitialized()) {
if (attr.offset().has_value()) {
offset = *attr.offset();
} else {
offset = implicitOffset;
implicitOffset += Attribute::AlignOffset(attr.size());
}
}
b->addBits(16, static_cast<uint16_t>(offset), "attrOffset");
}
}
AttributeSet::Iter AttributeSet::begin() const { return Iter(fAttributes, fCount); }
AttributeSet::Iter AttributeSet::end() const { return Iter(); }

View File

@ -63,98 +63,111 @@ public:
/** Describes a vertex or instance attribute. */
class Attribute {
public:
static constexpr size_t AlignOffset(size_t offset) { return SkAlign4(offset); }
constexpr Attribute() = default;
/**
* Makes an attribute whose offset will be implicitly determined by the types and ordering
* of an array attributes.
*/
constexpr Attribute(const char* name,
GrVertexAttribType cpuType,
GrSLType gpuType)
: fName(name), fCPUType(cpuType), fGPUType(gpuType) {
SkASSERT(name && gpuType != kVoid_GrSLType);
}
/**
* Makes an attribute with an explicit offset.
*/
constexpr Attribute(const char* name,
GrVertexAttribType cpuType,
GrSLType gpuType,
size_t offset)
: fName(name), fCPUType(cpuType), fGPUType(gpuType), fOffset(SkToU32(offset)) {
SkASSERT(AlignOffset(offset) == offset);
SkASSERT(name && gpuType != kVoid_GrSLType);
}
constexpr Attribute(const Attribute&) = default;
Attribute& operator=(const Attribute&) = default;
constexpr bool isInitialized() const { return fGPUType != kVoid_GrSLType; }
constexpr const char* name() const { return fName; }
constexpr const char* name() const { return fName; }
constexpr GrVertexAttribType cpuType() const { return fCPUType; }
constexpr GrSLType gpuType() const { return fGPUType; }
/**
* Returns the offset if attributes were specified with explicit offsets. Otherwise,
* offsets (and total vertex stride) are implicitly determined from attribute order and
* types.
*/
skstd::optional<size_t> offset() const {
if (fOffset != kImplicitOffset) {
SkASSERT(AlignOffset(fOffset) == fOffset);
return {fOffset};
}
return skstd::nullopt;
}
inline constexpr size_t size() const;
constexpr size_t sizeAlign4() const { return SkAlign4(this->size()); }
GrShaderVar asShaderVar() const {
return {fName, fGPUType, GrShaderVar::TypeModifier::In};
}
private:
const char* fName = nullptr;
static constexpr uint32_t kImplicitOffset = 1; // 1 is not valid because it isn't aligned.
const char* fName = nullptr;
GrVertexAttribType fCPUType = kFloat_GrVertexAttribType;
GrSLType fGPUType = kVoid_GrSLType;
GrSLType fGPUType = kVoid_GrSLType;
uint32_t fOffset = kImplicitOffset;
};
class Iter {
public:
Iter() : fCurr(nullptr), fRemaining(0) {}
Iter(const Iter& iter) : fCurr(iter.fCurr), fRemaining(iter.fRemaining) {}
Iter& operator= (const Iter& iter) {
fCurr = iter.fCurr;
fRemaining = iter.fRemaining;
return *this;
}
Iter(const Attribute* attrs, int count) : fCurr(attrs), fRemaining(count) {
this->skipUninitialized();
}
/**
* A set of attributes that can iterated. The iterator handles hides two pieces of complexity:
* 1) It skips uninitialized attributes.
* 2) It always returns an attribute with a known offset.
*/
class AttributeSet {
class Iter {
public:
Iter() = default;
Iter(const Iter& iter) = default;
Iter& operator=(const Iter& iter) = default;
bool operator!=(const Iter& that) const { return fCurr != that.fCurr; }
const Attribute& operator*() const { return *fCurr; }
void operator++() {
if (fRemaining) {
fRemaining--;
fCurr++;
Iter(const Attribute* attrs, int count) : fCurr(attrs), fRemaining(count) {
this->skipUninitialized();
}
}
private:
void skipUninitialized() {
if (!fRemaining) {
fCurr = nullptr;
} else {
while (!fCurr->isInitialized()) {
++fCurr;
}
}
}
bool operator!=(const Iter& that) const { return fCurr != that.fCurr; }
Attribute operator*() const;
void operator++();
const Attribute* fCurr;
int fRemaining;
};
private:
void skipUninitialized();
const Attribute* fCurr = nullptr;
int fRemaining = 0;
size_t fImplicitOffset = 0;
};
class AttributeSet {
public:
Iter begin() const { return Iter(fAttributes, fCount); }
Iter end() const { return Iter(); }
Iter begin() const;
Iter end() const;
int count() const { return fCount; }
size_t stride() const { return fStride; }
// Init with implicit offsets and stride. No attributes can have a predetermined stride.
void initImplicit(const Attribute* attrs, int count);
// Init with explicit offsets and stride. All attributes must be initialized and have
// an explicit offset aligned to 4 bytes and with no attribute crossing stride boundaries.
void initExplicit(const Attribute* attrs, int count, size_t stride);
void addToKey(GrProcessorKeyBuilder* b) const;
private:
friend class GrGeometryProcessor;
void init(const Attribute* attrs, int count) {
fAttributes = attrs;
fRawCount = count;
fCount = 0;
fStride = 0;
for (int i = 0; i < count; ++i) {
if (attrs[i].isInitialized()) {
fCount++;
fStride += attrs[i].sizeAlign4();
}
}
}
const Attribute* fAttributes = nullptr;
int fRawCount = 0;
int fCount = 0;
@ -165,21 +178,21 @@ public:
int numTextureSamplers() const { return fTextureSamplerCnt; }
const TextureSampler& textureSampler(int index) const;
int numVertexAttributes() const { return fVertexAttributes.fCount; }
int numVertexAttributes() const { return fVertexAttributes.count(); }
const AttributeSet& vertexAttributes() const { return fVertexAttributes; }
int numInstanceAttributes() const { return fInstanceAttributes.fCount; }
int numInstanceAttributes() const { return fInstanceAttributes.count(); }
const AttributeSet& instanceAttributes() const { return fInstanceAttributes; }
bool hasVertexAttributes() const { return SkToBool(fVertexAttributes.fCount); }
bool hasInstanceAttributes() const { return SkToBool(fInstanceAttributes.fCount); }
bool hasVertexAttributes() const { return SkToBool(fVertexAttributes.count()); }
bool hasInstanceAttributes() const { return SkToBool(fInstanceAttributes.count()); }
/**
* A common practice is to populate the the vertex/instance's memory using an implicit array of
* structs. In this case, it is best to assert that:
* stride == sizeof(struct)
*/
size_t vertexStride() const { return fVertexAttributes.fStride; }
size_t instanceStride() const { return fInstanceAttributes.fStride; }
size_t vertexStride() const { return fVertexAttributes.stride(); }
size_t instanceStride() const { return fInstanceAttributes.stride(); }
bool willUseTessellationShaders() const {
return fShaders & (kTessControl_GrShaderFlag | kTessEvaluation_GrShaderFlag);
@ -200,23 +213,10 @@ public:
virtual void addToKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const = 0;
void getAttributeKey(GrProcessorKeyBuilder* b) const {
// Ensure that our CPU and GPU type fields fit together in a 32-bit value, and we never
// collide with the "uninitialized" value.
static_assert(kGrVertexAttribTypeCount < (1 << 8), "");
static_assert(kGrSLTypeCount < (1 << 8), "");
auto add_attributes = [=](const Attribute* attrs, int attrCount) {
for (int i = 0; i < attrCount; ++i) {
const Attribute& attr = attrs[i];
b->appendComment(attr.isInitialized() ? attr.name() : "unusedAttr");
b->addBits(8, attr.isInitialized() ? attr.cpuType() : 0xff, "attrType");
b->addBits(8, attr.isInitialized() ? attr.gpuType() : 0xff, "attrGpuType");
}
};
b->add32(fVertexAttributes.fRawCount, "numVertexAttributes");
add_attributes(fVertexAttributes.fAttributes, fVertexAttributes.fRawCount);
b->add32(fInstanceAttributes.fRawCount, "numInstanceAttributes");
add_attributes(fInstanceAttributes.fAttributes, fInstanceAttributes.fRawCount);
b->appendComment("vertex attributes");
fVertexAttributes.addToKey(b);
b->appendComment("instance attributes");
fInstanceAttributes.addToKey(b);
}
/**
@ -233,13 +233,20 @@ protected:
wideColor ? kFloat4_GrVertexAttribType : kUByte4_norm_GrVertexAttribType,
kHalf4_GrSLType };
}
void setVertexAttributes(const Attribute* attrs, int attrCount) {
fVertexAttributes.init(attrs, attrCount);
void setVertexAttributes(const Attribute* attrs, int attrCount, size_t stride) {
fVertexAttributes.initExplicit(attrs, attrCount, stride);
}
void setInstanceAttributes(const Attribute* attrs, int attrCount) {
void setInstanceAttributes(const Attribute* attrs, int attrCount, size_t stride) {
SkASSERT(attrCount >= 0);
fInstanceAttributes.init(attrs, attrCount);
fInstanceAttributes.initExplicit(attrs, attrCount, stride);
}
void setVertexAttributesWithImplicitOffsets(const Attribute* attrs, int attrCount) {
fVertexAttributes.initImplicit(attrs, attrCount);
}
void setInstanceAttributesWithImplicitOffsets(const Attribute* attrs, int attrCount) {
SkASSERT(attrCount >= 0);
fInstanceAttributes.initImplicit(attrs, attrCount);
}
void setWillUseTessellationShaders() {
fShaders |= kTessControl_GrShaderFlag | kTessEvaluation_GrShaderFlag;

View File

@ -32,6 +32,7 @@ public:
enum ClassID {
kNull_ClassID, // Reserved ID for missing (null) processors
kAttributeTestProcessor_ClassID,
kBigKeyProcessor_ClassID,
kBlendFragmentProcessor_ClassID,
kBlockInputFragmentProcessor_ClassID,

View File

@ -245,32 +245,26 @@ static void setup_vertex_input_layout(const GrGeometryProcessor& geomProc,
}
unsigned int currentAttrib = 0;
unsigned int vertexAttributeOffset = 0;
for (const auto& attrib : geomProc.vertexAttributes()) {
for (auto attrib : geomProc.vertexAttributes()) {
// When using SPIRV-Cross it converts the location modifier in SPIRV to be
// TEXCOORD<N> where N is the location value for eveery vertext attribute
inputElements[currentAttrib] = { "TEXCOORD", currentAttrib,
attrib_type_to_format(attrib.cpuType()),
vertexSlot, vertexAttributeOffset,
vertexSlot, SkToU32(*attrib.offset()),
D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 };
vertexAttributeOffset += attrib.sizeAlign4();
currentAttrib++;
}
SkASSERT(vertexAttributeOffset == geomProc.vertexStride());
unsigned int instanceAttributeOffset = 0;
for (const auto& attrib : geomProc.instanceAttributes()) {
for (auto attrib : geomProc.instanceAttributes()) {
// When using SPIRV-Cross it converts the location modifier in SPIRV to be
// TEXCOORD<N> where N is the location value for eveery vertext attribute
inputElements[currentAttrib] = { "TEXCOORD", currentAttrib,
attrib_type_to_format(attrib.cpuType()),
instanceSlot, instanceAttributeOffset,
instanceSlot, SkToU32(*attrib.offset()),
D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA, 1 };
instanceAttributeOffset += attrib.sizeAlign4();
currentAttrib++;
}
SkASSERT(instanceAttributeOffset == geomProc.instanceStride());
}
static D3D12_BLEND blend_coeff_to_d3d_blend(GrBlendCoeff coeff) {

View File

@ -338,18 +338,16 @@ sk_sp<GrDawnProgram> GrDawnProgramBuilder::Build(GrDawnGpu* gpu,
const GrGeometryProcessor& geomProc = programInfo.geomProc();
int i = 0;
if (geomProc.numVertexAttributes() > 0) {
size_t offset = 0;
for (const auto& attrib : geomProc.vertexAttributes()) {
for (auto attrib : geomProc.vertexAttributes()) {
wgpu::VertexAttribute attribute;
attribute.shaderLocation = i;
attribute.offset = offset;
attribute.offset = *attrib.offset();
attribute.format = to_dawn_vertex_format(attrib.cpuType());
vertexAttributes.push_back(attribute);
offset += attrib.sizeAlign4();
i++;
}
wgpu::VertexBufferLayout input;
input.arrayStride = offset;
input.arrayStride = geomProc.vertexStride();
input.stepMode = wgpu::VertexStepMode::Vertex;
input.attributeCount = vertexAttributes.size();
input.attributes = &vertexAttributes.front();
@ -357,18 +355,16 @@ sk_sp<GrDawnProgram> GrDawnProgramBuilder::Build(GrDawnGpu* gpu,
}
std::vector<wgpu::VertexAttribute> instanceAttributes;
if (geomProc.numInstanceAttributes() > 0) {
size_t offset = 0;
for (const auto& attrib : geomProc.instanceAttributes()) {
for (auto attrib : geomProc.instanceAttributes()) {
wgpu::VertexAttribute attribute;
attribute.shaderLocation = i;
attribute.offset = offset;
attribute.offset = *attrib.offset();
attribute.format = to_dawn_vertex_format(attrib.cpuType());
instanceAttributes.push_back(attribute);
offset += attrib.sizeAlign4();
i++;
}
wgpu::VertexBufferLayout input;
input.arrayStride = offset;
input.arrayStride = geomProc.instanceStride();
input.stepMode = wgpu::VertexStepMode::Instance;
input.attributeCount = instanceAttributes.size();
input.attributes = &instanceAttributes.front();

View File

@ -175,7 +175,7 @@ GrConicEffect::GrConicEffect(const SkPMColor4f& color, const SkMatrix& viewMatri
, fLocalMatrix(viewMatrix)
, fUsesLocalCoords(usesLocalCoords)
, fCoverageScale(coverage) {
this->setVertexAttributes(kAttributes, SK_ARRAY_COUNT(kAttributes));
this->setVertexAttributesWithImplicitOffsets(kAttributes, SK_ARRAY_COUNT(kAttributes));
}
//////////////////////////////////////////////////////////////////////////////
@ -328,7 +328,7 @@ GrQuadEffect::GrQuadEffect(const SkPMColor4f& color, const SkMatrix& viewMatrix,
, fLocalMatrix(localMatrix)
, fUsesLocalCoords(usesLocalCoords)
, fCoverageScale(coverage) {
this->setVertexAttributes(kAttributes, SK_ARRAY_COUNT(kAttributes));
this->setVertexAttributesWithImplicitOffsets(kAttributes, SK_ARRAY_COUNT(kAttributes));
}
//////////////////////////////////////////////////////////////////////////////

View File

@ -140,7 +140,7 @@ GrBitmapTextGeoProc::GrBitmapTextGeoProc(const GrShaderCaps& caps,
fInTextureCoords = {"inTextureCoords", kUShort2_GrVertexAttribType,
caps.integerSupport() ? kUShort2_GrSLType : kFloat2_GrSLType};
this->setVertexAttributes(&fInPosition, 3);
this->setVertexAttributesWithImplicitOffsets(&fInPosition, 3);
if (numActiveViews) {
fAtlasDimensions = views[0].proxy()->dimensions();

View File

@ -228,7 +228,7 @@ GrDistanceFieldA8TextGeoProc::GrDistanceFieldA8TextGeoProc(const GrShaderCaps& c
fInColor = {"inColor", kUByte4_norm_GrVertexAttribType, kHalf4_GrSLType };
fInTextureCoords = {"inTextureCoords", kUShort2_GrVertexAttribType,
caps.integerSupport() ? kUShort2_GrSLType : kFloat2_GrSLType};
this->setVertexAttributes(&fInPosition, 3);
this->setVertexAttributesWithImplicitOffsets(&fInPosition, 3);
if (numViews) {
fAtlasDimensions = views[0].proxy()->dimensions();
@ -494,7 +494,7 @@ GrDistanceFieldPathGeoProc::GrDistanceFieldPathGeoProc(const GrShaderCaps& caps,
fInColor = MakeColorAttribute("inColor", wideColor);
fInTextureCoords = {"inTextureCoords", kUShort2_GrVertexAttribType,
caps.integerSupport() ? kUShort2_GrSLType : kFloat2_GrSLType};
this->setVertexAttributes(&fInPosition, 3);
this->setVertexAttributesWithImplicitOffsets(&fInPosition, 3);
if (numViews) {
fAtlasDimensions = views[0].proxy()->dimensions();
@ -807,7 +807,7 @@ GrDistanceFieldLCDTextGeoProc::GrDistanceFieldLCDTextGeoProc(const GrShaderCaps&
fInColor = {"inColor", kUByte4_norm_GrVertexAttribType, kHalf4_GrSLType};
fInTextureCoords = {"inTextureCoords", kUShort2_GrVertexAttribType,
caps.integerSupport() ? kUShort2_GrSLType : kFloat2_GrSLType};
this->setVertexAttributes(&fInPosition, 3);
this->setVertexAttributesWithImplicitOffsets(&fInPosition, 3);
if (numViews) {
fAtlasDimensions = views[0].proxy()->dimensions();

View File

@ -56,7 +56,7 @@ GrRRectShadowGeoProc::GrRRectShadowGeoProc(const GrSurfaceProxyView& lutView)
fInPosition = {"inPosition", kFloat2_GrVertexAttribType, kFloat2_GrSLType};
fInColor = {"inColor", kUByte4_norm_GrVertexAttribType, kHalf4_GrSLType};
fInShadowParams = {"inShadowParams", kFloat3_GrVertexAttribType, kHalf3_GrSLType};
this->setVertexAttributes(&fInPosition, 3);
this->setVertexAttributesWithImplicitOffsets(&fInPosition, 3);
SkASSERT(lutView.proxy());
fLUTTextureSampler.reset(GrSamplerState::Filter::kLinear, lutView.proxy()->backendFormat(),

View File

@ -123,25 +123,23 @@ void GrGLProgramBuilder::computeCountsAndStrides(GrGLuint programID,
fInstanceAttributeCnt = geomProc.numInstanceAttributes();
fAttributes = std::make_unique<GrGLProgram::Attribute[]>(
fVertexAttributeCnt + fInstanceAttributeCnt);
auto addAttr = [&](int i, const auto& a, size_t* stride) {
auto addAttr = [&](int i, const auto& a) {
fAttributes[i].fCPUType = a.cpuType();
fAttributes[i].fGPUType = a.gpuType();
fAttributes[i].fOffset = *stride;
*stride += a.sizeAlign4();
fAttributes[i].fOffset = *a.offset();
fAttributes[i].fLocation = i;
if (bindAttribLocations) {
GL_CALL(BindAttribLocation(programID, i, a.name()));
}
};
fVertexStride = 0;
fVertexStride = geomProc.vertexStride();
int i = 0;
for (const auto& attr : geomProc.vertexAttributes()) {
addAttr(i++, attr, &fVertexStride);
for (auto attr : geomProc.vertexAttributes()) {
addAttr(i++, attr);
}
SkASSERT(fVertexStride == geomProc.vertexStride());
fInstanceStride = 0;
for (const auto& attr : geomProc.instanceAttributes()) {
addAttr(i++, attr, &fInstanceStride);
fInstanceStride = geomProc.instanceStride();
for (auto attr : geomProc.instanceAttributes()) {
addAttr(i++, attr);
}
SkASSERT(fInstanceStride == geomProc.instanceStride());
}
@ -192,10 +190,10 @@ void GrGLProgramBuilder::storeShaderInCache(const SkSL::Program::Inputs& inputs,
meta.fSettings = settings;
meta.fHasCustomColorOutput = fFS.hasCustomColorOutput();
meta.fHasSecondaryColorOutput = fFS.hasSecondaryOutput();
for (const auto& attr : this->geometryProcessor().vertexAttributes()) {
for (auto attr : this->geometryProcessor().vertexAttributes()) {
meta.fAttributeNames.emplace_back(attr.name());
}
for (const auto& attr : this->geometryProcessor().instanceAttributes()) {
for (auto attr : this->geometryProcessor().instanceAttributes()) {
meta.fAttributeNames.emplace_back(attr.name());
}

View File

@ -58,10 +58,10 @@ void GrGLSLVaryingHandler::addVarying(const char* name, GrGLSLVarying* varying,
}
void GrGLSLVaryingHandler::emitAttributes(const GrGeometryProcessor& gp) {
for (const auto& attr : gp.vertexAttributes()) {
for (auto attr : gp.vertexAttributes()) {
this->addAttribute(attr.asShaderVar());
}
for (const auto& attr : gp.instanceAttributes()) {
for (auto attr : gp.instanceAttributes()) {
this->addAttribute(attr.asShaderVar());
}
}

View File

@ -199,33 +199,30 @@ static MTLVertexDescriptor* create_vertex_descriptor(const GrGeometryProcessor&
if (writer) {
writer->writeInt(vertexAttributeCount);
}
size_t vertexAttributeOffset = 0;
for (const auto& attribute : geomProc.vertexAttributes()) {
for (auto attribute : geomProc.vertexAttributes()) {
MTLVertexAttributeDescriptor* mtlAttribute = vertexDescriptor.attributes[attributeIndex];
MTLVertexFormat format = attribute_type_to_mtlformat(attribute.cpuType());
SkASSERT(MTLVertexFormatInvalid != format);
mtlAttribute.format = format;
mtlAttribute.offset = vertexAttributeOffset;
mtlAttribute.offset = *attribute.offset();
mtlAttribute.bufferIndex = vertexBinding;
if (writer) {
writer->writeInt(format);
writer->writeUInt(vertexAttributeOffset);
writer->writeUInt(*attribute.offset());
writer->writeUInt(vertexBinding);
}
vertexAttributeOffset += attribute.sizeAlign4();
attributeIndex++;
}
SkASSERT(vertexAttributeOffset == geomProc.vertexStride());
if (vertexAttributeCount) {
MTLVertexBufferLayoutDescriptor* vertexBufferLayout =
vertexDescriptor.layouts[vertexBinding];
vertexBufferLayout.stepFunction = MTLVertexStepFunctionPerVertex;
vertexBufferLayout.stepRate = 1;
vertexBufferLayout.stride = vertexAttributeOffset;
vertexBufferLayout.stride = geomProc.vertexStride();
if (writer) {
writer->writeUInt(vertexAttributeOffset);
writer->writeUInt(geomProc.vertexStride());
}
}
@ -233,33 +230,30 @@ static MTLVertexDescriptor* create_vertex_descriptor(const GrGeometryProcessor&
if (writer) {
writer->writeInt(instanceAttributeCount);
}
size_t instanceAttributeOffset = 0;
for (const auto& attribute : geomProc.instanceAttributes()) {
for (auto attribute : geomProc.instanceAttributes()) {
MTLVertexAttributeDescriptor* mtlAttribute = vertexDescriptor.attributes[attributeIndex];
MTLVertexFormat format = attribute_type_to_mtlformat(attribute.cpuType());
SkASSERT(MTLVertexFormatInvalid != format);
mtlAttribute.format = format;
mtlAttribute.offset = instanceAttributeOffset;
mtlAttribute.offset = *attribute.offset();
mtlAttribute.bufferIndex = instanceBinding;
if (writer) {
writer->writeInt(format);
writer->writeUInt(instanceAttributeOffset);
writer->writeUInt(*attribute.offset());
writer->writeUInt(instanceBinding);
}
instanceAttributeOffset += attribute.sizeAlign4();
attributeIndex++;
}
SkASSERT(instanceAttributeOffset == geomProc.instanceStride());
if (instanceAttributeCount) {
MTLVertexBufferLayoutDescriptor* instanceBufferLayout =
vertexDescriptor.layouts[instanceBinding];
instanceBufferLayout.stepFunction = MTLVertexStepFunctionPerInstance;
instanceBufferLayout.stepRate = 1;
instanceBufferLayout.stride = instanceAttributeOffset;
instanceBufferLayout.stride = geomProc.instanceStride();
if (writer) {
writer->writeUInt(instanceAttributeOffset);
writer->writeUInt(geomProc.instanceStride());
}
}
return vertexDescriptor;

View File

@ -577,7 +577,7 @@ private:
fInColor = MakeColorAttribute("inColor", wideColor);
// GL on iOS 14 needs more precision for the quadedge attributes
fInQuadEdge = {"inQuadEdge", kFloat4_GrVertexAttribType, kFloat4_GrSLType};
this->setVertexAttributes(&fInPosition, 3);
this->setVertexAttributesWithImplicitOffsets(&fInPosition, 3);
}
Attribute fInPosition;

View File

@ -867,7 +867,7 @@ DashingCircleEffect::DashingCircleEffect(const SkPMColor4f& color,
fInPosition = {"inPosition", kFloat2_GrVertexAttribType, kFloat2_GrSLType};
fInDashParams = {"inDashParams", kFloat3_GrVertexAttribType, kHalf3_GrSLType};
fInCircleParams = {"inCircleParams", kFloat2_GrVertexAttribType, kHalf2_GrSLType};
this->setVertexAttributes(&fInPosition, 3);
this->setVertexAttributesWithImplicitOffsets(&fInPosition, 3);
}
GR_DEFINE_GEOMETRY_PROCESSOR_TEST(DashingCircleEffect);
@ -1081,7 +1081,7 @@ DashingLineEffect::DashingLineEffect(const SkPMColor4f& color,
fInPosition = {"inPosition", kFloat2_GrVertexAttribType, kFloat2_GrSLType};
fInDashParams = {"inDashParams", kFloat3_GrVertexAttribType, kHalf3_GrSLType};
fInRect = {"inRect", kFloat4_GrVertexAttribType, kHalf4_GrSLType};
this->setVertexAttributes(&fInPosition, 3);
this->setVertexAttributesWithImplicitOffsets(&fInPosition, 3);
}
GR_DEFINE_GEOMETRY_PROCESSOR_TEST(DashingLineEffect);

View File

@ -33,7 +33,7 @@ public:
if (!shaderCaps.vertexIDSupport()) {
constexpr static Attribute kUnitCoordAttrib(
"unitCoord", kFloat2_GrVertexAttribType, kFloat2_GrSLType);
this->setVertexAttributes(&kUnitCoordAttrib, 1);
this->setVertexAttributesWithImplicitOffsets(&kUnitCoordAttrib, 1);
}
fAttribs.emplace_back("fillBounds", kFloat4_GrVertexAttribType, kFloat4_GrSLType);
if (fUsesLocalCoords) {
@ -44,7 +44,7 @@ public:
fAttribs.emplace_back("color", kFloat4_GrVertexAttribType, kHalf4_GrSLType);
fAtlasHelper->appendInstanceAttribs(&fAttribs);
SkASSERT(fAttribs.count() <= kMaxInstanceAttribs);
this->setInstanceAttributes(fAttribs.data(), fAttribs.count());
this->setInstanceAttributesWithImplicitOffsets(fAttribs.data(), fAttribs.count());
this->setTextureSamplerCnt(1);
}

View File

@ -174,7 +174,7 @@ private:
? Attribute{"inLocalCoord", kFloat2_GrVertexAttribType, kFloat2_GrSLType}
: missingAttr);
this->setVertexAttributes(fAttributes.data(), fAttributes.size());
this->setVertexAttributesWithImplicitOffsets(fAttributes.data(), fAttributes.size());
}
enum {

View File

@ -353,7 +353,8 @@ private:
Processor(GrAAType aaType, ProcessorFlags flags)
: GrGeometryProcessor(kGrFillRRectOp_Processor_ClassID)
, fFlags(flags) {
this->setVertexAttributes(kVertexAttribs, SK_ARRAY_COUNT(kVertexAttribs));
this->setVertexAttributesWithImplicitOffsets(kVertexAttribs,
SK_ARRAY_COUNT(kVertexAttribs));
fInstanceAttribs.emplace_back("skew", kFloat4_GrVertexAttribType, kFloat4_GrSLType);
fInstanceAttribs.emplace_back("translate", kFloat2_GrVertexAttribType, kFloat2_GrSLType);
@ -366,7 +367,8 @@ private:
"local_rect", kFloat4_GrVertexAttribType, kFloat4_GrSLType);
}
SkASSERT(fInstanceAttribs.count() <= kMaxInstanceAttribs);
this->setInstanceAttributes(fInstanceAttribs.begin(), fInstanceAttribs.count());
this->setInstanceAttributesWithImplicitOffsets(fInstanceAttribs.begin(),
fInstanceAttribs.count());
}
inline static constexpr Attribute kVertexAttribs[] = {

View File

@ -118,7 +118,7 @@ private:
fInRoundCapCenters =
{"inRoundCapCenters", kFloat4_GrVertexAttribType, kFloat4_GrSLType};
}
this->setVertexAttributes(&fInPosition, 7);
this->setVertexAttributesWithImplicitOffsets(&fInPosition, 7);
}
class Impl : public ProgramImpl {
@ -298,7 +298,7 @@ private:
fInColor = MakeColorAttribute("inColor", wideColor);
fInCircleEdge = {"inCircleEdge", kFloat4_GrVertexAttribType, kFloat4_GrSLType};
fInDashParams = {"inDashParams", kFloat4_GrVertexAttribType, kFloat4_GrSLType};
this->setVertexAttributes(&fInPosition, 4);
this->setVertexAttributesWithImplicitOffsets(&fInPosition, 4);
}
class Impl : public ProgramImpl {
@ -562,7 +562,7 @@ private:
fInEllipseOffset = {"inEllipseOffset", kFloat2_GrVertexAttribType, kFloat2_GrSLType};
}
fInEllipseRadii = {"inEllipseRadii", kFloat4_GrVertexAttribType, kFloat4_GrSLType};
this->setVertexAttributes(&fInPosition, 4);
this->setVertexAttributesWithImplicitOffsets(&fInPosition, 4);
}
class Impl : public ProgramImpl {
@ -761,7 +761,7 @@ private:
kFloat2_GrSLType};
}
fInEllipseOffsets1 = {"inEllipseOffsets1", kFloat2_GrVertexAttribType, kFloat2_GrSLType};
this->setVertexAttributes(&fInPosition, 4);
this->setVertexAttributesWithImplicitOffsets(&fInPosition, 4);
}
class Impl : public ProgramImpl {

View File

@ -111,7 +111,7 @@ private:
fInTextureCoords = {"textureCoords", kFloat2_GrVertexAttribType, kFloat2_GrSLType};
fInTextureDomain = {"textureDomain", kFloat4_GrVertexAttribType, kFloat4_GrSLType};
fInColor = MakeColorAttribute("color", wideColor);
this->setVertexAttributes(&fInPosition, 4);
this->setVertexAttributesWithImplicitOffsets(&fInPosition, 4);
}
const TextureSampler& onTextureSampler(int) const override { return fSampler; }

View File

@ -36,13 +36,14 @@ public:
// each patch that explicitly tells the shader what type of curve it is.
fInstanceAttribs.emplace_back("curveType", kFloat_GrVertexAttribType, kFloat_GrSLType);
}
this->setInstanceAttributes(fInstanceAttribs.data(), fInstanceAttribs.count());
this->setInstanceAttributesWithImplicitOffsets(fInstanceAttribs.data(),
fInstanceAttribs.count());
SkASSERT(fInstanceAttribs.count() <= kMaxInstanceAttribCount);
if (!shaderCaps.vertexIDSupport()) {
constexpr static Attribute kVertexIdxAttrib("vertexidx", kFloat_GrVertexAttribType,
kFloat_GrSLType);
this->setVertexAttributes(&kVertexIdxAttrib, 1);
this->setVertexAttributesWithImplicitOffsets(&kVertexIdxAttrib, 1);
}
}

View File

@ -36,14 +36,15 @@ public:
if (!shaderCaps.vertexIDSupport()) {
constexpr static Attribute kUnitCoordAttrib("unitCoord", kFloat2_GrVertexAttribType,
kFloat2_GrSLType);
this->setVertexAttributes(&kUnitCoordAttrib, 1);
this->setVertexAttributesWithImplicitOffsets(&kUnitCoordAttrib, 1);
}
constexpr static Attribute kInstanceAttribs[] = {
{"matrix2d", kFloat4_GrVertexAttribType, kFloat4_GrSLType},
{"translate", kFloat2_GrVertexAttribType, kFloat2_GrSLType},
{"pathBounds", kFloat4_GrVertexAttribType, kFloat4_GrSLType}
};
this->setInstanceAttributes(kInstanceAttribs, SK_ARRAY_COUNT(kInstanceAttribs));
this->setInstanceAttributesWithImplicitOffsets(kInstanceAttribs,
SK_ARRAY_COUNT(kInstanceAttribs));
}
private:

View File

@ -894,7 +894,7 @@ private:
fTexSubset = {"texSubset", kFloat4_GrVertexAttribType, kFloat4_GrSLType};
}
this->setVertexAttributes(&fPosition, 6);
this->setVertexAttributesWithImplicitOffsets(&fPosition, 6);
}
const TextureSampler& onTextureSampler(int) const override { return fSampler; }

View File

@ -25,7 +25,7 @@ public:
PatchAttribs::kNone) {
constexpr static Attribute kInputPointAttrib{"inputPoint", kFloat2_GrVertexAttribType,
kFloat2_GrSLType};
this->setVertexAttributes(&kInputPointAttrib, 1);
this->setVertexAttributesWithImplicitOffsets(&kInputPointAttrib, 1);
}
int maxTessellationSegments(const GrShaderCaps&) const override { SkUNREACHABLE; }

View File

@ -39,7 +39,7 @@ public:
GrPrimitiveType::kPatches, 5, viewMatrix, color, attribs) {
constexpr static Attribute kInputPointAttrib{"inputPoint", kFloat2_GrVertexAttribType,
kFloat2_GrSLType};
this->setVertexAttributes(&kInputPointAttrib, 1);
this->setVertexAttributesWithImplicitOffsets(&kInputPointAttrib, 1);
SkASSERT(this->vertexStride() * 5 ==
sizeof(SkPoint) * 4 + skgpu::PatchAttribsStride(fAttribs));
}
@ -180,7 +180,7 @@ public:
attribs) {
constexpr static Attribute kInputPointAttrib{"inputPoint", kFloat2_GrVertexAttribType,
kFloat2_GrSLType};
this->setVertexAttributes(&kInputPointAttrib, 1);
this->setVertexAttributesWithImplicitOffsets(&kInputPointAttrib, 1);
SkASSERT(this->vertexStride() * 4 ==
sizeof(SkPoint) * 4 + skgpu::PatchAttribsStride(fAttribs));
}

View File

@ -56,14 +56,15 @@ public:
// each patch that explicitly tells the shader what type of curve it is.
fInstanceAttribs.emplace_back("curveType", kFloat_GrVertexAttribType, kFloat_GrSLType);
}
this->setInstanceAttributes(fInstanceAttribs.data(), fInstanceAttribs.count());
this->setInstanceAttributesWithImplicitOffsets(fInstanceAttribs.data(),
fInstanceAttribs.count());
SkASSERT(fInstanceAttribs.count() <= kMaxInstanceAttribCount);
SkASSERT(this->instanceStride() ==
sizeof(SkPoint) * 4 + skgpu::PatchAttribsStride(fAttribs));
constexpr static Attribute kVertexAttrib("resolveLevel_and_idx", kFloat2_GrVertexAttribType,
kFloat2_GrSLType);
this->setVertexAttributes(&kVertexAttrib, 1);
this->setVertexAttributesWithImplicitOffsets(&kVertexAttrib, 1);
}
int maxTessellationSegments(const GrShaderCaps&) const override {

View File

@ -91,15 +91,15 @@ GrStrokeTessellationShader::GrStrokeTessellationShader(const GrShaderCaps& shade
fAttribs.emplace_back("curveTypeAttr", kFloat_GrVertexAttribType, kFloat_GrSLType);
}
if (fMode == Mode::kHardwareTessellation) {
this->setVertexAttributes(fAttribs.data(), fAttribs.count());
this->setVertexAttributesWithImplicitOffsets(fAttribs.data(), fAttribs.count());
SkASSERT(this->vertexStride() == sizeof(SkPoint) * 5 + PatchAttribsStride(fPatchAttribs));
} else {
this->setInstanceAttributes(fAttribs.data(), fAttribs.count());
this->setInstanceAttributesWithImplicitOffsets(fAttribs.data(), fAttribs.count());
SkASSERT(this->instanceStride() == sizeof(SkPoint) * 5 + PatchAttribsStride(fPatchAttribs));
if (!shaderCaps.vertexIDSupport()) {
constexpr static Attribute kVertexAttrib("edgeID", kFloat_GrVertexAttribType,
kFloat_GrSLType);
this->setVertexAttributes(&kVertexAttrib, 1);
this->setVertexAttributesWithImplicitOffsets(&kVertexAttrib, 1);
}
}
SkASSERT(fAttribs.count() <= kMaxAttribCount);

View File

@ -100,39 +100,33 @@ static void setup_vertex_input_state(
// setup attribute descriptions
int attribIndex = 0;
size_t vertexAttributeOffset = 0;
for (const auto& attrib : vertexAttribs) {
for (auto attrib : vertexAttribs) {
VkVertexInputAttributeDescription& vkAttrib = attributeDesc[attribIndex];
vkAttrib.location = attribIndex++; // for now assume location = attribIndex
vkAttrib.binding = vertexBinding;
vkAttrib.format = attrib_type_to_vkformat(attrib.cpuType());
vkAttrib.offset = vertexAttributeOffset;
vertexAttributeOffset += attrib.sizeAlign4();
vkAttrib.offset = *attrib.offset();
}
SkASSERT(vertexAttributeOffset == vertexAttribs.stride());
size_t instanceAttributeOffset = 0;
for (const auto& attrib : instanceAttribs) {
for (auto attrib : instanceAttribs) {
VkVertexInputAttributeDescription& vkAttrib = attributeDesc[attribIndex];
vkAttrib.location = attribIndex++; // for now assume location = attribIndex
vkAttrib.binding = instanceBinding;
vkAttrib.format = attrib_type_to_vkformat(attrib.cpuType());
vkAttrib.offset = instanceAttributeOffset;
instanceAttributeOffset += attrib.sizeAlign4();
vkAttrib.offset = *attrib.offset();
}
SkASSERT(instanceAttributeOffset == instanceAttribs.stride());
if (vaCount) {
bindingDescs->push_back() = {
vertexBinding,
(uint32_t) vertexAttributeOffset,
(uint32_t) vertexAttribs.stride(),
VK_VERTEX_INPUT_RATE_VERTEX
};
}
if (iaCount) {
bindingDescs->push_back() = {
instanceBinding,
(uint32_t) instanceAttributeOffset,
(uint32_t) instanceAttribs.stride(),
VK_VERTEX_INPUT_RATE_INSTANCE
};
}

View File

@ -469,15 +469,15 @@ private:
if (instanced) {
fInstanceLocation = {"location", kFloat2_GrVertexAttribType, kHalf2_GrSLType};
fInstanceColor = {"color", kUByte4_norm_GrVertexAttribType, kHalf4_GrSLType};
this->setInstanceAttributes(&fInstanceLocation, 2);
this->setInstanceAttributesWithImplicitOffsets(&fInstanceLocation, 2);
if (hasVertexBuffer) {
fVertexPosition = {"vertex", kFloat2_GrVertexAttribType, kHalf2_GrSLType};
this->setVertexAttributes(&fVertexPosition, 1);
this->setVertexAttributesWithImplicitOffsets(&fVertexPosition, 1);
}
} else {
fVertexPosition = {"vertex", kFloat2_GrVertexAttribType, kHalf2_GrSLType};
fVertexColor = {"color", kUByte4_norm_GrVertexAttribType, kHalf4_GrSLType};
this->setVertexAttributes(&fVertexPosition, 2);
this->setVertexAttributesWithImplicitOffsets(&fVertexPosition, 2);
}
}

View File

@ -72,7 +72,7 @@ public:
private:
PipelineDynamicStateTestProcessor() : INHERITED(kGrPipelineDynamicStateTestProcessor_ClassID) {
this->setVertexAttributes(kAttributes, SK_ARRAY_COUNT(kAttributes));
this->setVertexAttributesWithImplicitOffsets(kAttributes, SK_ARRAY_COUNT(kAttributes));
}
const Attribute& inVertex() const { return kAttributes[0]; }

View File

@ -115,7 +115,7 @@ private:
kFloat2_GrSLType};
}
}
this->setVertexAttributes(fAttributes.get(), numAttribs);
this->setVertexAttributesWithImplicitOffsets(fAttributes.get(), numAttribs);
}
int fNumAttribs;

View File

@ -26,7 +26,7 @@ public:
GP(const SkMatrix& localMatrix, bool wideColor)
: GrGeometryProcessor(kTestRectOp_ClassID), fLocalMatrix(localMatrix) {
fInColor = MakeColorAttribute("color", wideColor);
this->setVertexAttributes(&fInPosition, 3);
this->setVertexAttributesWithImplicitOffsets(&fInPosition, 3);
}
const char* name() const override { return "TestRectOp::GP"; }