blob: c916dc8f9e20617ad5e32f3216e7bbcfc644e47d [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 "include/core/SkColorSpace.h"
#include "include/core/SkColorType.h"
#include "include/gpu/graphite/PrecompileContext.h"
#include "include/gpu/graphite/precompile/Precompile.h"
#include "include/gpu/graphite/precompile/PrecompileColorFilter.h"
#include "src/gpu/graphite/Caps.h"
#include "src/gpu/graphite/ContextPriv.h"
#include "src/gpu/graphite/ContextUtils.h"
#include "src/gpu/graphite/GraphicsPipeline.h"
#include "src/gpu/graphite/GraphicsPipelineDesc.h"
#include "src/gpu/graphite/KeyContext.h"
#include "src/gpu/graphite/Log.h"
#include "src/gpu/graphite/PipelineData.h"
#include "src/gpu/graphite/PrecompileContextPriv.h"
#include "src/gpu/graphite/PrecompileInternal.h"
#include "src/gpu/graphite/RenderPassDesc.h"
#include "src/gpu/graphite/Renderer.h"
#include "src/gpu/graphite/RendererProvider.h"
#include "src/gpu/graphite/ResourceProvider.h"
#include "src/gpu/graphite/RuntimeEffectDictionary.h"
#include "src/gpu/graphite/UniquePaintParamsID.h"
#include "src/gpu/graphite/precompile/PaintOptionsPriv.h"
#include "src/gpu/graphite/precompile/PrecompileColorFiltersPriv.h"
namespace {
using namespace skgpu::graphite;
void compile(const RendererProvider* rendererProvider,
ResourceProvider* resourceProvider,
const KeyContext& keyContext,
UniquePaintParamsID uniqueID,
DrawTypeFlags drawTypes,
const RenderPassDesc& renderPassDesc,
bool withPrimitiveBlender,
Coverage coverage) {
const skgpu::graphite::Caps* caps = resourceProvider->caps();
for (const Renderer* r : rendererProvider->renderers()) {
if (!(r->drawTypes() & drawTypes)) {
continue;
}
if (r->emitsPrimitiveColor() != withPrimitiveBlender) {
// UniqueIDs are explicitly built either w/ or w/o primitiveBlending so must
// match what the Renderer requires
continue;
}
if (r->coverage() != coverage) {
// For now, UniqueIDs are explicitly built with a specific type of coverage so must
// match what the Renderer requires
continue;
}
for (auto&& s : r->steps()) {
SkASSERT(!s->performsShading() || s->emitsPrimitiveColor() == withPrimitiveBlender);
UniquePaintParamsID paintID = s->performsShading() ? uniqueID
: UniquePaintParamsID::Invalid();
GraphicsPipelineDesc pipelineDesc { s->renderStepID(), paintID };
skgpu::UniqueKey pipelineKey = caps->makeGraphicsPipelineKey(pipelineDesc,
renderPassDesc);
sk_sp<GraphicsPipeline> pipeline = resourceProvider->findOrCreateGraphicsPipeline(
keyContext.rtEffectDict().get(),
pipelineKey,
pipelineDesc,
renderPassDesc,
PipelineCreationFlags::kForPrecompilation);
if (!pipeline) {
SKGPU_LOG_W("Failed to create GraphicsPipeline in precompile!");
return;
}
}
}
}
} // anonymous namespace
namespace skgpu::graphite {
void Precompile(PrecompileContext* precompileContext,
const PaintOptions& options,
DrawTypeFlags drawTypes,
SkSpan<const RenderPassProperties> renderPassProperties) {
ShaderCodeDictionary* dict = precompileContext->priv().shaderCodeDictionary();
const RendererProvider* rendererProvider = precompileContext->priv().rendererProvider();
ResourceProvider* resourceProvider = precompileContext->priv().resourceProvider();
const Caps* caps = precompileContext->priv().caps();
sk_sp<RuntimeEffectDictionary> rtEffectDict = sk_make_sp<RuntimeEffectDictionary>();
for (const RenderPassProperties& rpp : renderPassProperties) {
// TODO: Allow the client to pass in mipmapping and protection too?
TextureInfo info = caps->getDefaultSampledTextureInfo(rpp.fDstCT,
Mipmapped::kNo,
Protected::kNo,
Renderable::kYes);
Swizzle writeSwizzle = caps->getWriteSwizzle(rpp.fDstCT, info);
// TODO(robertphillips): address mismatches between the MSAA requirements of the Renderers
// associated w/ the requested drawTypes and the specified MSAA setting
// On Native Metal, the LoadOp, StoreOp and clearColor fields don't influence
// the actual RenderPassDescKey.
// For Dawn, the LoadOp will sometimes matter. We add an extra LoadOp::kLoad combination
// when necessary.
const LoadOp kLoadOps[2] = { LoadOp::kClear, LoadOp::kLoad };
int numLoadOps = 1;
if (rpp.fRequiresMSAA &&
!caps->msaaRenderToSingleSampledSupport() &&
caps->loadOpAffectsMSAAPipelines()) {
numLoadOps = 2;
}
for (int loadOpIndex = 0; loadOpIndex < numLoadOps; ++loadOpIndex) {
const RenderPassDesc renderPassDesc =
RenderPassDesc::Make(caps,
info,
kLoadOps[loadOpIndex],
StoreOp::kStore,
rpp.fDSFlags,
/* clearColor= */ { .0f, .0f, .0f, .0f },
rpp.fRequiresMSAA,
writeSwizzle,
caps->getDstReadStrategy());
SkColorInfo ci(rpp.fDstCT, kPremul_SkAlphaType, rpp.fDstCS);
// The PipelineDataGatherer and FloatStorageManager are only used to accumulate uniform
// data. In the pre-compile case we don't need to record the uniform data but the
// process of generating it is required to create the correct key.
FloatStorageManager floatStorageManager;
PipelineDataGatherer gatherer(Layout::kMetal);
PaintParamsKeyBuilder builder(dict);
KeyContext keyContext(caps, &floatStorageManager, &builder, &gatherer, dict,
rtEffectDict, ci);
for (Coverage coverage : { Coverage::kNone, Coverage::kSingleChannel }) {
PrecompileCombinations(
rendererProvider,
resourceProvider,
options, keyContext,
static_cast<DrawTypeFlags>(drawTypes & ~(DrawTypeFlags::kBitmapText_Color |
DrawTypeFlags::kBitmapText_LCD |
DrawTypeFlags::kSDFText_LCD |
DrawTypeFlags::kDrawVertices |
DrawTypeFlags::kDropShadows)),
/* withPrimitiveBlender= */ false,
coverage,
renderPassDesc);
}
if (drawTypes & DrawTypeFlags::kNonSimpleShape) {
// Special case handling to pick up the:
// "CoverBoundsRenderStep[InverseCover] + (empty)"
// pipelines.
const RenderStep* renderStep =
rendererProvider->lookup(RenderStep::RenderStepID::kCoverBounds_InverseCover);
GraphicsPipelineDesc pipelineDesc { renderStep->renderStepID(),
UniquePaintParamsID::Invalid() };
skgpu::UniqueKey pipelineKey = caps->makeGraphicsPipelineKey(pipelineDesc,
renderPassDesc);
sk_sp<GraphicsPipeline> pipeline = resourceProvider->findOrCreateGraphicsPipeline(
keyContext.rtEffectDict().get(),
pipelineKey,
pipelineDesc,
renderPassDesc,
PipelineCreationFlags::kForPrecompilation);
if (!pipeline) {
SKGPU_LOG_W("Failed to create \"CoverBoundsRenderStep[InverseCover] + (empty)\""
" precompile Pipeline!");
}
}
if (drawTypes & DrawTypeFlags::kBitmapText_Color) {
DrawTypeFlags reducedTypes =
static_cast<DrawTypeFlags>(drawTypes & (DrawTypeFlags::kBitmapText_Color |
DrawTypeFlags::kAnalyticClip));
// For color emoji text, shaders don't affect the final color
PaintOptions tmp = options;
tmp.setShaders({});
// ARGB text doesn't emit coverage and always has a primitive blender
PrecompileCombinations(rendererProvider,
resourceProvider,
tmp,
keyContext,
reducedTypes,
/* withPrimitiveBlender= */ true,
Coverage::kNone,
renderPassDesc);
}
if (drawTypes & (DrawTypeFlags::kBitmapText_LCD | DrawTypeFlags::kSDFText_LCD)) {
DrawTypeFlags reducedTypes =
static_cast<DrawTypeFlags>(drawTypes & (DrawTypeFlags::kBitmapText_LCD |
DrawTypeFlags::kSDFText_LCD |
DrawTypeFlags::kAnalyticClip));
// LCD-based text always emits LCD coverage but never has primitiveBlenders
PrecompileCombinations(
rendererProvider,
resourceProvider,
options, keyContext,
reducedTypes,
/* withPrimitiveBlender= */ false,
Coverage::kLCD,
renderPassDesc);
}
if (drawTypes & DrawTypeFlags::kDrawVertices) {
DrawTypeFlags reducedTypes =
static_cast<DrawTypeFlags>(drawTypes & (DrawTypeFlags::kDrawVertices |
DrawTypeFlags::kAnalyticClip));
// drawVertices w/ colors use a primitiveBlender while those w/o don't. It never
// emits coverage.
for (bool withPrimitiveBlender : { true, false }) {
PrecompileCombinations(rendererProvider,
resourceProvider,
options, keyContext,
reducedTypes,
withPrimitiveBlender,
Coverage::kNone,
renderPassDesc);
}
}
if (drawTypes & DrawTypeFlags::kDropShadows) {
DrawTypeFlags reducedTypes =
static_cast<DrawTypeFlags>(drawTypes & (DrawTypeFlags::kDropShadows |
DrawTypeFlags::kAnalyticClip));
PaintOptions newOptions;
newOptions.setBlendModes({ SkBlendMode::kSrcOver });
// Analytic
{
PrecompileCombinations(rendererProvider,
resourceProvider,
newOptions, keyContext,
reducedTypes,
/* withPrimitiveBlender= */ false,
Coverage::kSingleChannel,
renderPassDesc);
}
// Geometric
{
sk_sp<PrecompileColorFilter> cf = PrecompileColorFilters::Compose(
{ PrecompileColorFilters::Blend({ SkBlendMode::kModulate }) },
{ PrecompileColorFiltersPriv::Gaussian() });
newOptions.setColorFilters({ std::move(cf) });
newOptions.priv().setPrimitiveBlendMode(SkBlendMode::kDst);
newOptions.priv().setSkipColorXform(true);
PrecompileCombinations(rendererProvider,
resourceProvider,
newOptions, keyContext,
reducedTypes,
/* withPrimitiveBlender= */ true,
Coverage::kNone,
renderPassDesc);
}
}
}
}
}
void PrecompileCombinations(const RendererProvider* rendererProvider,
ResourceProvider* resourceProvider,
const PaintOptions& options,
const KeyContext& keyContext,
DrawTypeFlags drawTypes,
bool withPrimitiveBlender,
Coverage coverage,
const RenderPassDesc& renderPassDescIn) {
if (drawTypes == DrawTypeFlags::kNone) {
return;
}
options.priv().buildCombinations(
keyContext,
drawTypes,
withPrimitiveBlender,
coverage,
renderPassDescIn,
[rendererProvider, resourceProvider, &keyContext](UniquePaintParamsID uniqueID,
DrawTypeFlags drawTypes,
bool withPrimitiveBlender,
Coverage coverage,
const RenderPassDesc& renderPassDesc) {
compile(rendererProvider,
resourceProvider,
keyContext,
uniqueID,
drawTypes,
renderPassDesc,
withPrimitiveBlender,
coverage);
});
}
} // namespace skgpu::graphite