[graphite] Add format tables to MtlCaps
Bug: skia:12845 Change-Id: If3ac2b6ba2c8e28328ee5805a29fc83353220364 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/524756 Reviewed-by: Greg Daniel <egdaniel@google.com> Commit-Queue: Jim Van Verth <jvanverth@google.com>
This commit is contained in:
parent
a06240b2dc
commit
f151351f47
@ -12,6 +12,7 @@
|
||||
#include "include/core/SkImageInfo.h"
|
||||
#include "include/core/SkRefCnt.h"
|
||||
#include "src/gpu/ResourceKey.h"
|
||||
#include "src/gpu/Swizzle.h"
|
||||
|
||||
namespace SkSL {
|
||||
struct ShaderCaps;
|
||||
@ -72,6 +73,22 @@ public:
|
||||
protected:
|
||||
Caps();
|
||||
|
||||
// ColorTypeInfo for a specific format.
|
||||
// Used in format tables.
|
||||
struct ColorTypeInfo {
|
||||
SkColorType fColorType = kUnknown_SkColorType;
|
||||
enum {
|
||||
kUploadData_Flag = 0x1,
|
||||
// Does Graphite itself support rendering to this colorType & format pair. Renderability
|
||||
// still additionally depends on if the format itself is renderable.
|
||||
kRenderable_Flag = 0x2,
|
||||
};
|
||||
uint32_t fFlags = 0;
|
||||
|
||||
skgpu::Swizzle fReadSwizzle;
|
||||
skgpu::Swizzle fWriteSwizzle;
|
||||
};
|
||||
|
||||
int fMaxTextureSize = 0;
|
||||
size_t fRequiredUniformBufferAlignment = 0;
|
||||
|
||||
|
@ -8,10 +8,12 @@
|
||||
#ifndef skgpu_MtlCaps_DEFINED
|
||||
#define skgpu_MtlCaps_DEFINED
|
||||
|
||||
#include "experimental/graphite/src/Caps.h"
|
||||
#include <vector>
|
||||
|
||||
#import <Metal/Metal.h>
|
||||
|
||||
#include "experimental/graphite/src/Caps.h"
|
||||
|
||||
namespace skgpu::mtl {
|
||||
|
||||
class Caps final : public skgpu::Caps {
|
||||
@ -69,9 +71,50 @@ private:
|
||||
bool onIsTexturable(const skgpu::TextureInfo&) const override;
|
||||
bool isTexturable(MTLPixelFormat) const;
|
||||
bool isRenderable(MTLPixelFormat, uint32_t numSamples) const;
|
||||
uint32_t maxRenderTargetSampleCount(MTLPixelFormat) const;
|
||||
|
||||
size_t getTransferBufferAlignment(size_t bytesPerPixel) const override;
|
||||
|
||||
struct FormatInfo {
|
||||
uint32_t colorTypeFlags(SkColorType colorType) const {
|
||||
for (int i = 0; i < fColorTypeInfoCount; ++i) {
|
||||
if (fColorTypeInfos[i].fColorType == colorType) {
|
||||
return fColorTypeInfos[i].fFlags;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
enum {
|
||||
kTexturable_Flag = 0x1,
|
||||
kRenderable_Flag = 0x2, // Color attachment and blendable
|
||||
kMSAA_Flag = 0x4,
|
||||
kResolve_Flag = 0x8,
|
||||
};
|
||||
static const uint16_t kAllFlags = kTexturable_Flag | kRenderable_Flag |
|
||||
kMSAA_Flag | kResolve_Flag;
|
||||
|
||||
uint16_t fFlags = 0;
|
||||
|
||||
std::unique_ptr<ColorTypeInfo[]> fColorTypeInfos;
|
||||
int fColorTypeInfoCount = 0;
|
||||
};
|
||||
inline static constexpr size_t kNumMtlFormats = 8;
|
||||
|
||||
static size_t GetFormatIndex(MTLPixelFormat);
|
||||
FormatInfo fFormatTable[kNumMtlFormats];
|
||||
|
||||
const FormatInfo& getFormatInfo(const MTLPixelFormat pixelFormat) const {
|
||||
size_t index = GetFormatIndex(pixelFormat);
|
||||
return fFormatTable[index];
|
||||
}
|
||||
|
||||
MTLPixelFormat fColorTypeToFormatTable[kSkColorTypeCnt];
|
||||
void setColorType(SkColorType, std::initializer_list<MTLPixelFormat> formats);
|
||||
|
||||
// A vector of the viable sample counts (e.g., { 1, 2, 4, 8 }).
|
||||
std::vector<uint32_t> fColorSampleCounts;
|
||||
|
||||
GPUFamily fGPUFamily;
|
||||
int fFamilyGroup;
|
||||
};
|
||||
|
@ -236,6 +236,16 @@ void Caps::initCaps(const id<MTLDevice> device) {
|
||||
} else {
|
||||
fClampToBorderSupport = false;
|
||||
}
|
||||
|
||||
// Init sample counts. All devices support 1 (i.e. 0 in skia).
|
||||
fColorSampleCounts.push_back(1);
|
||||
if (@available(macOS 10.11, iOS 9.0, *)) {
|
||||
for (auto sampleCnt : {2, 4, 8}) {
|
||||
if ([device supportsTextureSampleCount:sampleCnt]) {
|
||||
fColorSampleCounts.push_back(sampleCnt);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Caps::initShaderCaps() {
|
||||
@ -266,8 +276,192 @@ void Caps::initShaderCaps() {
|
||||
shaderCaps->fFloatIs32Bits = true;
|
||||
}
|
||||
|
||||
// These are all the valid MTLPixelFormats that we currently support in Skia. They are roughly
|
||||
// ordered from most frequently used to least to improve look up times in arrays.
|
||||
static constexpr MTLPixelFormat kMtlFormats[] = {
|
||||
MTLPixelFormatRGBA8Unorm,
|
||||
MTLPixelFormatR8Unorm,
|
||||
MTLPixelFormatA8Unorm,
|
||||
MTLPixelFormatBGRA8Unorm,
|
||||
|
||||
MTLPixelFormatStencil8,
|
||||
MTLPixelFormatDepth32Float,
|
||||
MTLPixelFormatDepth32Float_Stencil8,
|
||||
|
||||
MTLPixelFormatInvalid,
|
||||
};
|
||||
|
||||
void Caps::setColorType(SkColorType colorType, std::initializer_list<MTLPixelFormat> formats) {
|
||||
#ifdef SK_DEBUG
|
||||
for (size_t i = 0; i < kNumMtlFormats; ++i) {
|
||||
const auto& formatInfo = fFormatTable[i];
|
||||
for (int j = 0; j < formatInfo.fColorTypeInfoCount; ++j) {
|
||||
const auto& ctInfo = formatInfo.fColorTypeInfos[j];
|
||||
if (ctInfo.fColorType == colorType) {
|
||||
bool found = false;
|
||||
for (auto it = formats.begin(); it != formats.end(); ++it) {
|
||||
if (kMtlFormats[i] == *it) {
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
SkASSERT(found);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
int idx = static_cast<int>(colorType);
|
||||
for (auto it = formats.begin(); it != formats.end(); ++it) {
|
||||
const auto& info = this->getFormatInfo(*it);
|
||||
for (int i = 0; i < info.fColorTypeInfoCount; ++i) {
|
||||
if (info.fColorTypeInfos[i].fColorType == colorType) {
|
||||
fColorTypeToFormatTable[idx] = *it;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size_t Caps::GetFormatIndex(MTLPixelFormat pixelFormat) {
|
||||
static_assert(SK_ARRAY_COUNT(kMtlFormats) == Caps::kNumMtlFormats,
|
||||
"Size of kMtlFormats array must match static value in header");
|
||||
for (size_t i = 0; i < Caps::kNumMtlFormats; ++i) {
|
||||
if (kMtlFormats[i] == pixelFormat) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return GetFormatIndex(MTLPixelFormatInvalid);
|
||||
}
|
||||
|
||||
void Caps::initFormatTable() {
|
||||
// TODO
|
||||
FormatInfo* info;
|
||||
|
||||
// Format: RGBA8Unorm
|
||||
{
|
||||
info = &fFormatTable[GetFormatIndex(MTLPixelFormatRGBA8Unorm)];
|
||||
info->fFlags = FormatInfo::kAllFlags;
|
||||
info->fColorTypeInfoCount = 2;
|
||||
info->fColorTypeInfos.reset(new ColorTypeInfo[info->fColorTypeInfoCount]());
|
||||
int ctIdx = 0;
|
||||
// Format: RGBA8Unorm, Surface: kRGBA_8888
|
||||
{
|
||||
auto& ctInfo = info->fColorTypeInfos[ctIdx++];
|
||||
ctInfo.fColorType = kRGBA_8888_SkColorType;
|
||||
ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
|
||||
}
|
||||
// Format: RGBA8Unorm, Surface: kRGB_888x
|
||||
{
|
||||
auto& ctInfo = info->fColorTypeInfos[ctIdx++];
|
||||
ctInfo.fColorType = kRGB_888x_SkColorType;
|
||||
ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag;
|
||||
ctInfo.fReadSwizzle = skgpu::Swizzle::RGB1();
|
||||
}
|
||||
}
|
||||
|
||||
// Format: R8Unorm
|
||||
{
|
||||
info = &fFormatTable[GetFormatIndex(MTLPixelFormatR8Unorm)];
|
||||
info->fFlags = FormatInfo::kAllFlags;
|
||||
info->fColorTypeInfoCount = 3;
|
||||
info->fColorTypeInfos.reset(new ColorTypeInfo[info->fColorTypeInfoCount]());
|
||||
int ctIdx = 0;
|
||||
// Format: R8Unorm, Surface: kR8_unorm
|
||||
{
|
||||
auto& ctInfo = info->fColorTypeInfos[ctIdx++];
|
||||
ctInfo.fColorType = kR8_unorm_SkColorType;
|
||||
ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
|
||||
}
|
||||
// Format: R8Unorm, Surface: kAlpha_8
|
||||
{
|
||||
auto& ctInfo = info->fColorTypeInfos[ctIdx++];
|
||||
ctInfo.fColorType = kAlpha_8_SkColorType;
|
||||
ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
|
||||
ctInfo.fReadSwizzle = skgpu::Swizzle("000r");
|
||||
ctInfo.fWriteSwizzle = skgpu::Swizzle("a000");
|
||||
}
|
||||
// Format: R8Unorm, Surface: kGray_8
|
||||
{
|
||||
auto& ctInfo = info->fColorTypeInfos[ctIdx++];
|
||||
ctInfo.fColorType = kGray_8_SkColorType;
|
||||
ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag;
|
||||
ctInfo.fReadSwizzle = skgpu::Swizzle("rrr1");
|
||||
}
|
||||
}
|
||||
|
||||
// Format: A8Unorm
|
||||
{
|
||||
info = &fFormatTable[GetFormatIndex(MTLPixelFormatA8Unorm)];
|
||||
info->fFlags = FormatInfo::kTexturable_Flag;
|
||||
info->fColorTypeInfoCount = 1;
|
||||
info->fColorTypeInfos.reset(new ColorTypeInfo[info->fColorTypeInfoCount]());
|
||||
int ctIdx = 0;
|
||||
// Format: A8Unorm, Surface: kAlpha_8
|
||||
{
|
||||
auto& ctInfo = info->fColorTypeInfos[ctIdx++];
|
||||
ctInfo.fColorType = kAlpha_8_SkColorType;
|
||||
ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
|
||||
}
|
||||
}
|
||||
|
||||
// Format: BGRA8Unorm
|
||||
{
|
||||
info = &fFormatTable[GetFormatIndex(MTLPixelFormatBGRA8Unorm)];
|
||||
info->fFlags = FormatInfo::kAllFlags;
|
||||
info->fColorTypeInfoCount = 1;
|
||||
info->fColorTypeInfos.reset(new ColorTypeInfo[info->fColorTypeInfoCount]());
|
||||
int ctIdx = 0;
|
||||
// Format: BGRA8Unorm, Surface: kBGRA_8888
|
||||
{
|
||||
auto& ctInfo = info->fColorTypeInfos[ctIdx++];
|
||||
ctInfo.fColorType = kBGRA_8888_SkColorType;
|
||||
ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Non-color formats
|
||||
*/
|
||||
|
||||
// Format: Stencil8
|
||||
{
|
||||
info = &fFormatTable[GetFormatIndex(MTLPixelFormatStencil8)];
|
||||
info->fFlags = FormatInfo::kMSAA_Flag;
|
||||
info->fColorTypeInfoCount = 0;
|
||||
}
|
||||
|
||||
// Format: Depth32Float
|
||||
{
|
||||
info = &fFormatTable[GetFormatIndex(MTLPixelFormatDepth32Float)];
|
||||
info->fFlags = FormatInfo::kMSAA_Flag;
|
||||
if (this->isMac() || fFamilyGroup >= 3) {
|
||||
info->fFlags |= FormatInfo::kResolve_Flag;
|
||||
}
|
||||
info->fColorTypeInfoCount = 0;
|
||||
}
|
||||
|
||||
// Format: Depth32Float_Stencil8
|
||||
{
|
||||
info = &fFormatTable[GetFormatIndex(MTLPixelFormatDepth32Float_Stencil8)];
|
||||
info->fFlags = FormatInfo::kMSAA_Flag;
|
||||
if (this->isMac() || fFamilyGroup >= 3) {
|
||||
info->fFlags |= FormatInfo::kResolve_Flag;
|
||||
}
|
||||
info->fColorTypeInfoCount = 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Map SkColorTypes (used for creating SkSurfaces) to MTLPixelFormats. The order in which the
|
||||
// formats are passed into the setColorType function indicates the priority in selecting which
|
||||
// format we use for a given SkColorType.
|
||||
|
||||
std::fill_n(fColorTypeToFormatTable, kSkColorTypeCnt, MTLPixelFormatInvalid);
|
||||
|
||||
this->setColorType(kAlpha_8_SkColorType, { MTLPixelFormatR8Unorm,
|
||||
MTLPixelFormatA8Unorm });
|
||||
this->setColorType(kRGBA_8888_SkColorType, { MTLPixelFormatRGBA8Unorm });
|
||||
this->setColorType(kRGB_888x_SkColorType, { MTLPixelFormatRGBA8Unorm });
|
||||
this->setColorType(kBGRA_8888_SkColorType, { MTLPixelFormatBGRA8Unorm });
|
||||
this->setColorType(kGray_8_SkColorType, { MTLPixelFormatR8Unorm });
|
||||
this->setColorType(kR8_unorm_SkColorType, { MTLPixelFormatR8Unorm });
|
||||
}
|
||||
|
||||
skgpu::TextureInfo Caps::getDefaultSampledTextureInfo(SkColorType colorType,
|
||||
@ -356,9 +550,8 @@ bool Caps::onIsTexturable(const skgpu::TextureInfo& info) const {
|
||||
}
|
||||
|
||||
bool Caps::isTexturable(MTLPixelFormat format) const {
|
||||
// TODO: Fill out format table so that we can query all formats. For now we only support RGBA8
|
||||
// and BGRA8 which is supported everywhere.
|
||||
return format == MTLPixelFormatRGBA8Unorm || format == MTLPixelFormatBGRA8Unorm;
|
||||
const FormatInfo& formatInfo = this->getFormatInfo(format);
|
||||
return SkToBool(FormatInfo::kTexturable_Flag && formatInfo.fFlags);
|
||||
}
|
||||
|
||||
bool Caps::isRenderable(const skgpu::TextureInfo& info) const {
|
||||
@ -366,24 +559,33 @@ bool Caps::isRenderable(const skgpu::TextureInfo& info) const {
|
||||
this->isRenderable((MTLPixelFormat)info.mtlTextureSpec().fFormat, info.numSamples());
|
||||
}
|
||||
|
||||
bool Caps::isRenderable(MTLPixelFormat format, uint32_t numSamples) const {
|
||||
// TODO: Fill out format table so that we can query all formats. For now we only support RGBA8
|
||||
// and BGRA8 with a sampleCount of 1 which is supported everywhere.
|
||||
if ((format != MTLPixelFormatRGBA8Unorm && format != MTLPixelFormatBGRA8Unorm) ||
|
||||
numSamples != 1) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
bool Caps::isRenderable(MTLPixelFormat format, uint32_t sampleCount) const {
|
||||
return sampleCount <= this->maxRenderTargetSampleCount(format);
|
||||
}
|
||||
|
||||
bool Caps::onAreColorTypeAndTextureInfoCompatible(SkColorType type,
|
||||
const skgpu::TextureInfo& info) const {
|
||||
// TODO: Fill out format table so that we can query all formats. For now we only support RGBA8
|
||||
// or BGRA8 for both the color type and format.
|
||||
return (type == kRGBA_8888_SkColorType &&
|
||||
info.mtlTextureSpec().fFormat == MTLPixelFormatRGBA8Unorm) ||
|
||||
(type == kBGRA_8888_SkColorType &&
|
||||
info.mtlTextureSpec().fFormat == MTLPixelFormatBGRA8Unorm);
|
||||
uint32_t Caps::maxRenderTargetSampleCount(MTLPixelFormat format) const {
|
||||
const FormatInfo& formatInfo = this->getFormatInfo(format);
|
||||
if (!SkToBool(formatInfo.fFlags & FormatInfo::kRenderable_Flag)) {
|
||||
return 0;
|
||||
}
|
||||
if (SkToBool(formatInfo.fFlags & FormatInfo::kMSAA_Flag)) {
|
||||
return fColorSampleCounts[fColorSampleCounts.size() - 1];
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
bool Caps::onAreColorTypeAndTextureInfoCompatible(SkColorType ct,
|
||||
const skgpu::TextureInfo& textureInfo) const {
|
||||
MTLPixelFormat mtlFormat = static_cast<MTLPixelFormat>(textureInfo.mtlTextureSpec().fFormat);
|
||||
|
||||
const auto& info = this->getFormatInfo(mtlFormat);
|
||||
for (int i = 0; i < info.fColorTypeInfoCount; ++i) {
|
||||
if (info.fColorTypeInfos[i].fColorType == ct) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t Caps::getTransferBufferAlignment(size_t bytesPerPixel) const {
|
||||
|
@ -61,5 +61,6 @@ enum SkColorType : int {
|
||||
#error "SK_*32_SHIFT values must correspond to BGRA or RGBA byte order"
|
||||
#endif
|
||||
};
|
||||
static constexpr int kSkColorTypeCnt = static_cast<int>(kLastEnum_SkColorType) + 1;
|
||||
|
||||
#endif
|
||||
|
@ -42,8 +42,8 @@ DEF_GRAPHITE_TEST_FOR_CONTEXTS(MtlBackendTextureTest, reporter, context) {
|
||||
REPORTER_ASSERT(reporter, beTexture.isValid());
|
||||
context->deleteBackendTexture(beTexture);
|
||||
|
||||
// It should fail with a format that isn't rgba8
|
||||
textureInfo.fFormat = MTLPixelFormatR8Unorm;
|
||||
// It should fail with a format that isn't one of our supported formats
|
||||
textureInfo.fFormat = MTLPixelFormatRGB9E5Float;
|
||||
beTexture = context->createBackendTexture(kSize, textureInfo);
|
||||
REPORTER_ASSERT(reporter, !beTexture.isValid());
|
||||
context->deleteBackendTexture(beTexture);
|
||||
|
Loading…
Reference in New Issue
Block a user