[graphite] Add command buffer submission and tracking
Bug: skia:12466 Change-Id: I965417fc1de471af33a31155abf2760d5d1b4f62 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/457317 Commit-Queue: Jim Van Verth <jvanverth@google.com> Reviewed-by: Greg Daniel <egdaniel@google.com>
This commit is contained in:
parent
73065f325f
commit
dc6a9e3e12
@ -8,15 +8,22 @@
|
||||
#ifndef skgpu_CommandBuffer_DEFINED
|
||||
#define skgpu_CommandBuffer_DEFINED
|
||||
|
||||
namespace skgpu {
|
||||
#include "include/core/SkRefCnt.h"
|
||||
|
||||
class CommandBuffer {
|
||||
namespace skgpu {
|
||||
class Gpu;
|
||||
|
||||
class CommandBuffer : public SkRefCnt {
|
||||
public:
|
||||
virtual ~CommandBuffer() {}
|
||||
~CommandBuffer() override {}
|
||||
|
||||
bool hasWork() { return fHasWork; }
|
||||
|
||||
protected:
|
||||
CommandBuffer();
|
||||
|
||||
bool fHasWork = false;
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
|
@ -8,16 +8,70 @@
|
||||
#include "experimental/graphite/src/Gpu.h"
|
||||
|
||||
#include "experimental/graphite/src/Caps.h"
|
||||
#include "experimental/graphite/src/CommandBuffer.h"
|
||||
#include "experimental/graphite/src/GpuWorkSubmission.h"
|
||||
#include "experimental/graphite/src/ResourceProvider.h"
|
||||
|
||||
namespace skgpu {
|
||||
|
||||
// This constant determines how many OutstandingSubmissions are allocated together as a block in
|
||||
// the deque. As such it needs to balance allocating too much memory vs. incurring
|
||||
// allocation/deallocation thrashing. It should roughly correspond to the max number of outstanding
|
||||
// submissions we expect to see.
|
||||
static constexpr int kDefaultOutstandingAllocCnt = 8;
|
||||
|
||||
Gpu::Gpu(sk_sp<const Caps> caps)
|
||||
: fCaps(std::move(caps)) {
|
||||
: fOutstandingSubmissions(sizeof(OutstandingSubmission), kDefaultOutstandingAllocCnt)
|
||||
, fCaps(std::move(caps)) {
|
||||
// subclasses create their own subclassed resource provider
|
||||
}
|
||||
|
||||
Gpu::~Gpu() {
|
||||
// TODO: add disconnect?
|
||||
|
||||
|
||||
// TODO: destroyResources instead?
|
||||
// TODO: how do we handle command buffers that haven't been submitted yet?
|
||||
this->checkForFinishedWork(SyncToCpu::kYes);
|
||||
fResourceProvider.reset();
|
||||
}
|
||||
|
||||
bool Gpu::submit(sk_sp<CommandBuffer> commandBuffer) {
|
||||
if (!commandBuffer) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!commandBuffer->hasWork()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return this->onSubmit(std::move(commandBuffer));
|
||||
}
|
||||
|
||||
void Gpu::checkForFinishedWork(SyncToCpu sync) {
|
||||
if (sync == SyncToCpu::kYes) {
|
||||
// wait for the last submission to finish
|
||||
OutstandingSubmission* back = (OutstandingSubmission*)fOutstandingSubmissions.back();
|
||||
if (back) {
|
||||
(*back)->waitUntilFinished(this);
|
||||
}
|
||||
}
|
||||
|
||||
// Iterate over all the outstanding submissions to see if any have finished. The work
|
||||
// submissions are in order from oldest to newest, so we start at the front to check if they
|
||||
// have finished. If so we pop it off and move onto the next.
|
||||
// Repeat till we find a submission that has not finished yet (and all others afterwards are
|
||||
// also guaranteed to not have finished).
|
||||
OutstandingSubmission* front = (OutstandingSubmission*)fOutstandingSubmissions.front();
|
||||
while (front && (*front)->isFinished()) {
|
||||
// Make sure we remove before deleting as deletion might try to kick off another submit
|
||||
// (though hopefully *not* in Graphite).
|
||||
fOutstandingSubmissions.pop_front();
|
||||
// Since we used placement new we are responsible for calling the destructor manually.
|
||||
front->~OutstandingSubmission();
|
||||
front = (OutstandingSubmission*)fOutstandingSubmissions.front();
|
||||
}
|
||||
SkASSERT(sync == SyncToCpu::kNo || fOutstandingSubmissions.empty());
|
||||
}
|
||||
|
||||
} // namespace skgpu
|
||||
|
@ -9,11 +9,14 @@
|
||||
#define skgpu_Gpu_DEFINED
|
||||
|
||||
#include "include/core/SkRefCnt.h"
|
||||
#include "include/private/SkDeque.h"
|
||||
|
||||
namespace skgpu {
|
||||
|
||||
class Caps;
|
||||
class ResourceProvider;
|
||||
class CommandBuffer;
|
||||
class GpuWorkSubmission;
|
||||
|
||||
class Gpu : public SkRefCnt {
|
||||
public:
|
||||
@ -27,12 +30,27 @@ public:
|
||||
|
||||
ResourceProvider* resourceProvider() const { return fResourceProvider.get(); }
|
||||
|
||||
/**
|
||||
* Submit command buffer to GPU and track completion
|
||||
*/
|
||||
enum class SyncToCpu : bool {
|
||||
kYes = true,
|
||||
kNo = false
|
||||
};
|
||||
bool submit(sk_sp<CommandBuffer>);
|
||||
void checkForFinishedWork(SyncToCpu);
|
||||
|
||||
protected:
|
||||
Gpu(sk_sp<const Caps>);
|
||||
|
||||
std::unique_ptr<ResourceProvider> fResourceProvider;
|
||||
|
||||
using OutstandingSubmission = std::unique_ptr<GpuWorkSubmission>;
|
||||
SkDeque fOutstandingSubmissions;
|
||||
|
||||
private:
|
||||
virtual bool onSubmit(sk_sp<CommandBuffer>) = 0;
|
||||
|
||||
sk_sp<const Caps> fCaps;
|
||||
};
|
||||
|
||||
|
29
experimental/graphite/src/GpuWorkSubmission.h
Normal file
29
experimental/graphite/src/GpuWorkSubmission.h
Normal file
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright 2021 Google LLC
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef skgpu_GpuWorkSubmission_DEFINED
|
||||
#define skgpu_GpuWorkSubmission_DEFINED
|
||||
|
||||
namespace skgpu {
|
||||
class Gpu;
|
||||
|
||||
class GpuWorkSubmission {
|
||||
public:
|
||||
virtual ~GpuWorkSubmission() = default;
|
||||
|
||||
virtual bool isFinished() = 0;
|
||||
virtual void waitUntilFinished(const Gpu*) = 0;
|
||||
|
||||
protected:
|
||||
GpuWorkSubmission() = default;
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
} // namespace skgpu
|
||||
|
||||
#endif // skgpu_GpuWorkSubmission_DEFINED
|
@ -21,12 +21,6 @@ ResourceProvider::~ResourceProvider() {
|
||||
fRenderPipelineCache.release();
|
||||
}
|
||||
|
||||
std::unique_ptr<CommandBuffer> ResourceProvider::createCommandBuffer() {
|
||||
// TODO: cache the commandbuffer in an active list and return raw pointer instead
|
||||
|
||||
return this->onCreateCommandBuffer();
|
||||
}
|
||||
|
||||
RenderPipeline* ResourceProvider::findOrCreateRenderPipeline(const RenderPipelineDesc& desc) {
|
||||
return fRenderPipelineCache->refPipeline(desc);
|
||||
}
|
||||
|
@ -26,7 +26,8 @@ class ResourceProvider {
|
||||
public:
|
||||
virtual ~ResourceProvider();
|
||||
|
||||
std::unique_ptr<CommandBuffer> createCommandBuffer();
|
||||
virtual sk_sp<CommandBuffer> createCommandBuffer() = 0;
|
||||
|
||||
RenderPipeline* findOrCreateRenderPipeline(const RenderPipelineDesc&);
|
||||
|
||||
sk_sp<Texture> findOrCreateTexture(SkISize, const TextureInfo&);
|
||||
@ -37,7 +38,6 @@ protected:
|
||||
const Gpu* fGpu;
|
||||
|
||||
private:
|
||||
virtual std::unique_ptr<CommandBuffer> onCreateCommandBuffer() = 0;
|
||||
virtual std::unique_ptr<RenderPipeline> onCreateRenderPipeline(const RenderPipelineDesc&) = 0;
|
||||
virtual sk_sp<Texture> createTexture(SkISize, const TextureInfo&) = 0;
|
||||
|
||||
|
@ -9,6 +9,7 @@
|
||||
#define skgpu_MtlCommandBuffer_DEFINED
|
||||
|
||||
#include "experimental/graphite/src/CommandBuffer.h"
|
||||
#include "experimental/graphite/src/GpuWorkSubmission.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
@ -22,9 +23,22 @@ class Gpu;
|
||||
|
||||
class CommandBuffer final : public skgpu::CommandBuffer {
|
||||
public:
|
||||
static std::unique_ptr<CommandBuffer> Make(const Gpu*);
|
||||
static sk_sp<CommandBuffer> Make(const Gpu*);
|
||||
~CommandBuffer() override {}
|
||||
|
||||
bool isFinished() {
|
||||
return (*fCommandBuffer).status == MTLCommandBufferStatusCompleted ||
|
||||
(*fCommandBuffer).status == MTLCommandBufferStatusError;
|
||||
|
||||
}
|
||||
void waitUntilFinished() {
|
||||
// TODO: it's not clear what do to if status is Enqueued. Commit and then wait?
|
||||
if ((*fCommandBuffer).status == MTLCommandBufferStatusCommitted) {
|
||||
[(*fCommandBuffer) waitUntilCompleted];
|
||||
}
|
||||
}
|
||||
bool commit();
|
||||
|
||||
private:
|
||||
CommandBuffer(sk_cfp<id<MTLCommandBuffer>> cmdBuffer)
|
||||
: fCommandBuffer(std::move(cmdBuffer)) {}
|
||||
|
@ -11,7 +11,7 @@
|
||||
|
||||
namespace skgpu::mtl {
|
||||
|
||||
std::unique_ptr<CommandBuffer> CommandBuffer::Make(const Gpu* gpu) {
|
||||
sk_sp<CommandBuffer> CommandBuffer::Make(const Gpu* gpu) {
|
||||
sk_cfp<id<MTLCommandBuffer>> cmdBuffer;
|
||||
id<MTLCommandQueue> queue = gpu->queue();
|
||||
if (@available(macOS 11.0, iOS 14.0, tvOS 14.0, *)) {
|
||||
@ -34,7 +34,22 @@ std::unique_ptr<CommandBuffer> CommandBuffer::Make(const Gpu* gpu) {
|
||||
(*cmdBuffer).label = @"CommandBuffer::Make";
|
||||
#endif
|
||||
|
||||
return std::unique_ptr<CommandBuffer>(new CommandBuffer(std::move(cmdBuffer)));
|
||||
return sk_sp<CommandBuffer>(new CommandBuffer(std::move(cmdBuffer)));
|
||||
}
|
||||
|
||||
bool CommandBuffer::commit() {
|
||||
// TODO: end any encoding
|
||||
[(*fCommandBuffer) commit];
|
||||
|
||||
// TODO: better error reporting
|
||||
if ((*fCommandBuffer).status == MTLCommandBufferStatusError) {
|
||||
NSString* description = (*fCommandBuffer).error.localizedDescription;
|
||||
const char* errorString = [description UTF8String];
|
||||
SkDebugf("Error submitting command buffer: %s\n", errorString);
|
||||
}
|
||||
|
||||
return ((*fCommandBuffer).status != MTLCommandBufferStatusError);
|
||||
}
|
||||
|
||||
|
||||
} // namespace skgpu::mtl
|
||||
|
@ -32,6 +32,8 @@ public:
|
||||
private:
|
||||
Gpu(sk_cfp<id<MTLDevice>>, sk_cfp<id<MTLCommandQueue>>, sk_sp<const Caps>);
|
||||
|
||||
bool onSubmit(sk_sp<skgpu::CommandBuffer>) override;
|
||||
|
||||
sk_cfp<id<MTLDevice>> fDevice;
|
||||
sk_cfp<id<MTLCommandQueue>> fQueue;
|
||||
};
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include "experimental/graphite/src/mtl/MtlGpu.h"
|
||||
|
||||
#include "experimental/graphite/src/Caps.h"
|
||||
#include "experimental/graphite/src/mtl/MtlCommandBuffer.h"
|
||||
#include "experimental/graphite/src/mtl/MtlResourceProvider.h"
|
||||
|
||||
namespace skgpu::mtl {
|
||||
@ -31,4 +32,34 @@ Gpu::Gpu(sk_cfp<id<MTLDevice>> device, sk_cfp<id<MTLCommandQueue>> queue, sk_sp<
|
||||
Gpu::~Gpu() {
|
||||
}
|
||||
|
||||
class WorkSubmission final : public skgpu::GpuWorkSubmission {
|
||||
public:
|
||||
WorkSubmission(sk_sp<CommandBuffer> cmdBuffer)
|
||||
: fCommandBuffer(std::move(cmdBuffer)) {}
|
||||
~WorkSubmission() override {}
|
||||
|
||||
bool isFinished() override {
|
||||
return fCommandBuffer->isFinished();
|
||||
}
|
||||
void waitUntilFinished(const skgpu::Gpu*) override {
|
||||
return fCommandBuffer->waitUntilFinished();
|
||||
}
|
||||
|
||||
private:
|
||||
sk_sp<CommandBuffer> fCommandBuffer;
|
||||
};
|
||||
|
||||
bool Gpu::onSubmit(sk_sp<skgpu::CommandBuffer> commandBuffer) {
|
||||
SkASSERT(commandBuffer);
|
||||
sk_sp<CommandBuffer>& mtlCmdBuffer = (sk_sp<CommandBuffer>&)(commandBuffer);
|
||||
if (!mtlCmdBuffer->commit()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::unique_ptr<WorkSubmission> submission(new WorkSubmission(mtlCmdBuffer));
|
||||
new (fOutstandingSubmissions.push_back()) OutstandingSubmission(std::move(submission));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace skgpu::mtl
|
||||
|
@ -28,7 +28,7 @@ public:
|
||||
private:
|
||||
const Gpu* mtlGpu();
|
||||
|
||||
std::unique_ptr<skgpu::CommandBuffer> onCreateCommandBuffer() override;
|
||||
sk_sp<skgpu::CommandBuffer> createCommandBuffer() override;
|
||||
std::unique_ptr<skgpu::RenderPipeline> onCreateRenderPipeline(
|
||||
const RenderPipelineDesc&) override;
|
||||
sk_sp<skgpu::Texture> createTexture(SkISize, const skgpu::TextureInfo&) override;
|
||||
|
@ -24,7 +24,7 @@ const Gpu* ResourceProvider::mtlGpu() {
|
||||
return static_cast<const Gpu*>(fGpu);
|
||||
}
|
||||
|
||||
std::unique_ptr<skgpu::CommandBuffer> ResourceProvider::onCreateCommandBuffer() {
|
||||
sk_sp<skgpu::CommandBuffer> ResourceProvider::createCommandBuffer() {
|
||||
return CommandBuffer::Make(this->mtlGpu());
|
||||
}
|
||||
|
||||
|
@ -33,6 +33,7 @@ skia_graphite_sources = [
|
||||
"$_src/DrawPass.h",
|
||||
"$_src/Gpu.cpp",
|
||||
"$_src/Gpu.h",
|
||||
"$_src/GpuWorkSubmission.h",
|
||||
"$_src/Image_Graphite.cpp",
|
||||
"$_src/Image_Graphite.h",
|
||||
"$_src/Recorder.cpp",
|
||||
|
Loading…
Reference in New Issue
Block a user