[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:
Jim Van Verth 2022-03-25 16:27:50 -04:00 committed by SkCQ
parent a06240b2dc
commit f151351f47
5 changed files with 286 additions and 23 deletions

View File

@ -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;

View File

@ -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;
};

View File

@ -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 {

View File

@ -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

View File

@ -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);