blob: 2472faa440734a90a820eaf98ad2895a4f4d1a98 [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/PublicPrecompile.h"
#include "include/core/SkColorSpace.h"
#include "include/core/SkColorType.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/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"
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) {
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::InvalidID();
GraphicsPipelineDesc pipelineDesc(s, paintID);
sk_sp<GraphicsPipeline> pipeline = resourceProvider->findOrCreateGraphicsPipeline(
keyContext.rtEffectDict(),
pipelineDesc,
renderPassDesc);
if (!pipeline) {
SKGPU_LOG_W("Failed to create GraphicsPipeline in precompile!");
return;
}
}
}
}
} // anonymous namespace
namespace skgpu::graphite {
bool Precompile(Context* context,
RuntimeEffectDictionary* rteDict,
const GraphicsPipelineDesc& pipelineDesc,
const RenderPassDesc& renderPassDesc) {
ResourceProvider* resourceProvider = context->priv().resourceProvider();
sk_sp<GraphicsPipeline> pipeline = resourceProvider->findOrCreateGraphicsPipeline(
rteDict,
pipelineDesc,
renderPassDesc);
if (!pipeline) {
SKGPU_LOG_W("Failed to create GraphicsPipeline in precompile!");
return false;
}
return true;
}
void Precompile(Context* context, const PaintOptions& options, DrawTypeFlags drawTypes,
SkSpan<const RenderPassProperties> renderPassProperties) {
ShaderCodeDictionary* dict = context->priv().shaderCodeDictionary();
const Caps* caps = context->priv().caps();
auto rtEffectDict = std::make_unique<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);
SkColorInfo ci(rpp.fDstCT, kPremul_SkAlphaType, nullptr);
KeyContext keyContext(caps, dict, rtEffectDict.get(), ci,
/* dstTexture= */ nullptr,
/* dstOffset= */ {0, 0});
for (Coverage coverage : { Coverage::kNone, Coverage::kSingleChannel }) {
PrecompileCombinations(
context, options, keyContext,
static_cast<DrawTypeFlags>(drawTypes & ~(DrawTypeFlags::kBitmapText_Color |
DrawTypeFlags::kBitmapText_LCD |
DrawTypeFlags::kSDFText_LCD |
DrawTypeFlags::kDrawVertices)),
/* withPrimitiveBlender= */ false,
coverage,
renderPassDesc);
}
if (drawTypes & DrawTypeFlags::kBitmapText_Color) {
// 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(context, tmp, keyContext,
DrawTypeFlags::kBitmapText_Color,
/* withPrimitiveBlender= */ true,
Coverage::kNone,
renderPassDesc);
}
if (drawTypes & (DrawTypeFlags::kBitmapText_LCD | DrawTypeFlags::kSDFText_LCD)) {
// LCD-based text always emits LCD coverage but never has primitiveBlenders
PrecompileCombinations(
context, options, keyContext,
static_cast<DrawTypeFlags>(drawTypes & (DrawTypeFlags::kBitmapText_LCD |
DrawTypeFlags::kSDFText_LCD)),
/* withPrimitiveBlender= */ false,
Coverage::kLCD,
renderPassDesc);
}
if (drawTypes & DrawTypeFlags::kDrawVertices) {
// drawVertices w/ colors use a primitiveBlender while those w/o don't. It never
// emits coverage.
for (bool withPrimitiveBlender : { true, false }) {
PrecompileCombinations(context, options, keyContext,
DrawTypeFlags::kDrawVertices,
withPrimitiveBlender,
Coverage::kNone,
renderPassDesc);
}
}
}
}
}
void PrecompileCombinations(Context* context,
const PaintOptions& options,
const KeyContext& keyContext,
DrawTypeFlags drawTypes,
bool withPrimitiveBlender,
Coverage coverage,
const RenderPassDesc& renderPassDescIn) {
if (drawTypes == DrawTypeFlags::kNone) {
return;
}
// Since the precompilation path's uniforms aren't used and don't change the key,
// the exact layout doesn't matter
PipelineDataGatherer gatherer(Layout::kMetal);
options.priv().buildCombinations(
keyContext,
&gatherer,
drawTypes,
withPrimitiveBlender,
coverage,
renderPassDescIn,
[context, &keyContext](UniquePaintParamsID uniqueID,
DrawTypeFlags drawTypes,
bool withPrimitiveBlender,
Coverage coverage,
const RenderPassDesc& renderPassDesc) {
compile(context->priv().rendererProvider(),
context->priv().resourceProvider(),
keyContext,
uniqueID,
drawTypes,
renderPassDesc,
withPrimitiveBlender,
coverage);
});
}
} // namespace skgpu::graphite