[graphite] Add support for creating wrapped SkSurfaces.

Bug: skia:12633
Change-Id: Ic1598bea37bae6f53e054de98093b3c049125b38
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/479063
Reviewed-by: Robert Phillips <robertphillips@google.com>
Commit-Queue: Greg Daniel <egdaniel@google.com>
This commit is contained in:
Greg Daniel 2021-12-15 14:43:17 -05:00 committed by SkCQ
parent eff367ac83
commit fec9a3027c
11 changed files with 198 additions and 11 deletions

View File

@ -8,16 +8,39 @@
#ifndef SkStuff_DEFINED
#define SkStuff_DEFINED
#include "include/core/SkImageInfo.h"
#include "include/core/SkRefCnt.h"
struct SkImageInfo;
class SkSurface;
class SkSurfaceProps;
namespace skgpu {
class BackendTexture;
class Recorder;
}
// TODO: Should be in SkSurface.h
sk_sp<SkSurface> MakeGraphite(sk_sp<skgpu::Recorder>, const SkImageInfo&);
/**
* Wraps a GPU-backed texture into SkSurface. Depending on the backend gpu API, the caller may be
* required to ensure the texture is valid for the lifetime of returned SkSurface. The required
* lifetimes for the specific apis are:
* Metal: Skia will call retain on the underlying MTLTexture so the caller can drop it once this
* call returns.
*
* SkSurface is returned if all parameters are valid. BackendTexture is valid if its format agrees
* with colorSpace and context; for instance, if backendTexture has an sRGB configuration, then
* context must support sRGB, and colorSpace must be present. Further, backendTexture width and
* height must not exceed context capabilities, and the context must be able to support back-end
* textures.
*
* If SK_ENABLE_GRAPHITE is not defined, this has no effect and returns nullptr.
*/
sk_sp<SkSurface> MakeGraphiteFromBackendTexture(sk_sp<skgpu::Recorder>,
const skgpu::BackendTexture&,
SkColorType colorType,
sk_sp<SkColorSpace> colorSpace,
const SkSurfaceProps* props);
#endif // SkStuff_DEFINED

View File

