Dawn: implement a ring buffer for uniform uploads.

GrDawnGpu vends ring buffer slices out of a persistent (larger) buffer.

GrDawnProgramDataManager::setData() now returns a BindGroup containing
the (possibly new) UBO bindings, as well as the texture and sampler
bindings.
Change-Id: Id6694d6f44a815cfbffe4293779bf9bf558a2365
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/235866
Reviewed-by: Greg Daniel <egdaniel@google.com>
Commit-Queue: Stephen White <senorblanco@chromium.org>
This commit is contained in:
Stephen White 2019-08-21 09:48:05 -04:00 committed by Skia Commit-Bot
parent c4b4735a09
commit b7eaedcfcc
10 changed files with 170 additions and 69 deletions

View File

@ -723,6 +723,8 @@ skia_dawn_sources = [
"$_src/gpu/dawn/GrDawnProgramBuilder.h",
"$_src/gpu/dawn/GrDawnRenderTarget.cpp",
"$_src/gpu/dawn/GrDawnRenderTarget.h",
"$_src/gpu/dawn/GrDawnRingBuffer.cpp",
"$_src/gpu/dawn/GrDawnRingBuffer.h",
"$_src/gpu/dawn/GrDawnStencilAttachment.cpp",
"$_src/gpu/dawn/GrDawnStencilAttachment.h",
"$_src/gpu/dawn/GrDawnTexture.cpp",

View File

@ -49,7 +49,8 @@ GrDawnGpu::GrDawnGpu(GrContext* context, const GrContextOptions& options,
: INHERITED(context)
, fDevice(device)
, fQueue(device.CreateQueue())
, fCompiler(new SkSL::Compiler()) {
, fCompiler(new SkSL::Compiler())
, fUniformRingBuffer(this, dawn::BufferUsageBit::Uniform) {
fCaps.reset(new GrDawnCaps(options));
}
@ -543,3 +544,7 @@ sk_sp<GrSemaphore> GrDawnGpu::prepareTextureForCrossContextUsage(GrTexture* text
SkASSERT(!"unimplemented");
return nullptr;
}
GrDawnRingBuffer::Slice GrDawnGpu::allocateUniformRingBufferSlice(int size) {
return fUniformRingBuffer.allocate(size);
}

View File

@ -10,6 +10,7 @@
#include "src/gpu/GrGpu.h"
#include "dawn/dawncpp.h"
#include "src/gpu/dawn/GrDawnRingBuffer.h"
class GrPipeline;
class GrDawnGpuRTCommandBuffer;
@ -82,6 +83,8 @@ public:
sk_sp<GrSemaphore> prepareTextureForCrossContextUsage(GrTexture*) override;
GrDawnRingBuffer::Slice allocateUniformRingBufferSlice(int size);
private:
void onResetContext(uint32_t resetBits) override {}
@ -147,6 +150,7 @@ private:
std::unique_ptr<SkSL::Compiler> fCompiler;
std::unique_ptr<GrDawnGpuRTCommandBuffer> fRTCommandBuffer;
std::unique_ptr<GrDawnGpuTextureCommandBuffer> fTextureCommandBuffer;
GrDawnRingBuffer fUniformRingBuffer;
typedef GrGpu INHERITED;
};

View File

@ -326,7 +326,8 @@ void GrDawnGpuRTCommandBuffer::applyState(const GrPipeline& pipeline,
colorFormat, hasDepthStencil,
stencilFormat, &desc);
SkASSERT(program);
program->setData(primProc, fRenderTarget, fOrigin, pipeline);
auto bindGroup = program->setData(fGpu, fRenderTarget, fOrigin, primProc, pipeline,
primProcProxies);
std::vector<dawn::VertexBufferDescriptor> inputs;
std::vector<dawn::VertexAttributeDescriptor> vertexAttributes;
@ -404,7 +405,7 @@ void GrDawnGpuRTCommandBuffer::applyState(const GrPipeline& pipeline,
rpDesc.colorStates = colorStates;
dawn::RenderPipeline renderPipeline = fGpu->device().CreateRenderPipeline(&rpDesc);
fPassEncoder.SetPipeline(renderPipeline);
fPassEncoder.SetBindGroup(0, program->fBindGroup, 0, nullptr);
fPassEncoder.SetBindGroup(0, bindGroup, 0, nullptr);
if (pipeline.isStencilEnabled()) {
fPassEncoder.SetStencilReference(pipeline.getUserStencil()->fFront.fRef);
}

View File

@ -347,54 +347,11 @@ sk_sp<GrDawnProgram> GrDawnProgramBuilder::Build(GrDawnGpu* gpu,
dawn::BindGroupLayoutDescriptor bindGroupLayoutDesc;
bindGroupLayoutDesc.bindingCount = layoutBindings.size();
bindGroupLayoutDesc.bindings = layoutBindings.data();
auto bindGroupLayout = gpu->device().CreateBindGroupLayout(&bindGroupLayoutDesc);
result->fBindGroupLayout = gpu->device().CreateBindGroupLayout(&bindGroupLayoutDesc);
dawn::PipelineLayoutDescriptor pipelineLayoutDesc;
pipelineLayoutDesc.bindGroupLayoutCount = 1;
pipelineLayoutDesc.bindGroupLayouts = &bindGroupLayout;
pipelineLayoutDesc.bindGroupLayouts = &result->fBindGroupLayout;
result->fPipelineLayout = gpu->device().CreatePipelineLayout(&pipelineLayoutDesc);
if (0 != geometryUniformSize) {
dawn::BufferDescriptor desc;
desc.usage = dawn::BufferUsageBit::Uniform | dawn::BufferUsageBit::CopyDst;
desc.size = geometryUniformSize;
result->fGeometryUniformBuffer = gpu->device().CreateBuffer(&desc);
bindings.push_back(make_bind_group_binding(GrDawnUniformHandler::kGeometryBinding,
result->fGeometryUniformBuffer,
0, geometryUniformSize));
}
if (0 != fragmentUniformSize) {
dawn::BufferDescriptor desc;
desc.usage = dawn::BufferUsageBit::Uniform | dawn::BufferUsageBit::CopyDst;
desc.size = fragmentUniformSize;
result->fFragmentUniformBuffer = gpu->device().CreateBuffer(&desc);
bindings.push_back(make_bind_group_binding(GrDawnUniformHandler::kFragBinding,
result->fFragmentUniformBuffer,
0, fragmentUniformSize));
}
binding = GrDawnUniformHandler::kSamplerBindingBase;
for (int i = 0; i < primProc.numTextureSamplers(); ++i) {
dawn::Sampler sampler = create_sampler(gpu, primProc.textureSampler(i).samplerState());
bindings.push_back(make_bind_group_binding(binding++, sampler));
GrDawnTexture* tex = static_cast<GrDawnTexture*>(primProcProxies[i]->peekTexture());
dawn::TextureView textureView = tex->textureView();
bindings.push_back(make_bind_group_binding(binding++, textureView));
}
GrFragmentProcessor::Iter iter(pipeline);
const GrFragmentProcessor* fp = iter.next();
while (fp) {
for (int i = 0; i < fp->numTextureSamplers(); ++i) {
dawn::Sampler sampler = create_sampler(gpu, fp->textureSampler(i).samplerState());
bindings.push_back(make_bind_group_binding(binding++, sampler));
GrDawnTexture* tex = static_cast<GrDawnTexture*>(fp->textureSampler(i).peekTexture());
dawn::TextureView textureView = tex->textureView();
bindings.push_back(make_bind_group_binding(binding++, textureView));
}
fp = iter.next();
}
dawn::BindGroupDescriptor bindGroupDescriptor;
bindGroupDescriptor.layout = bindGroupLayout;
bindGroupDescriptor.bindingCount = bindings.size();
bindGroupDescriptor.bindings = bindings.data();
result->fBindGroup = gpu->device().CreateBindGroup(&bindGroupDescriptor);
result->fBuiltinUniformHandles = builder.fUniformHandles;
result->fColorState = create_color_state(gpu, pipeline, colorFormat);
GrStencilSettings stencil;
@ -465,22 +422,70 @@ void GrDawnProgram::setRenderTargetState(const GrRenderTarget* rt, GrSurfaceOrig
}
}
void GrDawnProgram::setData(const GrPrimitiveProcessor& primProc,
const GrRenderTarget* renderTarget,
GrSurfaceOrigin origin,
const GrPipeline& pipeline) {
static void setTexture(GrDawnGpu* gpu, const GrSamplerState& state, GrTexture* texture,
std::vector<dawn::BindGroupBinding> *bindings, int* binding) {
// FIXME: could probably cache samplers in GrDawnProgram
dawn::Sampler sampler = create_sampler(gpu, state);
bindings->push_back(make_bind_group_binding((*binding)++, sampler));
GrDawnTexture* tex = static_cast<GrDawnTexture*>(texture);
dawn::TextureView textureView = tex->textureView();
bindings->push_back(make_bind_group_binding((*binding)++, textureView));
}
dawn::BindGroup GrDawnProgram::setData(GrDawnGpu* gpu, const GrRenderTarget* renderTarget,
GrSurfaceOrigin origin,
const GrPrimitiveProcessor& primProc,
const GrPipeline& pipeline,
const GrTextureProxy* const primProcTextures[]) {
std::vector<dawn::BindGroupBinding> bindings;
GrDawnRingBuffer::Slice geom, frag;
uint32_t geometryUniformSize = fDataManager.geometryUniformSize();
uint32_t fragmentUniformSize = fDataManager.fragmentUniformSize();
if (0 != geometryUniformSize) {
geom = gpu->allocateUniformRingBufferSlice(geometryUniformSize);
bindings.push_back(make_bind_group_binding(GrDawnUniformHandler::kGeometryBinding,
geom.fBuffer, geom.fOffset,
geometryUniformSize));
}
if (0 != fragmentUniformSize) {
frag = gpu->allocateUniformRingBufferSlice(fragmentUniformSize);
bindings.push_back(make_bind_group_binding(GrDawnUniformHandler::kFragBinding,
frag.fBuffer, frag.fOffset,
fragmentUniformSize));
}
this->setRenderTargetState(renderTarget, origin);
fGeometryProcessor->setData(fDataManager, primProc,
GrFragmentProcessor::CoordTransformIter(pipeline));
int binding = GrDawnUniformHandler::kSamplerBindingBase;
for (int i = 0; i < primProc.numTextureSamplers(); ++i) {
auto& sampler = primProc.textureSampler(i);
setTexture(gpu, sampler.samplerState(), primProcTextures[i]->peekTexture(), &bindings,
&binding);
}
GrFragmentProcessor::Iter iter(pipeline);
GrGLSLFragmentProcessor::Iter glslIter(fFragmentProcessors.get(), fFragmentProcessorCnt);
const GrFragmentProcessor* fp = iter.next();
GrGLSLFragmentProcessor* glslFP = glslIter.next();
while (fp && glslFP) {
glslFP->setData(fDataManager, *fp);
for (int i = 0; i < fp->numTextureSamplers(); ++i) {
auto& s = fp->textureSampler(i);
setTexture(gpu, s.samplerState(), s.peekTexture(), &bindings, &binding);
}
fp = iter.next();
glslFP = glslIter.next();
}
fDataManager.uploadUniformBuffers(fGeometryUniformBuffer,
fFragmentUniformBuffer);
SkIPoint offset;
GrTexture* dstTexture = pipeline.peekDstTexture(&offset);
fXferProcessor->setData(fDataManager, pipeline.getXferProcessor(), dstTexture, offset);
if (GrTextureProxy* proxy = pipeline.dstTextureProxy()) {
GrFragmentProcessor::TextureSampler sampler(sk_ref_sp(proxy));
setTexture(gpu, sampler.samplerState(), sampler.peekTexture(), &bindings, &binding);
}
fDataManager.uploadUniformBuffers(geom, frag);
dawn::BindGroupDescriptor descriptor;
descriptor.layout = fBindGroupLayout;
descriptor.bindingCount = bindings.size();
descriptor.bindings = bindings.data();
return gpu->device().CreateBindGroup(&descriptor);
}

View File

@ -60,8 +60,7 @@ struct GrDawnProgram : public SkRefCnt {
std::unique_ptr<GrGLSLXferProcessor> fXferProcessor;
std::unique_ptr<std::unique_ptr<GrGLSLFragmentProcessor>[]> fFragmentProcessors;
int fFragmentProcessorCnt;
dawn::Buffer fGeometryUniformBuffer;
dawn::Buffer fFragmentUniformBuffer;
dawn::BindGroupLayout fBindGroupLayout;
dawn::PipelineLayout fPipelineLayout;
dawn::BindGroup fBindGroup;
dawn::ColorStateDescriptor fColorState;
@ -71,8 +70,9 @@ struct GrDawnProgram : public SkRefCnt {
BuiltinUniformHandles fBuiltinUniformHandles;
void setRenderTargetState(const GrRenderTarget*, GrSurfaceOrigin);
void setData(const GrPrimitiveProcessor&, const GrRenderTarget*, GrSurfaceOrigin,
const GrPipeline&);
dawn::BindGroup setData(GrDawnGpu* gpu, const GrRenderTarget*, GrSurfaceOrigin origin,
const GrPrimitiveProcessor&, const GrPipeline&,
const GrTextureProxy* const primProcTextures[]);
};
class GrDawnProgramBuilder : public GrGLSLProgramBuilder {

View File

@ -263,16 +263,17 @@ template<> struct set_uniform_matrix<4> {
}
};
void GrDawnProgramDataManager::uploadUniformBuffers(dawn::Buffer geometryBuffer,
dawn::Buffer fragmentBuffer) const {
if (geometryBuffer && fGeometryUniformsDirty) {
geometryBuffer.SetSubData(0, fGeometryUniformSize,
static_cast<const uint8_t*>(fGeometryUniformData.get()));
fGeometryUniformsDirty = false;
void GrDawnProgramDataManager::uploadUniformBuffers(GrDawnRingBuffer::Slice geometryBuffer,
GrDawnRingBuffer::Slice fragmentBuffer) const {
dawn::Buffer geom = geometryBuffer.fBuffer;
dawn::Buffer frag = fragmentBuffer.fBuffer;
if (geom && fGeometryUniformsDirty) {
geom.SetSubData(geometryBuffer.fOffset, fGeometryUniformSize,
static_cast<const uint8_t*>(fGeometryUniformData.get()));
}
if (fragmentBuffer && fFragmentUniformsDirty) {
fragmentBuffer.SetSubData(0, fFragmentUniformSize,
static_cast<const uint8_t*>(fFragmentUniformData.get()));
fFragmentUniformsDirty = false;
if (frag && fFragmentUniformsDirty) {
frag.SetSubData(fragmentBuffer.fOffset, fFragmentUniformSize,
static_cast<const uint8_t*>(fFragmentUniformData.get()));
}
}

View File

@ -8,6 +8,7 @@
#ifndef GrDawnProgramDataManager_DEFINED
#define GrDawnProgramDataManager_DEFINED
#include "src/gpu/dawn/GrDawnRingBuffer.h"
#include "src/gpu/dawn/GrDawnUniformHandler.h"
#include "src/gpu/glsl/GrGLSLProgramDataManager.h"
#include "dawn/dawncpp.h"
@ -57,8 +58,11 @@ public:
SK_ABORT("Only supported in NVPR, which is not in Dawn");
}
void uploadUniformBuffers(dawn::Buffer geometryBuffer, dawn::Buffer fragmentBuffer) const;
void uploadUniformBuffers(GrDawnRingBuffer::Slice geometryBuffer,
GrDawnRingBuffer::Slice fragmentBuffer) const;
uint32_t geometryUniformSize() const { return fGeometryUniformSize; }
uint32_t fragmentUniformSize() const { return fFragmentUniformSize; }
private:
struct Uniform {
uint32_t fBinding;

View File

@ -0,0 +1,36 @@
/*
* 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/GrDawnRingBuffer.h"
#include "src/gpu/dawn/GrDawnGpu.h"
#include "src/gpu/dawn/GrDawnUtil.h"
namespace {
const int kDefaultSize = 512 * 1024;
}
GrDawnRingBuffer::GrDawnRingBuffer(GrDawnGpu* gpu, dawn::BufferUsageBit usage)
: fGpu(gpu) , fUsage(usage) {
}
GrDawnRingBuffer::~GrDawnRingBuffer() {
}
GrDawnRingBuffer::Slice GrDawnRingBuffer::allocate(int size) {
if (!fBuffer || fOffset + size > kDefaultSize) {
dawn::BufferDescriptor desc;
desc.usage = fUsage | dawn::BufferUsageBit::CopyDst;
desc.size = kDefaultSize;
fBuffer = fGpu->device().CreateBuffer(&desc);
fOffset = 0;
}
int offset = fOffset;
fOffset += size;
fOffset = GrDawnRoundRowBytes(fOffset);
return Slice(fBuffer, offset);
}

View File

@ -0,0 +1,43 @@
/*
* 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 GrDawnRingBuffer_DEFINED
#define GrDawnRingBuffer_DEFINED
#include "src/gpu/GrBuffer.h"
#include "src/gpu/dawn/GrDawnBuffer.h"
#include "dawn/dawncpp.h"
class GrDawnGpu;
class GrDawnRingBuffer : public SkRefCnt {
public:
GrDawnRingBuffer(GrDawnGpu* gpu, dawn::BufferUsageBit usage);
~GrDawnRingBuffer() override;
struct Slice {
Slice(dawn::Buffer buffer, int offset) : fBuffer(buffer), fOffset(offset) {}
Slice() : fBuffer(nullptr), fOffset(0) {}
Slice(const Slice& other) : fBuffer(other.fBuffer), fOffset(other.fOffset) {}
Slice& operator=(const Slice& other) {
fBuffer = other.fBuffer;
fOffset = other.fOffset;
return *this;
}
dawn::Buffer fBuffer;
int fOffset;
};
Slice allocate(int size);
private:
GrDawnGpu* fGpu;
dawn::BufferUsageBit fUsage;
dawn::Buffer fBuffer;
int fOffset = 0;
};
#endif