blob: 173a66e450d84ccfd97125e6f05eb37c99fb9f37 [file] [log] [blame]
/*
* Copyright 2022 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/graphite/dawn/DawnSharedContext.h"
#include "include/gpu/graphite/Context.h"
#include "include/gpu/graphite/ContextOptions.h"
#include "include/gpu/graphite/dawn/DawnBackendContext.h"
#include "src/gpu/graphite/Log.h"
#include "src/gpu/graphite/dawn/DawnGraphicsPipeline.h"
#include "src/gpu/graphite/dawn/DawnResourceProvider.h"
#include "webgpu/webgpu_cpp.h" // NO_G3_REWRITE
namespace skgpu::graphite {
namespace {
wgpu::ShaderModule CreateNoopFragment(const wgpu::Device& device) {
#if defined(__EMSCRIPTEN__)
wgpu::ShaderModuleWGSLDescriptor wgslDesc;
#else
wgpu::ShaderSourceWGSL wgslDesc;
#endif
wgslDesc.code =
"@fragment\n"
"fn main() {}\n";
wgpu::ShaderModuleDescriptor smDesc;
smDesc.nextInChain = &wgslDesc;
smDesc.label = "no-op";
auto fsModule = device.CreateShaderModule(&smDesc);
return fsModule;
}
}
sk_sp<SharedContext> DawnSharedContext::Make(const DawnBackendContext& backendContext,
const ContextOptions& options) {
if (!backendContext.fDevice || !backendContext.fQueue) {
return {};
}
auto noopFragment = CreateNoopFragment(backendContext.fDevice);
if (!noopFragment) {
return {};
}
auto caps = std::make_unique<const DawnCaps>(backendContext, options);
return sk_sp<SharedContext>(new DawnSharedContext(backendContext,
std::move(caps),
std::move(noopFragment),
options.fExecutor,
options.fUserDefinedKnownRuntimeEffects));
}
DawnSharedContext::DawnSharedContext(const DawnBackendContext& backendContext,
std::unique_ptr<const DawnCaps> caps,
wgpu::ShaderModule noopFragment,
SkExecutor* executor,
SkSpan<sk_sp<SkRuntimeEffect>> userDefinedKnownRuntimeEffects)
: SharedContext(std::move(caps),
BackendApi::kDawn,
executor,
userDefinedKnownRuntimeEffects)
, fInstance(backendContext.fInstance)
, fDevice(backendContext.fDevice)
, fQueue(backendContext.fQueue)
, fTick(backendContext.fTick)
, fNoopFragment(std::move(noopFragment)) {
this->createUniformBuffersBindGroupLayout();
this->createSingleTextureSamplerBindGroupLayout();
}
DawnSharedContext::~DawnSharedContext() {
// need to clear out resources before any allocator is removed
this->globalCache()->deleteResources();
}
std::unique_ptr<ResourceProvider> DawnSharedContext::makeResourceProvider(
SingleOwner* singleOwner,
uint32_t recorderID,
size_t resourceBudget) {
return std::unique_ptr<ResourceProvider>(new DawnResourceProvider(this,
singleOwner,
recorderID,
resourceBudget));
}
void DawnSharedContext::deviceTick(Context* context) {
#if !defined(__EMSCRIPTEN__)
this->device().Tick();
#endif
context->checkAsyncWorkCompletion();
};
void DawnSharedContext::createUniformBuffersBindGroupLayout() {
const Caps* caps = this->caps();
std::array<wgpu::BindGroupLayoutEntry, 4> entries;
entries[0].binding = DawnGraphicsPipeline::kIntrinsicUniformBufferIndex;
entries[0].visibility = wgpu::ShaderStage::Vertex | wgpu::ShaderStage::Fragment;
entries[0].buffer.type = wgpu::BufferBindingType::Uniform;
entries[0].buffer.hasDynamicOffset = true;
entries[0].buffer.minBindingSize = 0;
entries[1].binding = DawnGraphicsPipeline::kRenderStepUniformBufferIndex;
entries[1].visibility = wgpu::ShaderStage::Vertex | wgpu::ShaderStage::Fragment;
entries[1].buffer.type = caps->storageBufferSupport()
? wgpu::BufferBindingType::ReadOnlyStorage
: wgpu::BufferBindingType::Uniform;
entries[1].buffer.hasDynamicOffset = true;
entries[1].buffer.minBindingSize = 0;
entries[2].binding = DawnGraphicsPipeline::kPaintUniformBufferIndex;
entries[2].visibility = wgpu::ShaderStage::Vertex | wgpu::ShaderStage::Fragment;
entries[2].buffer.type = caps->storageBufferSupport()
? wgpu::BufferBindingType::ReadOnlyStorage
: wgpu::BufferBindingType::Uniform;
entries[2].buffer.hasDynamicOffset = true;
entries[2].buffer.minBindingSize = 0;
// Gradient buffer will only be used when storage buffers are preferred, else large
// gradients use a texture fallback, set binding type as a uniform when not in use to
// satisfy any binding type restrictions for non-supported ssbo devices.
entries[3].binding = DawnGraphicsPipeline::kGradientBufferIndex;
entries[3].visibility = wgpu::ShaderStage::Fragment;
entries[3].buffer.type = caps->storageBufferSupport()
? wgpu::BufferBindingType::ReadOnlyStorage
: wgpu::BufferBindingType::Uniform;
entries[3].buffer.hasDynamicOffset = true;
entries[3].buffer.minBindingSize = 0;
wgpu::BindGroupLayoutDescriptor groupLayoutDesc;
if (caps->setBackendLabels()) {
groupLayoutDesc.label = "Uniform buffers bind group layout";
}
groupLayoutDesc.entryCount = entries.size();
groupLayoutDesc.entries = entries.data();
fUniformBuffersBindGroupLayout = this->device().CreateBindGroupLayout(&groupLayoutDesc);
}
void DawnSharedContext::createSingleTextureSamplerBindGroupLayout() {
const Caps* caps = this->caps();
std::array<wgpu::BindGroupLayoutEntry, 2> entries;
entries[0].binding = 0;
entries[0].visibility = wgpu::ShaderStage::Fragment;
entries[0].sampler.type = wgpu::SamplerBindingType::Filtering;
entries[1].binding = 1;
entries[1].visibility = wgpu::ShaderStage::Fragment;
entries[1].texture.sampleType = wgpu::TextureSampleType::Float;
entries[1].texture.viewDimension = wgpu::TextureViewDimension::e2D;
entries[1].texture.multisampled = false;
wgpu::BindGroupLayoutDescriptor groupLayoutDesc;
if (caps->setBackendLabels()) {
groupLayoutDesc.label = "Single texture + sampler bind group layout";
}
groupLayoutDesc.entryCount = entries.size();
groupLayoutDesc.entries = entries.data();
fSingleTextureSamplerBindGroupLayout = this->device().CreateBindGroupLayout(&groupLayoutDesc);
}
} // namespace skgpu::graphite