@ -6,6 +6,8 @@
*/
#include "experimental/graphite/src/Caps.h"
#include "experimental/graphite/include/TextureInfo.h"
#include "src/sksl/SkSLUtil.h"
namespace skgpu {
@ -13,6 +15,13 @@ namespace skgpu {
Caps::Caps() {}
Caps::~Caps() {}
bool Caps::isTexturable(const TextureInfo& info) const {
if (info.numSamples() > 1) {
return false;
}
return this->onIsTexturable(info);
}
bool Caps::areColorTypeAndTextureInfoCompatible(SkColorType type, const TextureInfo& info) const {
if (type == kUnknown_SkColorType) {
return false;

View File

@ -41,7 +41,7 @@ public:
bool areColorTypeAndTextureInfoCompatible(SkColorType, const TextureInfo&) const;
virtual bool isTexturable(const TextureInfo&) const = 0;
bool isTexturable(const TextureInfo&) const;
virtual bool isRenderable(const TextureInfo&) const = 0;
int maxTextureSize() const { return fMaxTextureSize; }
@ -59,6 +59,7 @@ protected:
std::unique_ptr<SkSL::ShaderCaps> fShaderCaps;
private:
virtual bool onIsTexturable(const TextureInfo&) const = 0;
virtual bool onAreColorTypeAndTextureInfoCompatible(SkColorType, const TextureInfo&) const = 0;
};

View File

@ -48,14 +48,33 @@ bool is_opaque(const PaintParams& paint) {
} // anonymous namespace
sk_sp<Device> Device::Make(sk_sp<Recorder> recorder, const SkImageInfo& ii) {
if (!recorder) {
return nullptr;
}
const Gpu* gpu = recorder->context()->priv().gpu();
auto textureInfo = gpu->caps()->getDefaultSampledTextureInfo(ii.colorType(), /*levelCount=*/1,
Protected::kNo, Renderable::kYes);
auto target = sk_sp<TextureProxy>(new TextureProxy(ii.dimensions(), textureInfo));
sk_sp<DrawContext> dc = DrawContext::Make(target,
ii.refColorSpace(),
ii.colorType(),
ii.alphaType());
sk_sp<TextureProxy> target(new TextureProxy(ii.dimensions(), textureInfo));
return Make(std::move(recorder),
std::move(target),
ii.refColorSpace(),
ii.colorType(),
ii.alphaType());
}
sk_sp<Device> Device::Make(sk_sp<Recorder> recorder,
sk_sp<TextureProxy> target,
sk_sp<SkColorSpace> colorSpace,
SkColorType colorType,
SkAlphaType alphaType) {
if (!recorder) {
return nullptr;
}
sk_sp<DrawContext> dc = DrawContext::Make(std::move(target),
std::move(colorSpace),
colorType,
alphaType);
if (!dc) {
return nullptr;
}

View File

@ -24,6 +24,7 @@ class Context;
class DrawContext;
class Recorder;
class Shape;
class TextureProxy;
class Transform;
class Device final : public SkBaseDevice {
@ -31,10 +32,15 @@ public:
~Device() override;
static sk_sp<Device> Make(sk_sp<Recorder>, const SkImageInfo&);
static sk_sp<Device> Make(sk_sp<Recorder>,
sk_sp<TextureProxy>,
sk_sp<SkColorSpace>,
SkColorType,
SkAlphaType);
sk_sp<Recorder> refRecorder() { return fRecorder; }
protected:
private:
// Clipping
void onSave() override {}
void onRestore() override {}
@ -112,7 +118,6 @@ protected:
sk_sp<SkSpecialImage> makeSpecial(const SkImage*) override;
sk_sp<SkSpecialImage> snapSpecial(const SkIRect& subset, bool forceCopy = false) override;
private:
// DrawFlags alters the effects used by drawShape.
enum class DrawFlags : unsigned {
kNone = 0b00,

View File

@ -7,9 +7,17 @@
#include "experimental/graphite/include/SkStuff.h"
#include "experimental/graphite/include/BackendTexture.h"
#include "experimental/graphite/include/Context.h"
#include "experimental/graphite/include/Recorder.h"
#include "experimental/graphite/src/Caps.h"
#include "experimental/graphite/src/ContextPriv.h"
#include "experimental/graphite/src/Device.h"
#include "experimental/graphite/src/Gpu.h"
#include "experimental/graphite/src/ResourceProvider.h"
#include "experimental/graphite/src/Surface_Graphite.h"
#include "experimental/graphite/src/Texture.h"
#include "experimental/graphite/src/TextureProxy.h"
sk_sp<SkSurface> MakeGraphite(sk_sp<skgpu::Recorder> recorder, const SkImageInfo& ii) {
sk_sp<skgpu::Device> device = skgpu::Device::Make(std::move(recorder), ii);
@ -19,3 +27,58 @@ sk_sp<SkSurface> MakeGraphite(sk_sp<skgpu::Recorder> recorder, const SkImageInfo
return sk_make_sp<skgpu::Surface_Graphite>(std::move(device));
}
static bool validate_backend_texture(const skgpu::Caps* caps,
const skgpu::BackendTexture& texture,
SkColorType ct) {
if (!texture.isValid()) {
return false;
}
const skgpu::TextureInfo& info = texture.info();
if (!caps->areColorTypeAndTextureInfoCompatible(ct, info)) {
return false;
}
if (!caps->isRenderable(info)) {
return false;
}
return true;
}
sk_sp<SkSurface> MakeGraphiteFromBackendTexture(sk_sp<skgpu::Recorder> recorder,
const skgpu::BackendTexture& beTexture,
SkColorType colorType,
sk_sp<SkColorSpace> colorSpace,
const SkSurfaceProps* props) {
if (!recorder) {
return nullptr;
}
if (!validate_backend_texture(recorder->context()->priv().gpu()->caps(),
beTexture,
colorType)) {
return nullptr;
}
sk_sp<skgpu::Texture> texture =
recorder->context()->priv().resourceProvider()->createWrappedTexture(beTexture);
if (!texture) {
return nullptr;
}
sk_sp<skgpu::TextureProxy> proxy(new skgpu::TextureProxy(std::move(texture)));
sk_sp<skgpu::Device> device = skgpu::Device::Make(std::move(recorder),
std::move(proxy),
std::move(colorSpace),
colorType,
kPremul_SkAlphaType);
if (!device) {
return nullptr;
}
return sk_make_sp<skgpu::Surface_Graphite>(std::move(device));
}

View File

@ -15,6 +15,11 @@ namespace skgpu {
TextureProxy::TextureProxy(SkISize dimensions, const TextureInfo& info)
: fDimensions(dimensions), fInfo(info) {}
TextureProxy::TextureProxy(sk_sp<Texture> texture)
: fDimensions(texture->dimensions())
, fInfo(texture->textureInfo())
, fTexture(std::move(texture)) {}
TextureProxy::~TextureProxy() {}
bool TextureProxy::instantiate(ResourceProvider* resourceProvider) {

View File

@ -20,6 +20,7 @@ class Texture;
class TextureProxy : public SkRefCnt {
public:
TextureProxy(SkISize dimensions, const TextureInfo& info);
TextureProxy(sk_sp<Texture>);
~TextureProxy() override;

View File

@ -37,7 +37,6 @@ public:
size_t getMinBufferAlignment() const { return this->isMac() ? 4 : 1; }
bool isTexturable(const skgpu::TextureInfo&) const override;
bool isRenderable(const skgpu::TextureInfo&) const override;
private:
@ -57,6 +56,8 @@ private:
bool onAreColorTypeAndTextureInfoCompatible(SkColorType,
const skgpu::TextureInfo&) const override;
bool onIsTexturable(const skgpu::TextureInfo&) const override;
bool isTexturable(MTLPixelFormat) const;
bool isRenderable(MTLPixelFormat, uint32_t numSamples) const;

View File

@ -311,7 +311,7 @@ skgpu::TextureInfo Caps::getDefaultDepthStencilTextureInfo(Mask<DepthStencilFlag
return info;
}
bool Caps::isTexturable(const skgpu::TextureInfo& info) const {
bool Caps::onIsTexturable(const skgpu::TextureInfo& info) const {
return info.mtlTextureSpec().fUsage & MTLTextureUsageShaderRead &&
this->isTexturable((MTLPixelFormat)info.mtlTextureSpec().fFormat);
}

View File

@ -9,11 +9,15 @@
#include "experimental/graphite/include/BackendTexture.h"
#include "experimental/graphite/include/Context.h"
#include "experimental/graphite/include/Recorder.h"
#include "experimental/graphite/include/SkStuff.h"
#include "experimental/graphite/src/Caps.h"
#include "experimental/graphite/src/ContextPriv.h"
#include "experimental/graphite/src/Gpu.h"
#include "experimental/graphite/src/ResourceTypes.h"
#include "include/core/SkSurface.h"
using namespace skgpu;
namespace {
@ -61,3 +65,59 @@ DEF_GRAPHITE_TEST_FOR_CONTEXTS(BackendTextureTest, reporter, context) {
context->deleteBackendTexture(texture1);
context->deleteBackendTexture(texture2);
}
// Tests the wrapping of a BackendTexture in an SkSurface
DEF_GRAPHITE_TEST_FOR_CONTEXTS(SurfaceBackendTextureTest, reporter, context) {
// TODO: Right now this just tests very basic combinations of surfaces. This should be expanded
// to conver a much broader set of things once we add more support in Graphite for different
// formats, color types, etc.
auto caps = context->priv().gpu()->caps();
sk_sp<Recorder> recorder = context->createRecorder();
TextureInfo info = caps->getDefaultSampledTextureInfo(kRGBA_8888_SkColorType,
/*levelCount=*/1,
Protected::kNo,
Renderable::kYes);
auto texture = context->createBackendTexture(kSize, info);
REPORTER_ASSERT(reporter, texture.isValid());
sk_sp<SkSurface> surface = MakeGraphiteFromBackendTexture(recorder,
texture,
kRGBA_8888_SkColorType,
/*colorSpace=*/nullptr,
/*props=*/nullptr);
REPORTER_ASSERT(reporter, surface);
surface.reset();
// We should fail when trying to wrap the same texture in a surface with a non compatible
// color type.
surface = MakeGraphiteFromBackendTexture(recorder,
texture,
kAlpha_8_SkColorType,
/*colorSpace=*/nullptr,
/*props=*/nullptr);
REPORTER_ASSERT(reporter, !surface);
context->deleteBackendTexture(texture);
// We should fail to make a wrap non renderable texture in a surface.
info = caps->getDefaultSampledTextureInfo(kRGBA_8888_SkColorType,
/*levelCount=*/1,
Protected::kNo,
Renderable::kNo);
texture = context->createBackendTexture(kSize, info);
REPORTER_ASSERT(reporter, texture.isValid());
surface = MakeGraphiteFromBackendTexture(recorder,
texture,
kRGBA_8888_SkColorType,
/*colorSpace=*/nullptr,
/*props=*/nullptr);
REPORTER_ASSERT(reporter, !surface);
context->deleteBackendTexture(texture);
}