Dawn: implement staging buffer manager.
Use managed staging buffers for texture uploads, uniforms and buffers. Change-Id: I063707c160236725d27a1d1bfb197d3096a07b34 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/238120 Commit-Queue: Stephen White <senorblanco@chromium.org> Reviewed-by: Greg Daniel <egdaniel@google.com>
This commit is contained in:
parent
2adbf9ce1c
commit
7fba36b88a
@ -725,6 +725,8 @@ skia_dawn_sources = [
|
||||
"$_src/gpu/dawn/GrDawnRingBuffer.h",
|
||||
"$_src/gpu/dawn/GrDawnStencilAttachment.cpp",
|
||||
"$_src/gpu/dawn/GrDawnStencilAttachment.h",
|
||||
"$_src/gpu/dawn/GrDawnStagingManager.cpp",
|
||||
"$_src/gpu/dawn/GrDawnStagingManager.h",
|
||||
"$_src/gpu/dawn/GrDawnTexture.cpp",
|
||||
"$_src/gpu/dawn/GrDawnTexture.h",
|
||||
"$_src/gpu/dawn/GrDawnTextureRenderTarget.cpp",
|
||||
|
@ -30,7 +30,7 @@ namespace {
|
||||
GrDawnBuffer::GrDawnBuffer(GrDawnGpu* gpu, size_t sizeInBytes, GrGpuBufferType type,
|
||||
GrAccessPattern pattern)
|
||||
: INHERITED(gpu, sizeInBytes, type, pattern)
|
||||
, fData(nullptr) {
|
||||
, fStagingBuffer(nullptr) {
|
||||
dawn::BufferDescriptor bufferDesc;
|
||||
bufferDesc.size = sizeInBytes;
|
||||
bufferDesc.usage = GrGpuBufferTypeToDawnUsageBit(type) | dawn::BufferUsageBit::CopyDst;
|
||||
@ -39,31 +39,33 @@ GrDawnBuffer::GrDawnBuffer(GrDawnGpu* gpu, size_t sizeInBytes, GrGpuBufferType t
|
||||
}
|
||||
|
||||
GrDawnBuffer::~GrDawnBuffer() {
|
||||
delete[] fData;
|
||||
}
|
||||
|
||||
void GrDawnBuffer::onMap() {
|
||||
if (this->wasDestroyed()) {
|
||||
return;
|
||||
}
|
||||
fData = new char[this->size()];
|
||||
fMapPtr = fData;
|
||||
fStagingBuffer = getDawnGpu()->getStagingBuffer(this->size());
|
||||
fMapPtr = fStagingBuffer->fData;
|
||||
}
|
||||
|
||||
void GrDawnBuffer::onUnmap() {
|
||||
if (this->wasDestroyed()) {
|
||||
return;
|
||||
}
|
||||
fBuffer.SetSubData(0, this->size(), reinterpret_cast<const uint8_t*>(fData));
|
||||
delete[] fData;
|
||||
fData = nullptr;
|
||||
fStagingBuffer->fBuffer.Unmap();
|
||||
fMapPtr = nullptr;
|
||||
getDawnGpu()->getCopyEncoder()
|
||||
.CopyBufferToBuffer(fStagingBuffer->fBuffer, 0, fBuffer, 0, this->size());
|
||||
}
|
||||
|
||||
bool GrDawnBuffer::onUpdateData(const void* src, size_t srcSizeInBytes) {
|
||||
if (this->wasDestroyed()) {
|
||||
return false;
|
||||
}
|
||||
fBuffer.SetSubData(0, srcSizeInBytes, static_cast<const uint8_t*>(src));
|
||||
this->onMap();
|
||||
memcpy(fStagingBuffer->fData, src, srcSizeInBytes);
|
||||
this->onUnmap();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "dawn/dawncpp.h"
|
||||
|
||||
class GrDawnGpu;
|
||||
struct GrDawnStagingBuffer;
|
||||
|
||||
class GrDawnBuffer : public GrGpuBuffer {
|
||||
public:
|
||||
@ -27,7 +28,7 @@ public:
|
||||
|
||||
private:
|
||||
dawn::Buffer fBuffer;
|
||||
char* fData; // Used only for map/unmap.
|
||||
GrDawnStagingBuffer* fStagingBuffer;
|
||||
typedef GrGpuBuffer INHERITED;
|
||||
};
|
||||
|
||||
|
@ -102,7 +102,8 @@ GrDawnGpu::GrDawnGpu(GrContext* context, const GrContextOptions& options,
|
||||
, fQueue(device.CreateQueue())
|
||||
, fCompiler(new SkSL::Compiler())
|
||||
, fUniformRingBuffer(this, dawn::BufferUsageBit::Uniform)
|
||||
, fRenderPipelineCache(kMaxRenderPipelineEntries) {
|
||||
, fRenderPipelineCache(kMaxRenderPipelineEntries)
|
||||
, fStagingManager(fDevice) {
|
||||
fCaps.reset(new GrDawnCaps(options));
|
||||
}
|
||||
|
||||
@ -354,21 +355,21 @@ GrBackendTexture GrDawnGpu::createBackendTexture(int width, int height,
|
||||
size_t origRowBytes = bpp * w;
|
||||
size_t rowBytes = GrDawnRoundRowBytes(origRowBytes);
|
||||
size_t size = rowBytes * h;
|
||||
dawn::BufferDescriptor bufferDesc;
|
||||
bufferDesc.size = size;
|
||||
bufferDesc.usage = dawn::BufferUsageBit::CopySrc | dawn::BufferUsageBit::CopyDst;
|
||||
dawn::Buffer buffer = this->device().CreateBuffer(&bufferDesc);
|
||||
const uint8_t* src = static_cast<const uint8_t*>(pixels);
|
||||
GrDawnStagingBuffer* stagingBuffer = this->getStagingBuffer(size);
|
||||
if (rowBytes == origRowBytes) {
|
||||
buffer.SetSubData(0, size, src);
|
||||
memcpy(stagingBuffer->fData, pixels, size);
|
||||
} else {
|
||||
uint32_t offset = 0;
|
||||
const char* src = static_cast<const char*>(pixels);
|
||||
char* dst = static_cast<char*>(stagingBuffer->fData);
|
||||
for (int row = 0; row < h; row++) {
|
||||
buffer.SetSubData(offset, origRowBytes, src);
|
||||
offset += rowBytes;
|
||||
memcpy(dst, src, origRowBytes);
|
||||
dst += rowBytes;
|
||||
src += origRowBytes;
|
||||
}
|
||||
}
|
||||
dawn::Buffer buffer = stagingBuffer->fBuffer;
|
||||
buffer.Unmap();
|
||||
stagingBuffer->fData = nullptr;
|
||||
dawn::BufferCopyView srcBuffer;
|
||||
srcBuffer.buffer = buffer;
|
||||
srcBuffer.offset = 0;
|
||||
@ -458,6 +459,8 @@ void GrDawnGpu::flush() {
|
||||
this->flushCopyEncoder();
|
||||
fQueue.Submit(fCommandBuffers.size(), &fCommandBuffers.front());
|
||||
fCommandBuffers.clear();
|
||||
fStagingManager.mapBusyList();
|
||||
fDevice.Tick();
|
||||
}
|
||||
|
||||
void GrDawnGpu::onFinishFlush(GrSurfaceProxy*[], int n, SkSurface::BackendSurfaceAccess access,
|
||||
@ -644,6 +647,10 @@ GrDawnRingBuffer::Slice GrDawnGpu::allocateUniformRingBufferSlice(int size) {
|
||||
return fUniformRingBuffer.allocate(size);
|
||||
}
|
||||
|
||||
GrDawnStagingBuffer* GrDawnGpu::getStagingBuffer(size_t size) {
|
||||
return fStagingManager.findOrCreateStagingBuffer(size);
|
||||
}
|
||||
|
||||
void GrDawnGpu::appendCommandBuffer(dawn::CommandBuffer commandBuffer) {
|
||||
if (commandBuffer) {
|
||||
fCommandBuffers.push_back(commandBuffer);
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "dawn/dawncpp.h"
|
||||
#include "src/core/SkLRUCache.h"
|
||||
#include "src/gpu/dawn/GrDawnRingBuffer.h"
|
||||
#include "src/gpu/dawn/GrDawnStagingManager.h"
|
||||
|
||||
class GrDawnOpsRenderPass;
|
||||
class GrPipeline;
|
||||
@ -94,6 +95,8 @@ public:
|
||||
GrPrimitiveType primitiveType);
|
||||
|
||||
GrDawnRingBuffer::Slice allocateUniformRingBufferSlice(int size);
|
||||
GrDawnStagingBuffer* getStagingBuffer(size_t size);
|
||||
GrDawnStagingManager* getStagingManager() { return &fStagingManager; }
|
||||
dawn::CommandEncoder getCopyEncoder();
|
||||
void flushCopyEncoder();
|
||||
void appendCommandBuffer(dawn::CommandBuffer commandBuffer);
|
||||
@ -173,6 +176,7 @@ private:
|
||||
};
|
||||
|
||||
SkLRUCache<GrProgramDesc, sk_sp<GrDawnProgram>, ProgramDescHash> fRenderPipelineCache;
|
||||
GrDawnStagingManager fStagingManager;
|
||||
|
||||
typedef GrGpu INHERITED;
|
||||
};
|
||||
|
@ -587,7 +587,7 @@ dawn::BindGroup GrDawnProgram::setData(GrDawnGpu* gpu, const GrRenderTarget* ren
|
||||
GrFragmentProcessor::TextureSampler sampler(sk_ref_sp(proxy));
|
||||
setTexture(gpu, sampler.samplerState(), sampler.peekTexture(), &bindings, &binding);
|
||||
}
|
||||
fDataManager.uploadUniformBuffers(geom, frag);
|
||||
fDataManager.uploadUniformBuffers(gpu, geom, frag);
|
||||
dawn::BindGroupDescriptor descriptor;
|
||||
descriptor.layout = fBindGroupLayout;
|
||||
descriptor.bindingCount = bindings.size();
|
||||
|
@ -263,17 +263,26 @@ template<> struct set_uniform_matrix<4> {
|
||||
}
|
||||
};
|
||||
|
||||
void GrDawnProgramDataManager::uploadUniformBuffers(GrDawnRingBuffer::Slice geometryBuffer,
|
||||
void GrDawnProgramDataManager::uploadUniformBuffers(GrDawnGpu* gpu,
|
||||
GrDawnRingBuffer::Slice geometryBuffer,
|
||||
GrDawnRingBuffer::Slice fragmentBuffer) const {
|
||||
|
||||
dawn::Buffer geom = geometryBuffer.fBuffer;
|
||||
uint32_t geomOffset = geometryBuffer.fOffset;
|
||||
dawn::Buffer frag = fragmentBuffer.fBuffer;
|
||||
uint32_t fragOffset = fragmentBuffer.fOffset;
|
||||
auto copyEncoder = gpu->getCopyEncoder();
|
||||
if (geom && fGeometryUniformsDirty) {
|
||||
geom.SetSubData(geometryBuffer.fOffset, fGeometryUniformSize,
|
||||
static_cast<const uint8_t*>(fGeometryUniformData.get()));
|
||||
GrDawnStagingBuffer* stagingBuffer = gpu->getStagingBuffer(fGeometryUniformSize);
|
||||
memcpy(stagingBuffer->fData, fGeometryUniformData.get(), fGeometryUniformSize);
|
||||
stagingBuffer->fBuffer.Unmap();
|
||||
copyEncoder
|
||||
.CopyBufferToBuffer(stagingBuffer->fBuffer, 0, geom, geomOffset, fGeometryUniformSize);
|
||||
}
|
||||
if (frag && fFragmentUniformsDirty) {
|
||||
frag.SetSubData(fragmentBuffer.fOffset, fFragmentUniformSize,
|
||||
static_cast<const uint8_t*>(fFragmentUniformData.get()));
|
||||
GrDawnStagingBuffer* stagingBuffer = gpu->getStagingBuffer(fFragmentUniformSize);
|
||||
memcpy(stagingBuffer->fData, fFragmentUniformData.get(), fFragmentUniformSize);
|
||||
stagingBuffer->fBuffer.Unmap();
|
||||
copyEncoder
|
||||
.CopyBufferToBuffer(stagingBuffer->fBuffer, 0, frag, fragOffset, fFragmentUniformSize);
|
||||
}
|
||||
}
|
||||
|
@ -58,7 +58,8 @@ public:
|
||||
SK_ABORT("Only supported in NVPR, which is not in Dawn");
|
||||
}
|
||||
|
||||
void uploadUniformBuffers(GrDawnRingBuffer::Slice geometryBuffer,
|
||||
void uploadUniformBuffers(GrDawnGpu* gpu,
|
||||
GrDawnRingBuffer::Slice geometryBuffer,
|
||||
GrDawnRingBuffer::Slice fragmentBuffer) const;
|
||||
|
||||
uint32_t geometryUniformSize() const { return fGeometryUniformSize; }
|
||||
|
65
src/gpu/dawn/GrDawnStagingManager.cpp
Normal file
65
src/gpu/dawn/GrDawnStagingManager.cpp
Normal file
@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright 2019 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "src/gpu/dawn/GrDawnStagingManager.h"
|
||||
|
||||
#include "src/core/SkMathPriv.h"
|
||||
|
||||
GrDawnStagingManager::GrDawnStagingManager(dawn::Device device) : fDevice(device) {
|
||||
}
|
||||
|
||||
GrDawnStagingManager::~GrDawnStagingManager() {
|
||||
// Clean up any pending callbacks before destroying the StagingBuffers.
|
||||
while (fWaitingCount > 0) {
|
||||
fDevice.Tick();
|
||||
}
|
||||
}
|
||||
|
||||
GrDawnStagingBuffer* GrDawnStagingManager::findOrCreateStagingBuffer(size_t size) {
|
||||
size_t sizePow2 = GrNextPow2(size);
|
||||
GrDawnStagingBuffer* stagingBuffer;
|
||||
auto i = fReadyPool.find(sizePow2);
|
||||
if (i != fReadyPool.end()) {
|
||||
stagingBuffer = i->second;
|
||||
fReadyPool.erase(i);
|
||||
} else {
|
||||
dawn::BufferDescriptor desc;
|
||||
desc.usage = dawn::BufferUsageBit::MapWrite | dawn::BufferUsageBit::CopySrc;
|
||||
desc.size = sizePow2;
|
||||
dawn::CreateBufferMappedResult result = fDevice.CreateBufferMapped(&desc);
|
||||
std::unique_ptr<GrDawnStagingBuffer> b(new GrDawnStagingBuffer(
|
||||
this, result.buffer, sizePow2, result.data));
|
||||
stagingBuffer = b.get();
|
||||
fBuffers.push_back(std::move(b));
|
||||
}
|
||||
fBusyList.push_back(stagingBuffer);
|
||||
return stagingBuffer;
|
||||
}
|
||||
|
||||
static void callback(DawnBufferMapAsyncStatus status, void* data, uint64_t dataLength,
|
||||
void* userData) {
|
||||
GrDawnStagingBuffer* buffer = static_cast<GrDawnStagingBuffer*>(userData);
|
||||
buffer->fData = data;
|
||||
if (buffer->fManager) {
|
||||
buffer->fManager->addToReadyPool(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
void GrDawnStagingManager::mapBusyList() {
|
||||
// Map all buffers on the busy list for writing. When they're no longer in flight on the GPU,
|
||||
// their callback will be called and they'll be moved to the ready pool.
|
||||
for (GrDawnStagingBuffer* buffer : fBusyList) {
|
||||
buffer->fBuffer.MapWriteAsync(callback, buffer);
|
||||
fWaitingCount++;
|
||||
}
|
||||
fBusyList.clear();
|
||||
}
|
||||
|
||||
void GrDawnStagingManager::addToReadyPool(GrDawnStagingBuffer* buffer) {
|
||||
fWaitingCount--;
|
||||
fReadyPool.insert(std::pair<size_t, GrDawnStagingBuffer*>(buffer->fSize, buffer));
|
||||
}
|
49
src/gpu/dawn/GrDawnStagingManager.h
Normal file
49
src/gpu/dawn/GrDawnStagingManager.h
Normal file
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 2019 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef GrDawnStagingManager_DEFINED
|
||||
#define GrDawnStagingManager_DEFINED
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "dawn/dawncpp.h"
|
||||
|
||||
struct GrDawnStagingBuffer;
|
||||
|
||||
class GrDawnStagingManager {
|
||||
public:
|
||||
GrDawnStagingManager(dawn::Device device);
|
||||
~GrDawnStagingManager();
|
||||
GrDawnStagingBuffer* findOrCreateStagingBuffer(size_t size);
|
||||
|
||||
void addToReadyPool(GrDawnStagingBuffer* buffer);
|
||||
void mapBusyList();
|
||||
|
||||
private:
|
||||
dawn::Device fDevice;
|
||||
std::vector<std::unique_ptr<GrDawnStagingBuffer>> fBuffers;
|
||||
std::multimap<size_t, GrDawnStagingBuffer*> fReadyPool;
|
||||
std::vector<GrDawnStagingBuffer*> fBusyList;
|
||||
int fWaitingCount = 0;
|
||||
};
|
||||
|
||||
struct GrDawnStagingBuffer {
|
||||
GrDawnStagingBuffer(GrDawnStagingManager* manager, dawn::Buffer buffer, size_t size,
|
||||
void* data)
|
||||
: fManager(manager), fBuffer(buffer), fSize(size), fData(data) {}
|
||||
~GrDawnStagingBuffer() {
|
||||
fManager = nullptr;
|
||||
}
|
||||
GrDawnStagingManager* fManager;
|
||||
dawn::Buffer fBuffer;
|
||||
size_t fSize;
|
||||
void* fData;
|
||||
};
|
||||
|
||||
#endif
|
@ -166,31 +166,23 @@ void GrDawnTexture::upload(const GrMipLevel texels[], int mipLevels, const SkIRe
|
||||
}
|
||||
size_t rowBytes = GrDawnRoundRowBytes(origRowBytes);
|
||||
size_t size = rowBytes * height;
|
||||
|
||||
dawn::BufferDescriptor desc;
|
||||
desc.usage = dawn::BufferUsageBit::CopyDst | dawn::BufferUsageBit::CopySrc;
|
||||
desc.size = size;
|
||||
|
||||
dawn::Buffer stagingBuffer = device.CreateBuffer(&desc);
|
||||
|
||||
GrDawnStagingBuffer* stagingBuffer = getDawnGpu()->getStagingBuffer(size);
|
||||
if (rowBytes == origRowBytes) {
|
||||
stagingBuffer.SetSubData(0, size,
|
||||
static_cast<const uint8_t*>(static_cast<const void *>(src)));
|
||||
memcpy(stagingBuffer->fData, src, size);
|
||||
} else {
|
||||
char* buf = new char[size];
|
||||
char* dst = buf;
|
||||
char* dst = static_cast<char*>(stagingBuffer->fData);
|
||||
for (uint32_t row = 0; row < height; row++) {
|
||||
memcpy(dst, src, origRowBytes);
|
||||
dst += rowBytes;
|
||||
src += texels[i].fRowBytes;
|
||||
}
|
||||
stagingBuffer.SetSubData(0, size,
|
||||
static_cast<const uint8_t*>(static_cast<const void*>(buf)));
|
||||
delete[] buf;
|
||||
}
|
||||
dawn::Buffer buffer = stagingBuffer->fBuffer;
|
||||
buffer.Unmap();
|
||||
stagingBuffer->fData = nullptr;
|
||||
|
||||
dawn::BufferCopyView srcBuffer;
|
||||
srcBuffer.buffer = stagingBuffer;
|
||||
srcBuffer.buffer = buffer;
|
||||
srcBuffer.offset = 0;
|
||||
srcBuffer.rowPitch = rowBytes;
|
||||
srcBuffer.imageHeight = height;
|
||||
|
Loading…
Reference in New Issue
Block a user