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>
diff --git a/src/gpu/dawn/GrDawnGpu.cpp b/src/gpu/dawn/GrDawnGpu.cpp
index 1fd124f..f21cbb9 100644
--- a/src/gpu/dawn/GrDawnGpu.cpp
+++ b/src/gpu/dawn/GrDawnGpu.cpp
@@ -49,7 +49,8 @@
: 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 @@
SkASSERT(!"unimplemented");
return nullptr;
}
+
+GrDawnRingBuffer::Slice GrDawnGpu::allocateUniformRingBufferSlice(int size) {
+ return fUniformRingBuffer.allocate(size);
+}
diff --git a/src/gpu/dawn/GrDawnGpu.h b/src/gpu/dawn/GrDawnGpu.h
index 3973055..736e6cc 100644
--- a/src/gpu/dawn/GrDawnGpu.h
+++ b/src/gpu/dawn/GrDawnGpu.h
@@ -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 @@
sk_sp<GrSemaphore> prepareTextureForCrossContextUsage(GrTexture*) override;
+ GrDawnRingBuffer::Slice allocateUniformRingBufferSlice(int size);
+
private:
void onResetContext(uint32_t resetBits) override {}
@@ -147,6 +150,7 @@
std::unique_ptr<SkSL::Compiler> fCompiler;
std::unique_ptr<GrDawnGpuRTCommandBuffer> fRTCommandBuffer;
std::unique_ptr<GrDawnGpuTextureCommandBuffer> fTextureCommandBuffer;
+ GrDawnRingBuffer fUniformRingBuffer;
typedef GrGpu INHERITED;
};
diff --git a/src/gpu/dawn/GrDawnGpuCommandBuffer.cpp b/src/gpu/dawn/GrDawnGpuCommandBuffer.cpp
index 020207e..312663d 100644
--- a/src/gpu/dawn/GrDawnGpuCommandBuffer.cpp
+++ b/src/gpu/dawn/GrDawnGpuCommandBuffer.cpp
@@ -326,7 +326,8 @@
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 @@
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);
}
diff --git a/src/gpu/dawn/GrDawnProgramBuilder.cpp b/src/gpu/dawn/GrDawnProgramBuilder.cpp
index f0fe759..db51fce 100644
--- a/src/gpu/dawn/GrDawnProgramBuilder.cpp
+++ b/src/gpu/dawn/GrDawnProgramBuilder.cpp
@@ -347,54 +347,11 @@
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::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);
}
diff --git a/src/gpu/dawn/GrDawnProgramBuilder.h b/src/gpu/dawn/GrDawnProgramBuilder.h
index 319dff9..a98f270 100644
--- a/src/gpu/dawn/GrDawnProgramBuilder.h
+++ b/src/gpu/dawn/GrDawnProgramBuilder.h
@@ -60,8 +60,7 @@
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 @@
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 {
diff --git a/src/gpu/dawn/GrDawnProgramDataManager.cpp b/src/gpu/dawn/GrDawnProgramDataManager.cpp
index 45371f4..b2bb013 100644
--- a/src/gpu/dawn/GrDawnProgramDataManager.cpp
+++ b/src/gpu/dawn/GrDawnProgramDataManager.cpp
@@ -263,16 +263,17 @@
}
};
-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()));
}
}
diff --git a/src/gpu/dawn/GrDawnProgramDataManager.h b/src/gpu/dawn/GrDawnProgramDataManager.h
index 0b2f35e..d74f1ee 100644
--- a/src/gpu/dawn/GrDawnProgramDataManager.h
+++ b/src/gpu/dawn/GrDawnProgramDataManager.h
@@ -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 @@
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;
diff --git a/src/gpu/dawn/GrDawnRingBuffer.cpp b/src/gpu/dawn/GrDawnRingBuffer.cpp
new file mode 100644
index 0000000..0e26369
--- /dev/null
+++ b/src/gpu/dawn/GrDawnRingBuffer.cpp
@@ -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);
+}
diff --git a/src/gpu/dawn/GrDawnRingBuffer.h b/src/gpu/dawn/GrDawnRingBuffer.h
new file mode 100644
index 0000000..48e2576
--- /dev/null
+++ b/src/gpu/dawn/GrDawnRingBuffer.h
@@ -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