Add support for GPU-backed buffers to SkCustomMesh.
The client passes a GrDirectContext* when creating a vertex or index buffer. The data is copied to a GPU accessible buffer object and the client gets a Skia object that may only be used with the GrDirectContext. The GPU backend draws directly from the buffer, thereby avoiding the per-draw copy cost. The underlying Ganesh object is freed in a thread-safe manner using an existing message bus to perform a delayed unref in GrResourceCache. Bug: skia:12720 Change-Id: If2578fbbf094874967a294a095b3bc5d7616d73a Reviewed-on: https://skia-review.googlesource.com/c/skia/+/527918 Reviewed-by: Greg Daniel <egdaniel@google.com> Commit-Queue: Brian Salomon <bsalomon@google.com>
This commit is contained in:
parent
e706ba895c
commit
4cf577899c
@ -3238,7 +3238,9 @@ generated_cc_atom(
|
||||
"//include/core:SkData_hdr",
|
||||
"//include/core:SkSurface_hdr",
|
||||
"//include/effects:SkGradientShader_hdr",
|
||||
"//include/gpu:GrDirectContext_hdr",
|
||||
"//src/core:SkCanvasPriv_hdr",
|
||||
"//src/core:SkCustomMeshPriv_hdr",
|
||||
],
|
||||
)
|
||||
|
||||
|
@ -13,7 +13,9 @@
|
||||
#include "include/core/SkData.h"
|
||||
#include "include/core/SkSurface.h"
|
||||
#include "include/effects/SkGradientShader.h"
|
||||
#include "include/gpu/GrDirectContext.h"
|
||||
#include "src/core/SkCanvasPriv.h"
|
||||
#include "src/core/SkCustomMeshPriv.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
@ -102,31 +104,29 @@ protected:
|
||||
nullptr,
|
||||
2,
|
||||
SkTileMode::kMirror);
|
||||
fColorVB = SkCustomMesh::MakeVertexBuffer(
|
||||
/*GrDirectContext*=*/nullptr,
|
||||
SkData::MakeWithoutCopy(kColorQuad, sizeof(kColorQuad)));
|
||||
}
|
||||
|
||||
// Make this one such that the data is offset into the buffer.
|
||||
auto data = SkData::MakeUninitialized(sizeof(kNoColorQuad) + kNoColorOffset);
|
||||
std::memcpy(SkTAddOffset<void>(data->writable_data(), kNoColorOffset),
|
||||
kNoColorQuad,
|
||||
sizeof(kNoColorQuad));
|
||||
fNoColorVB = SkCustomMesh::MakeVertexBuffer(/*GrDirectContext*=*/nullptr, std::move(data));
|
||||
DrawResult onGpuSetup(GrDirectContext* context, SkString* string) override {
|
||||
this->ensureBuffers();
|
||||
if (!context || context->abandoned()) {
|
||||
return DrawResult::kOk;
|
||||
}
|
||||
|
||||
fColorIndexedVB = SkCustomMesh::MakeVertexBuffer(
|
||||
/*GrDirectContext*=*/nullptr,
|
||||
SkData::MakeWithoutCopy(kColorIndexedQuad, sizeof(kColorIndexedQuad)));
|
||||
fColorVB = SkCustomMesh::MakeVertexBuffer(context, CpuVBAsData(fColorVB));
|
||||
fColorIndexedVB = SkCustomMesh::MakeVertexBuffer(context, CpuVBAsData(fColorIndexedVB));
|
||||
fIB[1] = SkCustomMesh::MakeIndexBuffer (context, CpuIBAsData(fIB[0]));
|
||||
if (!fColorVB || !fColorIndexedVB || !fIB[1]) {
|
||||
return DrawResult::kFail;
|
||||
}
|
||||
return DrawResult::kOk;
|
||||
}
|
||||
|
||||
fNoColorIndexedVB = SkCustomMesh::MakeVertexBuffer(
|
||||
/*GrDirectContext*=*/nullptr,
|
||||
SkData::MakeWithoutCopy(kNoColorIndexedQuad, sizeof(kNoColorIndexedQuad)));
|
||||
|
||||
// Also make index buffer with an offset
|
||||
data = SkData::MakeUninitialized(sizeof(kIndices) + kIndexOffset);
|
||||
std::memcpy(SkTAddOffset<void>(data->writable_data(), kIndexOffset),
|
||||
kIndices,
|
||||
sizeof(kIndices));
|
||||
fIB = SkCustomMesh::MakeIndexBuffer(/*GrDirectContext*=*/nullptr, std::move(data));
|
||||
void onGpuTeardown() override {
|
||||
// Destroy the GPU buffers and recreate on CPU
|
||||
fColorVB = nullptr;
|
||||
fColorIndexedVB = nullptr;
|
||||
fIB[1] = nullptr;
|
||||
this->ensureBuffers();
|
||||
}
|
||||
|
||||
SkString onShortName() override { return SkString("custommesh"); }
|
||||
@ -159,30 +159,30 @@ protected:
|
||||
kRect);
|
||||
}
|
||||
} else {
|
||||
// Alternate between CPU and GPU-backend index buffers.
|
||||
auto ib = (i%4 == 0) ? fIB[0] : fIB[1];
|
||||
if (colors) {
|
||||
cm = SkCustomMesh::MakeIndexed(fSpecWithColor,
|
||||
SkCustomMesh::Mode::kTriangles,
|
||||
fColorIndexedVB,
|
||||
/*vertexCount=*/ 6,
|
||||
/*vertexOffset=*/0,
|
||||
fIB,
|
||||
/*vertexCount=*/6,
|
||||
kColorIndexedOffset,
|
||||
std::move(ib),
|
||||
/*indexCount=*/6,
|
||||
kIndexOffset,
|
||||
kRect);
|
||||
|
||||
} else {
|
||||
cm = SkCustomMesh::MakeIndexed(fSpecWithNoColor,
|
||||
SkCustomMesh::Mode::kTriangles,
|
||||
fNoColorIndexedVB,
|
||||
/*vertexCount=*/ 6,
|
||||
/*vertexOffset=*/0,
|
||||
fIB,
|
||||
std::move(ib),
|
||||
/*indexCount=*/6,
|
||||
kIndexOffset,
|
||||
kRect);
|
||||
}
|
||||
}
|
||||
|
||||
SkPaint paint;
|
||||
paint.setColor(SK_ColorGREEN);
|
||||
paint.setShader(shader ? fShader : nullptr);
|
||||
@ -200,6 +200,66 @@ protected:
|
||||
}
|
||||
|
||||
private:
|
||||
static sk_sp<const SkData> CpuVBAsData(sk_sp<SkCustomMesh::VertexBuffer> buffer) {
|
||||
auto vb = static_cast<SkCustomMeshPriv::VB*>(buffer.get());
|
||||
SkASSERT(vb->asData());
|
||||
return vb->asData();
|
||||
}
|
||||
|
||||
static sk_sp<const SkData> CpuIBAsData(sk_sp<SkCustomMesh::IndexBuffer> buffer) {
|
||||
auto ib = static_cast<SkCustomMeshPriv::IB*>(buffer.get());
|
||||
SkASSERT(ib->asData());
|
||||
return ib->asData();
|
||||
}
|
||||
|
||||
void ensureBuffers() {
|
||||
if (!fColorVB) {
|
||||
fColorVB = SkCustomMesh::MakeVertexBuffer(
|
||||
/*GrDirectContext*=*/nullptr,
|
||||
SkData::MakeWithoutCopy(kColorQuad, sizeof(kColorQuad)));
|
||||
}
|
||||
|
||||
if (!fNoColorVB) {
|
||||
// Make this one such that the data is offset into the buffer.
|
||||
auto data = SkData::MakeUninitialized(sizeof(kNoColorQuad) + kNoColorOffset);
|
||||
std::memcpy(SkTAddOffset<void>(data->writable_data(), kNoColorOffset),
|
||||
kNoColorQuad,
|
||||
sizeof(kNoColorQuad));
|
||||
fNoColorVB = SkCustomMesh::MakeVertexBuffer(/*GrDirectContext*=*/nullptr,
|
||||
std::move(data));
|
||||
}
|
||||
|
||||
if (!fColorIndexedVB) {
|
||||
// This buffer also has an offset.
|
||||
auto data = SkData::MakeUninitialized(sizeof(kColorIndexedQuad) + kColorIndexedOffset);
|
||||
std::memcpy(SkTAddOffset<void>(data->writable_data(), kColorIndexedOffset),
|
||||
kColorIndexedQuad,
|
||||
sizeof(kColorIndexedQuad));
|
||||
fColorIndexedVB = SkCustomMesh::MakeVertexBuffer(/*GrDirectContext*=*/nullptr,
|
||||
std::move(data));
|
||||
}
|
||||
|
||||
if (!fNoColorIndexedVB) {
|
||||
fNoColorIndexedVB = SkCustomMesh::MakeVertexBuffer(
|
||||
/*GrDirectContext*=*/nullptr,
|
||||
SkData::MakeWithoutCopy(kNoColorIndexedQuad, sizeof(kNoColorIndexedQuad)));
|
||||
}
|
||||
|
||||
if (!fIB[0]) {
|
||||
// The index buffer has an offset.
|
||||
auto data = SkData::MakeUninitialized(sizeof(kIndices) + kIndexOffset);
|
||||
std::memcpy(SkTAddOffset<void>(data->writable_data(), kIndexOffset),
|
||||
kIndices,
|
||||
sizeof(kIndices));
|
||||
fIB[0] = SkCustomMesh::MakeIndexBuffer(/*GrDirectContext*=*/nullptr, std::move(data));
|
||||
}
|
||||
|
||||
if (!fIB[1]) {
|
||||
// On CPU we always use the same CPU-backed index buffer.
|
||||
fIB[1] = fIB[0];
|
||||
}
|
||||
}
|
||||
|
||||
struct ColorVertex {
|
||||
uint32_t pad;
|
||||
uint32_t brag;
|
||||
@ -249,15 +309,18 @@ private:
|
||||
|
||||
static constexpr uint16_t kIndices[]{0, 2, 4, 2, 5, 4};
|
||||
|
||||
static constexpr size_t kNoColorOffset = sizeof(NoColorVertex);
|
||||
static constexpr size_t kIndexOffset = 6;
|
||||
// For some buffers we add an offset to ensure we're exercising drawing from mid-buffer.
|
||||
static constexpr size_t kNoColorOffset = sizeof(NoColorVertex);
|
||||
static constexpr size_t kColorIndexedOffset = 2*sizeof(ColorVertex);
|
||||
static constexpr size_t kIndexOffset = 6;
|
||||
|
||||
sk_sp<SkShader> fShader;
|
||||
|
||||
sk_sp<SkCustomMeshSpecification> fSpecWithColor;
|
||||
sk_sp<SkCustomMeshSpecification> fSpecWithNoColor;
|
||||
|
||||
sk_sp<SkCustomMesh::IndexBuffer> fIB;
|
||||
// On GPU the first IB is a CPU buffer and the second is a GPU buffer.
|
||||
sk_sp<SkCustomMesh::IndexBuffer> fIB[2];
|
||||
|
||||
sk_sp<SkCustomMesh::VertexBuffer> fColorVB;
|
||||
sk_sp<SkCustomMesh::VertexBuffer> fNoColorVB;
|
||||
|
@ -217,18 +217,26 @@ public:
|
||||
|
||||
/**
|
||||
* Makes an index buffer to be used with SkCustomMeshes. The SkData is used to determine the
|
||||
* size and contents of the buffer.
|
||||
* size and contents of the buffer. The buffer may be CPU- or GPU-backed depending on whether
|
||||
* GrDirectContext* is nullptr.
|
||||
*
|
||||
* @param GrDirectContext* currently ignored. May be nullptr.
|
||||
* @param GrDirectContext* If nullptr a CPU-backed object is returned that owns the SkData.
|
||||
* Otherwise, the data is uploaded to the GPU and a GPU-backed buffer
|
||||
* is returned. It may only be used to draw into SkSurfaces that
|
||||
* are backed by the passed GrDirectContext.
|
||||
* @param sk_sp<SkData> required. The data used to populate the buffer.
|
||||
*/
|
||||
static sk_sp<IndexBuffer> MakeIndexBuffer(GrDirectContext*, sk_sp<const SkData>);
|
||||
|
||||
/**
|
||||
* Makes a vertex buffer to be used with SkCustomMeshes. The SkData is used to determine the
|
||||
* size and contents of the buffer.
|
||||
* size and contents of the buffer.The buffer may be CPU- or GPU-backed depending on whether
|
||||
* GrDirectContext* is nullptr.
|
||||
*
|
||||
* @param GrDirectContext* currently ignored. May be nullptr.
|
||||
* @param GrDirectContext* If nullptr a CPU-backed object is returned that owns the SkData.
|
||||
* Otherwise, the data is uploaded to the GPU and a GPU-backed buffer
|
||||
* is returned. It may only be used to draw into SkSurfaces that
|
||||
* are backed by the passed GrDirectContext.
|
||||
* @param sk_sp<SkData> required. The data used to populate the buffer.
|
||||
*/
|
||||
static sk_sp<VertexBuffer> MakeVertexBuffer(GrDirectContext*, sk_sp<const SkData>);
|
||||
|
@ -5566,7 +5566,12 @@ generated_cc_atom(
|
||||
":SkSLTypeShared_hdr",
|
||||
"//include/core:SkCustomMesh_hdr",
|
||||
"//include/core:SkData_hdr",
|
||||
"//include/gpu:GrDirectContext_hdr",
|
||||
"//include/private/gpu/ganesh:GrTypesPriv_hdr",
|
||||
"//src/gpu/ganesh:GrDirectContextPriv_hdr",
|
||||
"//src/gpu/ganesh:GrGpuBuffer_hdr",
|
||||
"//src/gpu/ganesh:GrResourceCache_hdr",
|
||||
"//src/gpu/ganesh:GrResourceProvider_hdr",
|
||||
],
|
||||
)
|
||||
|
||||
|
@ -384,12 +384,30 @@ SkCustomMesh::SkCustomMesh(SkCustomMesh&&) = default;
|
||||
SkCustomMesh& SkCustomMesh::operator=(const SkCustomMesh&) = default;
|
||||
SkCustomMesh& SkCustomMesh::operator=(SkCustomMesh&&) = default;
|
||||
|
||||
sk_sp<IndexBuffer> SkCustomMesh::MakeIndexBuffer(GrDirectContext*, sk_sp<const SkData> data) {
|
||||
return SkCustomMeshPriv::CpuIndexBuffer::Make(std::move(data));
|
||||
sk_sp<IndexBuffer> SkCustomMesh::MakeIndexBuffer(GrDirectContext* dc, sk_sp<const SkData> data) {
|
||||
if (!data) {
|
||||
return nullptr;
|
||||
}
|
||||
if (!dc) {
|
||||
return SkCustomMeshPriv::CpuIndexBuffer::Make(std::move(data));
|
||||
}
|
||||
#if SK_SUPPORT_GPU
|
||||
return SkCustomMeshPriv::GpuIndexBuffer::Make(dc, std::move(data));
|
||||
#endif
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
sk_sp<VertexBuffer> SkCustomMesh::MakeVertexBuffer(GrDirectContext*, sk_sp<const SkData> data) {
|
||||
return SkCustomMeshPriv::CpuVertexBuffer::Make(std::move(data));
|
||||
sk_sp<VertexBuffer> SkCustomMesh::MakeVertexBuffer(GrDirectContext* dc, sk_sp<const SkData> data) {
|
||||
if (!data) {
|
||||
return nullptr;
|
||||
}
|
||||
if (!dc) {
|
||||
return SkCustomMeshPriv::CpuVertexBuffer::Make(std::move(data));
|
||||
}
|
||||
#if SK_SUPPORT_GPU
|
||||
return SkCustomMeshPriv::GpuVertexBuffer::Make(dc, std::move(data));
|
||||
#endif
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SkCustomMesh SkCustomMesh::Make(sk_sp<SkCustomMeshSpecification> spec,
|
||||
|
@ -15,6 +15,14 @@
|
||||
#include "include/private/gpu/ganesh/GrTypesPriv.h"
|
||||
#include "src/core/SkSLTypeShared.h"
|
||||
|
||||
#if SK_SUPPORT_GPU
|
||||
#include "include/gpu/GrDirectContext.h"
|
||||
#include "src/gpu/ganesh/GrDirectContextPriv.h"
|
||||
#include "src/gpu/ganesh/GrGpuBuffer.h"
|
||||
#include "src/gpu/ganesh/GrResourceCache.h"
|
||||
#include "src/gpu/ganesh/GrResourceProvider.h"
|
||||
#endif
|
||||
|
||||
struct SkCustomMeshSpecificationPriv {
|
||||
using Varying = SkCustomMeshSpecification::Varying;
|
||||
using Attribute = SkCustomMeshSpecification::Attribute;
|
||||
@ -91,7 +99,11 @@ struct SkCustomMeshPriv {
|
||||
|
||||
Buffer& operator=(const Buffer&) = delete;
|
||||
|
||||
virtual sk_sp<const SkData> asData() const = 0;
|
||||
virtual sk_sp<const SkData> asData() const { return nullptr; }
|
||||
|
||||
#if SK_SUPPORT_GPU
|
||||
virtual sk_sp<const GrGpuBuffer> asGpuBuffer() const { return nullptr; }
|
||||
#endif
|
||||
|
||||
virtual size_t size() const = 0;
|
||||
};
|
||||
@ -116,16 +128,69 @@ struct SkCustomMeshPriv {
|
||||
|
||||
using CpuIndexBuffer = CpuBuffer<IB>;
|
||||
using CpuVertexBuffer = CpuBuffer<VB>;
|
||||
|
||||
#if SK_SUPPORT_GPU
|
||||
template <typename Base, GrGpuBufferType> class GpuBuffer final : public Base {
|
||||
public:
|
||||
GpuBuffer() = default;
|
||||
|
||||
~GpuBuffer() override;
|
||||
|
||||
static sk_sp<Base> Make(GrDirectContext*, sk_sp<const SkData>);
|
||||
|
||||
sk_sp<const GrGpuBuffer> asGpuBuffer() const override { return fBuffer; }
|
||||
|
||||
size_t size() const override { return fBuffer->size(); }
|
||||
|
||||
private:
|
||||
sk_sp<GrGpuBuffer> fBuffer;
|
||||
GrDirectContext::DirectContextID fContextID;
|
||||
};
|
||||
|
||||
using GpuIndexBuffer = GpuBuffer<IB, GrGpuBufferType::kIndex >;
|
||||
using GpuVertexBuffer = GpuBuffer<VB, GrGpuBufferType::kVertex>;
|
||||
#endif // SK_SUPPORT_GPU
|
||||
};
|
||||
|
||||
inline SkCustomMeshPriv::Buffer::~Buffer() = default;
|
||||
|
||||
template <typename Base>
|
||||
sk_sp<Base> SkCustomMeshPriv::CpuBuffer<Base>::Make(sk_sp<const SkData> data) {
|
||||
SkASSERT(data);
|
||||
|
||||
auto result = new CpuBuffer<Base>;
|
||||
result->fData = std::move(data);
|
||||
return sk_sp<Base>(result);
|
||||
}
|
||||
#if SK_SUPPORT_GPU
|
||||
|
||||
template <typename Base, GrGpuBufferType Type>
|
||||
SkCustomMeshPriv::GpuBuffer<Base, Type>::~GpuBuffer() {
|
||||
GrResourceCache::ReturnResourceFromThread(std::move(fBuffer), fContextID);
|
||||
}
|
||||
|
||||
template <typename Base, GrGpuBufferType Type>
|
||||
sk_sp<Base> SkCustomMeshPriv::GpuBuffer<Base, Type>::Make(GrDirectContext* dc,
|
||||
sk_sp<const SkData> data) {
|
||||
SkASSERT(dc);
|
||||
SkASSERT(data);
|
||||
|
||||
sk_sp<GrGpuBuffer> buffer = dc->priv().resourceProvider()->createBuffer(
|
||||
data->size(),
|
||||
Type,
|
||||
kStatic_GrAccessPattern,
|
||||
data->data());
|
||||
if (!buffer) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto result = new GpuBuffer;
|
||||
result->fBuffer = std::move(buffer);
|
||||
result->fContextID = dc->directContextID();
|
||||
return sk_sp<Base>(result);
|
||||
}
|
||||
|
||||
#endif // SK_SUPPORT_GPU
|
||||
|
||||
#endif // SK_ENABLE_SKSL
|
||||
|
||||
|
@ -396,6 +396,20 @@ private:
|
||||
|
||||
bool isFromVertices() const { return SkToBool(fVertices); }
|
||||
|
||||
std::tuple<sk_sp<const GrGpuBuffer>, size_t> gpuVB() const {
|
||||
if (this->isFromVertices()) {
|
||||
return {};
|
||||
}
|
||||
return {fCMData.vb->asGpuBuffer(), fCMData.voffset};
|
||||
}
|
||||
|
||||
std::tuple<sk_sp<const GrGpuBuffer>, size_t> gpuIB() const {
|
||||
if (this->isFromVertices() || !fCMData.ib) {
|
||||
return {};
|
||||
}
|
||||
return {fCMData.ib->asGpuBuffer(), fCMData.ioffset};
|
||||
}
|
||||
|
||||
void writeVertices(skgpu::VertexWriter& writer,
|
||||
const SkCustomMeshSpecification& spec,
|
||||
bool transform) const;
|
||||
@ -405,9 +419,17 @@ private:
|
||||
}
|
||||
|
||||
const uint16_t* indices() const {
|
||||
return this->isFromVertices()
|
||||
? fVertices->priv().indices()
|
||||
: SkTAddOffset<const uint16_t>(fCMData.ib->data(), fCMData.ioffset);
|
||||
if (this->isFromVertices()) {
|
||||
return fVertices->priv().indices();
|
||||
}
|
||||
if (!fCMData.ib) {
|
||||
return nullptr;
|
||||
}
|
||||
auto data = fCMData.ib->asData();
|
||||
if (!data) {
|
||||
return nullptr;
|
||||
}
|
||||
return SkTAddOffset<const uint16_t>(data->data(), fCMData.ioffset);
|
||||
}
|
||||
|
||||
int indexCount() const {
|
||||
@ -416,8 +438,8 @@ private:
|
||||
|
||||
private:
|
||||
struct CMData {
|
||||
sk_sp<const SkData> vb;
|
||||
sk_sp<const SkData> ib;
|
||||
sk_sp<const SkCustomMeshPriv::VB> vb;
|
||||
sk_sp<const SkCustomMeshPriv::IB> ib;
|
||||
|
||||
size_t vcount = 0;
|
||||
size_t icount = 0;
|
||||
@ -452,9 +474,9 @@ private:
|
||||
|
||||
CustomMeshOp::Mesh::Mesh(const SkCustomMesh& cm) {
|
||||
new (&fCMData) CMData();
|
||||
fCMData.vb = static_cast<SkCustomMeshPriv::VB*>(cm.vertexBuffer().get())->asData();
|
||||
fCMData.vb = sk_ref_sp(static_cast<SkCustomMeshPriv::VB*>(cm.vertexBuffer().get()));
|
||||
if (cm.indexBuffer()) {
|
||||
fCMData.ib = static_cast<SkCustomMeshPriv::IB*>(cm.indexBuffer().get())->asData();
|
||||
fCMData.ib = sk_ref_sp(static_cast<SkCustomMeshPriv::IB*>(cm.indexBuffer().get()));
|
||||
}
|
||||
fCMData.vcount = cm.vertexCount();
|
||||
fCMData.voffset = cm.vertexOffset();
|
||||
@ -507,8 +529,11 @@ void CustomMeshOp::Mesh::writeVertices(skgpu::VertexWriter& writer,
|
||||
}
|
||||
}
|
||||
} else {
|
||||
auto vb = static_cast<const char*>(fCMData.vb->data()) + fCMData.voffset;
|
||||
writer << skgpu::VertexWriter::Array(vb, spec.stride()*fCMData.vcount);
|
||||
sk_sp<const SkData> data = fCMData.vb->asData();
|
||||
if (data) {
|
||||
auto vdata = static_cast<const char*>(data->data()) + fCMData.voffset;
|
||||
writer << skgpu::VertexWriter::Array(vdata, spec.stride() * fCMData.vcount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -706,25 +731,35 @@ void CustomMeshOp::onCreateProgramInfo(const GrCaps* caps,
|
||||
void CustomMeshOp::onPrepareDraws(GrMeshDrawTarget* target) {
|
||||
size_t vertexStride = fSpecification->stride();
|
||||
sk_sp<const GrBuffer> vertexBuffer;
|
||||
int firstVertex = 0;
|
||||
skgpu::VertexWriter verts = target->makeVertexWriter(vertexStride,
|
||||
fVertexCount,
|
||||
&vertexBuffer,
|
||||
&firstVertex);
|
||||
if (!verts) {
|
||||
SkDebugf("Could not allocate vertices.\n");
|
||||
return;
|
||||
}
|
||||
int firstVertex;
|
||||
std::tie(vertexBuffer, firstVertex) = fMeshes[0].gpuVB();
|
||||
|
||||
bool transform = fViewMatrix == SkMatrix::InvalidMatrix();
|
||||
for (const auto& m : fMeshes) {
|
||||
m.writeVertices(verts, *fSpecification, transform);
|
||||
if (!vertexBuffer) {
|
||||
skgpu::VertexWriter verts = target->makeVertexWriter(vertexStride,
|
||||
fVertexCount,
|
||||
&vertexBuffer,
|
||||
&firstVertex);
|
||||
if (!verts) {
|
||||
SkDebugf("Could not allocate vertices.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
bool transform = fViewMatrix == SkMatrix::InvalidMatrix();
|
||||
for (const auto& m : fMeshes) {
|
||||
m.writeVertices(verts, *fSpecification, transform);
|
||||
}
|
||||
} else {
|
||||
SkASSERT(fMeshes.count() == 1);
|
||||
SkASSERT(firstVertex % fSpecification->stride() == 0);
|
||||
firstVertex /= fSpecification->stride();
|
||||
}
|
||||
|
||||
sk_sp<const GrBuffer> indexBuffer;
|
||||
int firstIndex = 0;
|
||||
uint16_t* indices = nullptr;
|
||||
if (fIndexCount) {
|
||||
|
||||
std::tie(indexBuffer, firstIndex) = fMeshes[0].gpuIB();
|
||||
if (fIndexCount && !indexBuffer) {
|
||||
uint16_t* indices = nullptr;
|
||||
indices = target->makeIndexSpace(fIndexCount, &indexBuffer, &firstIndex);
|
||||
if (!indices) {
|
||||
SkDebugf("Could not allocate indices.\n");
|
||||
@ -742,12 +777,16 @@ void CustomMeshOp::onPrepareDraws(GrMeshDrawTarget* target) {
|
||||
}
|
||||
SkASSERT(voffset == fVertexCount);
|
||||
SkASSERT(ioffset == fIndexCount);
|
||||
} else if (indexBuffer) {
|
||||
SkASSERT(fMeshes.count() == 1);
|
||||
SkASSERT(firstIndex % sizeof(uint16_t) == 0);
|
||||
firstIndex /= sizeof(uint16_t);
|
||||
}
|
||||
|
||||
SkASSERT(!fMesh);
|
||||
fMesh = target->allocMesh();
|
||||
|
||||
if (indices) {
|
||||
if (indexBuffer) {
|
||||
fMesh->setIndexed(std::move(indexBuffer),
|
||||
fIndexCount,
|
||||
firstIndex,
|
||||
|
Loading…
Reference in New Issue
Block a user