Reland "GraphiteDawn: use dawn's LoadResolveTexture extension." x2
This is a reland of commit 6165e26f33aca1de3e6d87674113174b7153a136
What're changed:
- Include "load-resolve-to-msaa" bit flag in graphics pipeline keys.
The chromium test failures were caused by a cached pipeline being
returned but not compatible with the current render pass.
Original change's description:
> Reland "GraphiteDawn: use dawn's LoadResolveTexture extension."
>
> This is a reland of commit cb016dd7154aa0d8fd8a178d9f830ea3ba8f2a4b
>
> What're changed:
> - Restructure DawnCaps to avoid EMSCRIPTEN #ifdef
> - Use MultisampleStateExpandResolveTextureDawn chained struct
> to create graphics pipeline that is compatible with a render pass
> loading a resove texture.
>
> Original change's description:
> > GraphiteDawn: use dawn's LoadResolveTexture extension.
> >
> > This extension allows loading the resolve texture to MSAA texture
> > using a load op. The MSAA texture's memory will be controlled by
> > graphite unlike the old MSAARenderToSingleSampled feature.
> >
> > Bug: b/258652999
> > Change-Id: I3f537e278bd7787afc7404e611518cfa75136379
> > Reviewed-on: https://skia-review.googlesource.com/c/skia/+/849496
> > Reviewed-by: Michael Ludwig <michaelludwig@google.com>
> > Commit-Queue: Quyen Le <lehoangquyen@chromium.org>
> > Reviewed-by: Greg Daniel <egdaniel@google.com>
>
> Bug: b/258652999
> Change-Id: I8b4c4b4392256b509505cfca6116de2c4ce19178
> Reviewed-on: https://skia-review.googlesource.com/c/skia/+/853476
> Reviewed-by: Greg Daniel <egdaniel@google.com>
> Commit-Queue: Quyen Le <lehoangquyen@chromium.org>
> Reviewed-by: Michael Ludwig <michaelludwig@google.com>
Bug: b/258652999
Change-Id: I631195b2883b0414099df03a6f625509b718fb8c
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/855616
Reviewed-by: Greg Daniel <egdaniel@google.com>
Reviewed-by: Michael Ludwig <michaelludwig@google.com>
Commit-Queue: Quyen Le <lehoangquyen@chromium.org>
diff --git a/src/gpu/graphite/dawn/DawnCaps.cpp b/src/gpu/graphite/dawn/DawnCaps.cpp
index 934e2f6..153e16f 100644
--- a/src/gpu/graphite/dawn/DawnCaps.cpp
+++ b/src/gpu/graphite/dawn/DawnCaps.cpp
@@ -270,11 +270,10 @@
info.fViewFormat = singleSpec.fFormat;
info.fUsage = wgpu::TextureUsage::RenderAttachment;
-#if !defined(__EMSCRIPTEN__)
- if (fTransientAttachmentSupport && discardable == Discardable::kYes) {
- info.fUsage |= wgpu::TextureUsage::TransientAttachment;
+ if (fSupportedTransientAttachmentUsage != wgpu::TextureUsage::None &&
+ discardable == Discardable::kYes) {
+ info.fUsage |= fSupportedTransientAttachmentUsage;
}
-#endif
return info;
}
@@ -290,11 +289,9 @@
info.fViewFormat = info.fFormat;
info.fUsage = wgpu::TextureUsage::RenderAttachment;
-#if !defined(__EMSCRIPTEN__)
- if (fTransientAttachmentSupport) {
- info.fUsage |= wgpu::TextureUsage::TransientAttachment;
+ if (fSupportedTransientAttachmentUsage != wgpu::TextureUsage::None) {
+ info.fUsage |= fSupportedTransientAttachmentUsage;
}
-#endif
return info;
}
@@ -467,8 +464,12 @@
fMSAARenderToSingleSampledSupport =
backendContext.fDevice.HasFeature(wgpu::FeatureName::MSAARenderToSingleSampled);
- fTransientAttachmentSupport =
- backendContext.fDevice.HasFeature(wgpu::FeatureName::TransientAttachments);
+ if (backendContext.fDevice.HasFeature(wgpu::FeatureName::TransientAttachments)) {
+ fSupportedTransientAttachmentUsage = wgpu::TextureUsage::TransientAttachment;
+ }
+ if (backendContext.fDevice.HasFeature(wgpu::FeatureName::DawnLoadResolveTexture)) {
+ fSupportedResolveTextureLoadOp = wgpu::LoadOp::ExpandResolveTexture;
+ }
#endif
if (!backendContext.fTick) {
@@ -841,17 +842,36 @@
}
}
-uint64_t DawnCaps::getRenderPassDescKey(const RenderPassDesc& renderPassDesc) const {
+uint64_t DawnCaps::getRenderPassDescKeyForPipeline(const RenderPassDesc& renderPassDesc) const {
DawnTextureInfo colorInfo, depthStencilInfo;
renderPassDesc.fColorAttachment.fTextureInfo.getDawnTextureInfo(&colorInfo);
renderPassDesc.fDepthStencilAttachment.fTextureInfo.getDawnTextureInfo(&depthStencilInfo);
SkASSERT(static_cast<uint32_t>(colorInfo.getViewFormat()) <= 0xffff &&
- static_cast<uint32_t>(depthStencilInfo.getViewFormat()) <= 0xffff);
- uint32_t colorAttachmentKey =
- static_cast<uint32_t>(colorInfo.getViewFormat()) << 16 | colorInfo.fSampleCount;
+ static_cast<uint32_t>(depthStencilInfo.getViewFormat()) <= 0xffff &&
+ colorInfo.fSampleCount < 0x7fff);
+
+ // Note: if Dawn supports ExpandResolveTexture load op and the render pass uses it to load
+ // the resolve texture, a render pipeline will need to be created with
+ // wgpu::ColorTargetStateExpandResolveTextureDawn chained struct in order to be compatible.
+ // Hence a render pipeline created for a render pass using ExpandResolveTexture load op will
+ // be different from the one created for a render pass not using that load op.
+ // So we need to include a bit flag to differentiate the two kinds of pipelines.
+ // Also avoid returning a cached pipeline that is not compatible with the render pass using
+ // ExpandResolveTexture load op and vice versa.
+ const bool shouldIncludeLoadResolveAttachmentBit = this->resolveTextureLoadOp().has_value();
+ uint32_t loadResolveAttachmentKey = 0;
+ if (shouldIncludeLoadResolveAttachmentBit &&
+ renderPassDesc.fColorResolveAttachment.fTextureInfo.isValid() &&
+ renderPassDesc.fColorResolveAttachment.fLoadOp == LoadOp::kLoad) {
+ loadResolveAttachmentKey = 1;
+ }
+
+ uint32_t colorAttachmentKey = static_cast<uint32_t>(colorInfo.getViewFormat()) << 16 |
+ colorInfo.fSampleCount << 1 | loadResolveAttachmentKey;
+
uint32_t dsAttachmentKey = static_cast<uint32_t>(depthStencilInfo.getViewFormat()) << 16 |
depthStencilInfo.fSampleCount;
- return (((uint64_t) colorAttachmentKey) << 32) | dsAttachmentKey;
+ return (((uint64_t)colorAttachmentKey) << 32) | dsAttachmentKey;
}
UniqueKey DawnCaps::makeGraphicsPipelineKey(const GraphicsPipelineDesc& pipelineDesc,
@@ -865,8 +885,8 @@
builder[0] = pipelineDesc.renderStepID();
builder[1] = pipelineDesc.paintParamsID().asUInt();
- // add RenderPassDesc key
- uint64_t renderPassKey = this->getRenderPassDescKey(renderPassDesc);
+ // Add RenderPassDesc key.
+ uint64_t renderPassKey = this->getRenderPassDescKeyForPipeline(renderPassDesc);
builder[2] = renderPassKey & 0xFFFFFFFF;
builder[3] = (renderPassKey >> 32) & 0xFFFFFFFF;
builder[4] = renderPassDesc.fWriteSwizzle.asKey();
diff --git a/src/gpu/graphite/dawn/DawnCaps.h b/src/gpu/graphite/dawn/DawnCaps.h
index 2f5515c..2d8ef2a 100644
--- a/src/gpu/graphite/dawn/DawnCaps.h
+++ b/src/gpu/graphite/dawn/DawnCaps.h
@@ -27,6 +27,11 @@
bool useAsyncPipelineCreation() const { return fUseAsyncPipelineCreation; }
bool allowScopedErrorChecks() const { return fAllowScopedErrorChecks; }
+ // If this has no value then loading the resolve texture via a LoadOp is not supported.
+ std::optional<wgpu::LoadOp> resolveTextureLoadOp() const {
+ return fSupportedResolveTextureLoadOp;
+ }
+
TextureInfo getDefaultSampledTextureInfo(SkColorType,
Mipmapped mipmapped,
Protected,
@@ -55,7 +60,7 @@
ResourceType,
Shareable,
GraphiteResourceKey*) const override;
- uint64_t getRenderPassDescKey(const RenderPassDesc& renderPassDesc) const;
+ uint64_t getRenderPassDescKeyForPipeline(const RenderPassDesc& renderPassDesc) const;
static constexpr size_t kFormatCnt = 17;
@@ -123,9 +128,11 @@
wgpu::TextureFormat fColorTypeToFormatTable[kSkColorTypeCnt];
void setColorType(SkColorType, std::initializer_list<wgpu::TextureFormat> formats);
-#if !defined(__EMSCRIPTEN__)
- bool fTransientAttachmentSupport = false;
-#endif
+ // When supported, this value will hold the TransientAttachment usage symbol that is only
+ // defined in Dawn native builds and not EMSCRIPTEN but this avoids having to #define guard it.
+ wgpu::TextureUsage fSupportedTransientAttachmentUsage = wgpu::TextureUsage::None;
+ // When supported this holds the ExpandResolveTexture load op, otherwise holds no value.
+ std::optional<wgpu::LoadOp> fSupportedResolveTextureLoadOp;
bool fUseAsyncPipelineCreation = true;
bool fAllowScopedErrorChecks = true;
diff --git a/src/gpu/graphite/dawn/DawnCommandBuffer.cpp b/src/gpu/graphite/dawn/DawnCommandBuffer.cpp
index b04fe0c..3cd0d60 100644
--- a/src/gpu/graphite/dawn/DawnCommandBuffer.cpp
+++ b/src/gpu/graphite/dawn/DawnCommandBuffer.cpp
@@ -165,7 +165,7 @@
wgpu::RenderPassDepthStencilAttachment wgpuDepthStencilAttachment;
// Set up color attachment.
-#ifndef __EMSCRIPTEN__
+#if !defined(__EMSCRIPTEN__)
wgpu::DawnRenderPassColorAttachmentRenderToSingleSampled mssaRenderToSingleSampledDesc;
#endif
@@ -199,8 +199,16 @@
SkASSERT(wgpuColorAttachment.storeOp == wgpu::StoreOp::Discard);
// But it also means we have to load the resolve texture into the MSAA color attachment
- loadMSAAFromResolveExplicitly =
- renderPassDesc.fColorResolveAttachment.fLoadOp == LoadOp::kLoad;
+ if (renderPassDesc.fColorResolveAttachment.fLoadOp == LoadOp::kLoad) {
+ std::optional<wgpu::LoadOp> resolveLoadOp =
+ fSharedContext->dawnCaps()->resolveTextureLoadOp();
+ if (resolveLoadOp.has_value()) {
+ wgpuColorAttachment.loadOp = *resolveLoadOp;
+ } else {
+ // No Dawn built-in support, we need to manually load the resolve texture.
+ loadMSAAFromResolveExplicitly = true;
+ }
+ }
// TODO: If the color resolve texture is read-only we can use a private (vs. memoryless)
// msaa attachment that's coupled to the framebuffer and the StoreAndMultisampleResolve
// action instead of loading as a draw.
diff --git a/src/gpu/graphite/dawn/DawnGraphicsPipeline.cpp b/src/gpu/graphite/dawn/DawnGraphicsPipeline.cpp
index ea3b820..49fb848 100644
--- a/src/gpu/graphite/dawn/DawnGraphicsPipeline.cpp
+++ b/src/gpu/graphite/dawn/DawnGraphicsPipeline.cpp
@@ -362,6 +362,20 @@
colorTarget.writeMask = blendInfo.fWritesColor && hasFragmentSkSL ? wgpu::ColorWriteMask::All
: wgpu::ColorWriteMask::None;
+#if !defined(__EMSCRIPTEN__)
+ const bool loadMsaaFromResolve =
+ renderPassDesc.fColorResolveAttachment.fTextureInfo.isValid() &&
+ renderPassDesc.fColorResolveAttachment.fLoadOp == LoadOp::kLoad;
+ // Special case: a render pass loading resolve texture requires additional settings for the
+ // pipeline to make it compatible.
+ wgpu::ColorTargetStateExpandResolveTextureDawn pipelineMSAALoadResolveTextureDesc;
+ if (loadMsaaFromResolve && sharedContext->dawnCaps()->resolveTextureLoadOp().has_value()) {
+ SkASSERT(device.HasFeature(wgpu::FeatureName::DawnLoadResolveTexture));
+ colorTarget.nextInChain = &pipelineMSAALoadResolveTextureDesc;
+ pipelineMSAALoadResolveTextureDesc.enabled = true;
+ }
+#endif
+
wgpu::FragmentState fragment;
// Dawn doesn't allow having a color attachment but without fragment shader, so have to use a
// noop fragment shader, if fragment shader is null.
@@ -508,7 +522,7 @@
// Other state
descriptor.primitive.frontFace = wgpu::FrontFace::CCW;
descriptor.primitive.cullMode = wgpu::CullMode::None;
- switch(step->primitiveType()) {
+ switch (step->primitiveType()) {
case PrimitiveType::kTriangles:
descriptor.primitive.topology = wgpu::PrimitiveTopology::TriangleList;
break;
@@ -523,24 +537,6 @@
// Multisampled state
descriptor.multisample.count = renderPassDesc.fSampleCount;
- [[maybe_unused]] bool isMSAARenderToSingleSampled =
- renderPassDesc.fSampleCount > 1 &&
- renderPassDesc.fColorAttachment.fTextureInfo.isValid() &&
- renderPassDesc.fColorAttachment.fTextureInfo.numSamples() == 1;
-#if defined(__EMSCRIPTEN__)
- SkASSERT(!isMSAARenderToSingleSampled);
-#else
- wgpu::DawnMultisampleStateRenderToSingleSampled pipelineMSAARenderToSingleSampledDesc;
- if (isMSAARenderToSingleSampled) {
- // If render pass is multi sampled but the color attachment is single sampled, we need
- // to activate multisampled render to single sampled feature for this graphics pipeline.
- SkASSERT(device.HasFeature(wgpu::FeatureName::MSAARenderToSingleSampled));
-
- descriptor.multisample.nextInChain = &pipelineMSAARenderToSingleSampledDesc;
- pipelineMSAARenderToSingleSampledDesc.enabled = true;
- }
-#endif
-
descriptor.multisample.mask = 0xFFFFFFFF;
descriptor.multisample.alphaToCoverageEnabled = false;
diff --git a/src/gpu/graphite/dawn/DawnResourceProvider.cpp b/src/gpu/graphite/dawn/DawnResourceProvider.cpp
index ee35c7f..a343641 100644
--- a/src/gpu/graphite/dawn/DawnResourceProvider.cpp
+++ b/src/gpu/graphite/dawn/DawnResourceProvider.cpp
@@ -162,7 +162,7 @@
wgpu::RenderPipeline DawnResourceProvider::findOrCreateBlitWithDrawPipeline(
const RenderPassDesc& renderPassDesc) {
uint64_t renderPassKey =
- this->dawnSharedContext()->dawnCaps()->getRenderPassDescKey(renderPassDesc);
+ this->dawnSharedContext()->dawnCaps()->getRenderPassDescKeyForPipeline(renderPassDesc);
wgpu::RenderPipeline pipeline = fBlitWithDrawPipelines[renderPassKey];
if (!pipeline) {
static constexpr char kVertexShaderText[] = R"(
diff --git a/tools/graphite/dawn/GraphiteDawnTestContext.cpp b/tools/graphite/dawn/GraphiteDawnTestContext.cpp
index e2ef3d0..f056197 100644
--- a/tools/graphite/dawn/GraphiteDawnTestContext.cpp
+++ b/tools/graphite/dawn/GraphiteDawnTestContext.cpp
@@ -121,6 +121,9 @@
if (adapter.HasFeature(wgpu::FeatureName::R8UnormStorage)) {
features.push_back(wgpu::FeatureName::R8UnormStorage);
}
+ if (adapter.HasFeature(wgpu::FeatureName::DawnLoadResolveTexture)) {
+ features.push_back(wgpu::FeatureName::DawnLoadResolveTexture);
+ }
wgpu::DeviceDescriptor desc;
desc.requiredFeatureCount = features.size();
diff --git a/tools/window/GraphiteDawnWindowContext.cpp b/tools/window/GraphiteDawnWindowContext.cpp
index fe09208..41cb938 100644
--- a/tools/window/GraphiteDawnWindowContext.cpp
+++ b/tools/window/GraphiteDawnWindowContext.cpp
@@ -162,6 +162,9 @@
if (adapter.HasFeature(wgpu::FeatureName::R8UnormStorage)) {
features.push_back(wgpu::FeatureName::R8UnormStorage);
}
+ if (adapter.HasFeature(wgpu::FeatureName::DawnLoadResolveTexture)) {
+ features.push_back(wgpu::FeatureName::DawnLoadResolveTexture);
+ }
wgpu::DeviceDescriptor deviceDescriptor;
deviceDescriptor.requiredFeatures = features.data();