blob: c4c08509db5e28045e2fdcbdb8b0641bb2c5dbbb [file] [log] [blame]
/*
* Copyright 2019 Google LLC
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "src/core/SkRuntimeBlender.h"
#include "include/core/SkCapabilities.h"
#include "include/core/SkData.h"
#include "include/core/SkMatrix.h"
#include "include/core/SkString.h"
#include "include/effects/SkRuntimeEffect.h"
#include "include/private/SkSLSampleUsage.h"
#include "include/private/base/SkTArray.h"
#include "src/core/SkEffectPriv.h"
#include "src/core/SkReadBuffer.h"
#include "src/core/SkRuntimeEffectPriv.h"
#include "src/core/SkWriteBuffer.h"
#include "src/shaders/SkShaderBase.h"
#include "src/sksl/codegen/SkSLRasterPipelineBuilder.h"
#if defined(SK_GRAPHITE)
#include "src/gpu/graphite/KeyContext.h"
#include "src/gpu/graphite/KeyHelpers.h"
#include "src/gpu/graphite/PaintParamsKey.h"
#endif
#include <string>
using namespace skia_private;
#if defined(SK_BUILD_FOR_DEBUGGER)
#define SK_LENIENT_SKSL_DESERIALIZATION 1
#else
#define SK_LENIENT_SKSL_DESERIALIZATION 0
#endif
sk_sp<SkFlattenable> SkRuntimeBlender::CreateProc(SkReadBuffer& buffer) {
if (!buffer.validate(buffer.allowSkSL())) {
return nullptr;
}
SkString sksl;
buffer.readString(&sksl);
sk_sp<SkData> uniforms = buffer.readByteArrayAsData();
auto effect = SkMakeCachedRuntimeEffect(SkRuntimeEffect::MakeForBlender, std::move(sksl));
#if !SK_LENIENT_SKSL_DESERIALIZATION
if (!buffer.validate(effect != nullptr)) {
return nullptr;
}
#endif
STArray<4, SkRuntimeEffect::ChildPtr> children;
if (!SkRuntimeEffectPriv::ReadChildEffects(buffer, effect.get(), &children)) {
return nullptr;
}
#if SK_LENIENT_SKSL_DESERIALIZATION
if (!effect) {
SkDebugf("Serialized SkSL failed to compile. Ignoring/dropping SkSL blender.\n");
return nullptr;
}
#endif
return effect->makeBlender(std::move(uniforms), SkSpan(children));
}
bool SkRuntimeBlender::onAppendStages(const SkStageRec& rec) const {
#ifdef SK_ENABLE_SKSL_IN_RASTER_PIPELINE
if (!SkRuntimeEffectPriv::CanDraw(SkCapabilities::RasterBackend().get(), fEffect.get())) {
// SkRP has support for many parts of #version 300 already, but for now, we restrict its
// usage in runtime effects to just #version 100.
return false;
}
if (const SkSL::RP::Program* program = fEffect->getRPProgram(/*debugTrace=*/nullptr)) {
SkSpan<const float> uniforms = SkRuntimeEffectPriv::UniformsAsSpan(
fEffect->uniforms(),
fUniforms,
/*alwaysCopyIntoAlloc=*/false,
rec.fDstCS,
rec.fAlloc);
SkShaders::MatrixRec matrix(SkMatrix::I());
matrix.markCTMApplied();
RuntimeEffectRPCallbacks callbacks(rec, matrix, fChildren, fEffect->fSampleUsages);
bool success = program->appendStages(rec.fPipeline, rec.fAlloc, &callbacks, uniforms);
return success;
}
#endif
return false;
}
void SkRuntimeBlender::flatten(SkWriteBuffer& buffer) const {
buffer.writeString(fEffect->source().c_str());
buffer.writeDataAsByteArray(fUniforms.get());
SkRuntimeEffectPriv::WriteChildEffects(buffer, fChildren);
}
#ifdef SK_ENABLE_SKVM
skvm::Color SkRuntimeBlender::onProgram(skvm::Builder* p, skvm::Color src, skvm::Color dst,
const SkColorInfo& colorInfo, skvm::Uniforms* uniforms,
SkArenaAlloc* alloc) const {
if (!SkRuntimeEffectPriv::CanDraw(SkCapabilities::RasterBackend().get(), fEffect.get())) {
return {};
}
sk_sp<const SkData> inputs = SkRuntimeEffectPriv::TransformUniforms(fEffect->uniforms(),
fUniforms,
colorInfo.colorSpace());
SkASSERT(inputs);
SkShaders::MatrixRec mRec(SkMatrix::I());
mRec.markTotalMatrixInvalid();
RuntimeEffectVMCallbacks callbacks(p, uniforms, alloc, fChildren, mRec, src, colorInfo);
std::vector<skvm::Val> uniform = SkRuntimeEffectPriv::MakeSkVMUniforms(p,
uniforms,
fEffect->uniformSize(),
*inputs);
// Emit the blend function as an SkVM program.
skvm::Coord zeroCoord = {p->splat(0.0f), p->splat(0.0f)};
return SkSL::ProgramToSkVM(*fEffect->fBaseProgram, fEffect->fMain, p,/*debugTrace=*/nullptr,
SkSpan(uniform), /*device=*/zeroCoord, /*local=*/zeroCoord,
src, dst, &callbacks);
}
#endif
#if defined(SK_GRAPHITE)
void SkRuntimeBlender::addToKey(const skgpu::graphite::KeyContext& keyContext,
skgpu::graphite::PaintParamsKeyBuilder* builder,
skgpu::graphite::PipelineDataGatherer* gatherer) const {
using namespace skgpu::graphite;
sk_sp<const SkData> uniforms = SkRuntimeEffectPriv::TransformUniforms(
fEffect->uniforms(),
fUniforms,
keyContext.dstColorInfo().colorSpace());
SkASSERT(uniforms);
RuntimeEffectBlock::BeginBlock(keyContext, builder, gatherer,
{ fEffect, std::move(uniforms) });
SkRuntimeEffectPriv::AddChildrenToKey(fChildren, fEffect->children(), keyContext, builder,
gatherer);
builder->endBlock();
}
#endif