blob: 77fe65f8bc7e7f7bcbb2404576e6cc19f08b20b7 [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/SkCanvas.h"
#include "include/core/SkColorSpace.h"
#include "src/core/SkSpecialImage.h"
#include "src/core/SkSpecialSurface.h"
#include "src/gpu/graphite/Image_Graphite.h"
#include "src/gpu/graphite/Surface_Graphite.h"
#include "src/shaders/SkImageShader.h"
namespace skgpu::graphite {
class SkSpecialImage_Graphite final : public SkSpecialImage {
SkSpecialImage_Graphite(Recorder* recorder,
const SkIRect& subset,
uint32_t uniqueID,
TextureProxyView view,
const SkColorInfo& colorInfo,
const SkSurfaceProps& props)
: SkSpecialImage(subset, uniqueID, colorInfo, props)
, fRecorder(recorder)
, fTextureProxyView(std::move(view)) {
size_t getSize() const override {
// TODO: return VRAM size here
return 0;
void onDraw(SkCanvas* canvas,
SkScalar x, SkScalar y,
const SkSamplingOptions& sampling,
const SkPaint* paint) const override {
SkRect dst = SkRect::MakeXYWH(x, y,
this->subset().width(), this->subset().height());
sk_sp<SkImage> img = sk_sp<SkImage>(new skgpu::graphite::Image(this->uniqueID(),
canvas->drawImageRect(img, SkRect::Make(this->subset()), dst,
sampling, paint, SkCanvas::kStrict_SrcRectConstraint);
#if defined(SK_GANESH)
GrSurfaceProxyView onView(GrRecordingContext*) const override {
// To get here we would have to be requesting a Ganesh resource from a Graphite-backed
// special image. That should never happen.
return {};
TextureProxyView onTextureProxyView() const override { return fTextureProxyView; }
bool onGetROPixels(SkBitmap* dst) const override {
// This should never be called: All GPU image filters are implemented entirely on the GPU,
// so we never perform read-back.
// TODO: re-enabled this assert once Graphite has image filter support. Right now image
// filters will fallback to the raster backend in Graphite.
return false;
sk_sp<SkSpecialSurface> onMakeSurface(SkColorType colorType,
const SkColorSpace* colorSpace,
const SkISize& size,
SkAlphaType at,
const SkSurfaceProps& props) const override {
SkImageInfo ii = SkImageInfo::Make(size, colorType, at, sk_ref_sp(colorSpace));
return SkSpecialSurface::MakeGraphite(fRecorder, ii, props);
sk_sp<SkSpecialImage> onMakeSubset(const SkIRect& subset) const override {
return SkSpecialImage::MakeGraphite(fRecorder,
sk_sp<SkImage> onAsImage(const SkIRect* subset) const override {
if (subset) {
// TODO: fill this in
return nullptr;
return sk_make_sp<Image>(this->uniqueID(), fTextureProxyView, this->colorInfo());
sk_sp<SkShader> onAsShader(SkTileMode tileMode,
const SkSamplingOptions& sampling,
const SkMatrix& lm) const override {
// The special image's logical (0,0) is at its subset's topLeft() so we need to account for
// that in the local matrix used when sampling.
SkMatrix subsetOrigin = SkMatrix::Translate(-this->subset().topLeft());
// However, we don't need to modify the subset itself since that is defined with respect to
// the base image, and the local matrix is applied before any tiling/clamping.
const SkRect subset = SkRect::Make(this->subset());
// asImage() w/o a subset makes no copy; create the SkImageShader directly to remember the
// subset used to access the image.
return SkImageShader::MakeSubset(this->asImage(), subset, tileMode, tileMode,
sampling, &subsetOrigin);
sk_sp<SkSurface> onMakeTightSurface(SkColorType colorType,
const SkColorSpace* colorSpace,
const SkISize& size,
SkAlphaType at) const override {
// TODO (michaelludwig): Why does this ignore colorType but onMakeSurface doesn't ignore it?
// Once makeTightSurface() goes away, should this type overriding behavior be moved into
// onMakeSurface() or is this unnecessary?
colorType = colorSpace && colorSpace->gammaIsLinear() ? kRGBA_F16_SkColorType
: kRGBA_8888_SkColorType;
SkImageInfo info = SkImageInfo::Make(size, colorType, at, sk_ref_sp(colorSpace));
// The user never gets a direct ref to this surface (nor its snapped image) so it must be
// budgeted
return Surface::MakeGraphite(fRecorder, info, skgpu::Budgeted::kYes);
Recorder* fRecorder;
TextureProxyView fTextureProxyView;
} // namespace skgpu::graphite
sk_sp<SkSpecialImage> SkSpecialImage::MakeGraphite(skgpu::graphite::Recorder* recorder,
const SkIRect& subset,
uint32_t uniqueID,
skgpu::graphite::TextureProxyView view,
const SkColorInfo& colorInfo,
const SkSurfaceProps& props) {
if (!recorder || !view) {
return nullptr;
SkASSERT(RectFits(subset, view.width(), view.height()));
return sk_make_sp<skgpu::graphite::SkSpecialImage_Graphite>(recorder, subset, uniqueID,
std::move(view), colorInfo, props);