/* * Copyright 2023 Google LLC * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include "src/gpu/ganesh/GrMeshBuffers.h" #include "include/core/SkData.h" #include "include/core/SkMesh.h" #include "include/gpu/ganesh/GrDirectContext.h" #include "include/gpu/ganesh/SkMeshGanesh.h" #include "include/private/base/SkAssert.h" #include "include/private/gpu/ganesh/GrTypesPriv.h" #include "src/core/SkMeshPriv.h" #include "src/gpu/ganesh/GrCaps.h" #include "src/gpu/ganesh/GrDirectContextPriv.h" #include "src/gpu/ganesh/GrDrawingManager.h" #include "src/gpu/ganesh/GrGpu.h" #include "src/gpu/ganesh/GrGpuBuffer.h" #include "src/gpu/ganesh/GrResourceCache.h" #include "src/gpu/ganesh/GrResourceProvider.h" #include "src/gpu/ganesh/GrStagingBufferManager.h" #include #include template GrMeshBuffer::~GrMeshBuffer() { GrResourceCache::ReturnResourceFromThread(std::move(fBuffer), fContextID); } template sk_sp GrMeshBuffer::Make(GrDirectContext* dc, const void* data, size_t size) { SkASSERT(dc); sk_sp buffer = dc->priv().resourceProvider()->createBuffer( size, Type, kStatic_GrAccessPattern, data ? GrResourceProvider::ZeroInit::kNo : GrResourceProvider::ZeroInit::kYes); if (!buffer) { return nullptr; } if (data && !buffer->updateData(data, 0, size, /*preserve=*/false)) { return nullptr; } auto result = new GrMeshBuffer; result->fBuffer = std::move(buffer); result->fContextID = dc->directContextID(); return sk_sp(result); } template bool GrMeshBuffer::onUpdate(GrDirectContext* dc, const void* data, size_t offset, size_t size) { if (!dc || dc != fBuffer->getContext()) { return false; } SkASSERT(!dc->abandoned()); // If dc is abandoned then fBuffer->getContext() should be null. if (!dc->priv().caps()->transferFromBufferToBufferSupport()) { auto ownedData = SkData::MakeWithCopy(data, size); dc->priv().drawingManager()->newBufferUpdateTask( std::move(ownedData), fBuffer, offset); return true; } sk_sp tempBuffer; size_t tempOffset = 0; if (auto* sbm = dc->priv().getGpu()->stagingBufferManager()) { auto alignment = dc->priv().caps()->transferFromBufferToBufferAlignment(); auto [sliceBuffer, sliceOffset, ptr] = sbm->allocateStagingBufferSlice(size, alignment); if (sliceBuffer) { std::memcpy(ptr, data, size); tempBuffer.reset(SkRef(sliceBuffer)); tempOffset = sliceOffset; } } if (!tempBuffer) { tempBuffer = dc->priv().resourceProvider()->createBuffer(size, GrGpuBufferType::kXferCpuToGpu, kDynamic_GrAccessPattern, GrResourceProvider::ZeroInit::kNo); if (!tempBuffer) { return false; } if (!tempBuffer->updateData(data, 0, size, /*preserve=*/false)) { return false; } } dc->priv().drawingManager()->newBufferTransferTask( std::move(tempBuffer), tempOffset, fBuffer, offset, size); return true; } namespace SkMeshes { sk_sp MakeIndexBuffer(GrDirectContext* dc, const void* data, size_t size) { if (!dc) { // Fallback to a CPU buffer. return MakeIndexBuffer(data, size); } return SkMeshPriv::GaneshIndexBuffer::Make(dc, data, size); } sk_sp CopyIndexBuffer(GrDirectContext* dc, sk_sp src) { if (!src) { return nullptr; } auto* ib = static_cast(src.get()); const void* data = ib->peek(); if (!data) { return nullptr; } if (!dc) { return MakeIndexBuffer(data, ib->size()); } return MakeIndexBuffer(dc, data, ib->size()); } sk_sp MakeVertexBuffer(GrDirectContext* dc, const void* data, size_t size) { if (!dc) { return MakeVertexBuffer(data, size); } return SkMeshPriv::GaneshVertexBuffer::Make(dc, data, size); } sk_sp CopyVertexBuffer(GrDirectContext* dc, sk_sp src) { if (!src) { return nullptr; } auto* vb = static_cast(src.get()); const void* data = vb->peek(); if (!data) { return nullptr; } if (!dc) { return MakeVertexBuffer(data, vb->size()); } return MakeVertexBuffer(dc, data, vb->size()); } } // namespace SkMeshes