Add caps files for metal

Bug: skia:
Change-Id: I8e7488320d4237cf67d6ebeaad319d3de75b67e6
Reviewed-on: https://skia-review.googlesource.com/27741
Commit-Queue: Greg Daniel <egdaniel@google.com>
Reviewed-by: Brian Salomon <bsalomon@google.com>
Reviewed-by: Ethan Nicholas <ethannicholas@google.com>
This commit is contained in:
Greg Daniel 2017-07-31 10:45:52 -04:00 committed by Skia Commit-Bot
parent 6bd729d8eb
commit cebcb84739
6 changed files with 495 additions and 3 deletions

View File

@ -581,6 +581,8 @@ skia_vk_sources = [
skia_metal_sources = [
"$_include/gpu/mtl/GrMtlTypes.h",
"$_src/gpu/mtl/GrMtlCaps.h",
"$_src/gpu/mtl/GrMtlCaps.mm",
"$_src/gpu/mtl/GrMtlGpu.h",
"$_src/gpu/mtl/GrMtlGpu.mm",
"$_src/gpu/mtl/GrMtlTrampoline.h",

View File

@ -331,6 +331,7 @@ private:
uint8_t fSamplerPrecisions[(1 << kGrShaderTypeCount)][kGrPixelConfigCnt];
friend class GrGLCaps; // For initialization.
friend class GrMtlCaps;
friend class GrVkCaps;
friend class SkSL::ShaderCapsFactory;
};

97
src/gpu/mtl/GrMtlCaps.h Normal file
View File

@ -0,0 +1,97 @@
/*
* Copyright 2017 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef GrMtlCaps_DEFINED
#define GrMtlCaps_DEFINED
#include "GrCaps.h"
#include "SkTDArray.h"
#import <Metal/Metal.h>
class GrShaderCaps;
/**
* Stores some capabilities of a Mtl backend.
*/
class GrMtlCaps : public GrCaps {
public:
GrMtlCaps(const GrContextOptions& contextOptions, id<MTLDevice> device,
MTLFeatureSet featureSet);
int getSampleCount(int requestedCount, GrPixelConfig config) const override;
bool isConfigTexturable(GrPixelConfig config) const override {
return SkToBool(fConfigTable[config].fFlags & ConfigInfo::kTextureable_Flag);
}
bool isConfigRenderable(GrPixelConfig config, bool withMSAA) const override {
if (withMSAA) {
return SkToBool(fConfigTable[config].fFlags & ConfigInfo::kRenderable_Flag) &&
SkToBool(fConfigTable[config].fFlags & ConfigInfo::kMSAA_Flag);
} else {
return SkToBool(fConfigTable[config].fFlags & ConfigInfo::kRenderable_Flag);
}
}
bool canConfigBeImageStorage(GrPixelConfig) const override { return false; }
#if 0
/**
* Returns both a supported and most prefered stencil format to use in draws.
*/
const StencilFormat& preferedStencilFormat() const {
return fPreferedStencilFormat;
}
#endif
bool initDescForDstCopy(const GrRenderTargetProxy* src, GrSurfaceDesc* desc,
bool* rectsMustMatch, bool* disallowSubrect) const override {
return false;
}
private:
void initFeatureSet(MTLFeatureSet featureSet);
void initGrCaps(const id<MTLDevice> device);
void initShaderCaps();
void initSampleCount();
void initConfigTable();
struct ConfigInfo {
ConfigInfo() : fFlags(0) {}
enum {
kTextureable_Flag = 0x1,
kRenderable_Flag = 0x2, // Color attachment and blendable
kMSAA_Flag = 0x4,
kResolve_Flag = 0x8,
};
static const uint16_t kAllFlags = kTextureable_Flag | kRenderable_Flag |
kMSAA_Flag | kResolve_Flag;
uint16_t fFlags;
};
ConfigInfo fConfigTable[kGrPixelConfigCnt];
enum class Platform {
kMac,
kIOS
};
bool isMac() { return Platform::kMac == fPlatform; }
bool isIOS() { return Platform::kIOS == fPlatform; }
Platform fPlatform;
int fFamilyGroup;
int fVersion;
SkTDArray<int> fSampleCounts;
typedef GrCaps INHERITED;
};
#endif

322
src/gpu/mtl/GrMtlCaps.mm Normal file
View File

@ -0,0 +1,322 @@
/*
* Copyright 2017 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "GrMtlCaps.h"
#include "GrShaderCaps.h"
GrMtlCaps::GrMtlCaps(const GrContextOptions& contextOptions, const id<MTLDevice> device,
MTLFeatureSet featureSet)
: INHERITED(contextOptions) {
fShaderCaps.reset(new GrShaderCaps(contextOptions));
this->initFeatureSet(featureSet);
this->initGrCaps(device);
this->initShaderCaps();
this->initConfigTable();
this->applyOptionsOverrides(contextOptions);
fShaderCaps->applyOptionsOverrides(contextOptions);
}
void GrMtlCaps::initFeatureSet(MTLFeatureSet featureSet) {
// Mac OSX
#ifdef SK_BUILD_FOR_MAC
if (MTLFeatureSet_OSX_GPUFamily1_v2 == featureSet) {
fPlatform = Platform::kMac;
fFamilyGroup = 1;
fVersion = 2;
return;
}
if (MTLFeatureSet_OSX_GPUFamily1_v1 == featureSet) {
fPlatform = Platform::kMac;
fFamilyGroup = 1;
fVersion = 1;
return;
}
#endif
// iOS Family group 3
#ifdef SK_BUILD_FOR_IOS
if (MTLFeatureSet_iOS_GPUFamily3_v2 == featureSet) {
fPlatform = Platform::kIOS;
fFamilyGroup = 3;
fVersion = 2;
return;
}
if (MTLFeatureSet_iOS_GPUFamily3_v1 == featureSet) {
fPlatform = Platform::kIOS;
fFamilyGroup = 3;
fVersion = 1;
return;
}
// iOS Family group 2
if (MTLFeatureSet_iOS_GPUFamily2_v3 == featureSet) {
fPlatform = Platform::kIOS;
fFamilyGroup = 2;
fVersion = 3;
return;
}
if (MTLFeatureSet_iOS_GPUFamily2_v2 == featureSet) {
fPlatform = Platform::kIOS;
fFamilyGroup = 2;
fVersion = 2;
return;
}
if (MTLFeatureSet_iOS_GPUFamily2_v1 == featureSet) {
fPlatform = Platform::kIOS;
fFamilyGroup = 2;
fVersion = 1;
return;
}
// iOS Family group 1
if (MTLFeatureSet_iOS_GPUFamily1_v3 == featureSet) {
fPlatform = Platform::kIOS;
fFamilyGroup = 1;
fVersion = 3;
return;
}
if (MTLFeatureSet_iOS_GPUFamily1_v2 == featureSet) {
fPlatform = Platform::kIOS;
fFamilyGroup = 1;
fVersion = 2;
return;
}
if (MTLFeatureSet_iOS_GPUFamily1_v1 == featureSet) {
fPlatform = Platform::kIOS;
fFamilyGroup = 1;
fVersion = 1;
return;
}
#endif
// No supported feature sets were found
SkFAIL("Requested an unsupported feature set");
}
void GrMtlCaps::initGrCaps(const id<MTLDevice> device) {
// Max vertex attribs is the same on all devices
fMaxVertexAttributes = 31;
// RenderTarget and Texture size
if (this->isMac()) {
fMaxRenderTargetSize = 16384;
} else {
if (3 == fFamilyGroup) {
fMaxRenderTargetSize = 16384;
} else {
// Family group 1 and 2 support 8192 for version 2 and above, 4096 for v1
if (1 == fVersion) {
fMaxRenderTargetSize = 4096;
} else {
fMaxRenderTargetSize = 8192;
}
}
}
fMaxTextureSize = fMaxRenderTargetSize;
// Init sample counts. All devices support 1 (i.e. 0 in skia).
fSampleCounts.push(0);
for (auto sampleCnt : {2, 4, 8}) {
if ([device supportsTextureSampleCount:sampleCnt]) {
fSampleCounts.push(sampleCnt);
}
}
// Starting with the assumption that there isn't a reason to not map small buffers.
fBufferMapThreshold = 0;
// Buffers are always fully mapped.
fMapBufferFlags = kCanMap_MapFlag;
fOversizedStencilSupport = true;
// Looks like there is a field called rasterSampleCount labeled as beta in the Metal docs. This
// may be what we eventually need here, but it has no description.
fSampleShadingSupport = false;
fSRGBSupport = true; // always available in Metal
fSRGBWriteControl = false;
fMipMapSupport = true; // always available in Metal
fNPOTTextureTileSupport = true; // always available in Metal
fDiscardRenderTargetSupport = true;
fReuseScratchTextures = true; // Assuming this okay
fTextureBarrierSupport = false; // Need to figure out if we can do this
fSampleLocationsSupport = false;
fMultisampleDisableSupport = false;
if (this->isMac() || 3 == fFamilyGroup) {
fInstanceAttribSupport = true;
}
fUsesMixedSamples = false;
fGpuTracingSupport = false;
fUseDrawInsteadOfClear = false;
fFenceSyncSupport = true; // always available in Metal
fCrossContextTextureSupport = false;
fMaxColorSampleCount = 4; // minimum required by spec
fMaxStencilSampleCount = 4; // minimum required by spec
}
int GrMtlCaps::getSampleCount(int requestedCount, GrPixelConfig config) const {
int count = fSampleCounts.count();
SkASSERT(count > 0); // We always add 0 as a valid sample count
if (!this->isConfigRenderable(config, true)) {
return 0;
}
for (int i = 0; i < count; ++i) {
if (fSampleCounts[i] >= requestedCount) {
return fSampleCounts[i];
}
}
return fSampleCounts[count-1];
}
void GrMtlCaps::initShaderCaps() {
GrShaderCaps* shaderCaps = fShaderCaps.get();
// fConfigOutputSwizzle will default to RGBA so we only need to set it for alpha only config.
for (int i = 0; i < kGrPixelConfigCnt; ++i) {
GrPixelConfig config = static_cast<GrPixelConfig>(i);
if (GrPixelConfigIsAlphaOnly(config)) {
shaderCaps->fConfigTextureSwizzle[i] = GrSwizzle::RRRR();
shaderCaps->fConfigOutputSwizzle[i] = GrSwizzle::AAAA();
} else {
if (kGray_8_GrPixelConfig == config) {
shaderCaps->fConfigTextureSwizzle[i] = GrSwizzle::RRRA();
} else {
shaderCaps->fConfigTextureSwizzle[i] = GrSwizzle::RGBA();
}
}
}
// Setting this true with the assumption that this cap will eventually mean we support varying
// percisions and not just via modifiers.
shaderCaps->fUsesPrecisionModifiers = true;
shaderCaps->fFlatInterpolationSupport = true;
shaderCaps->fShaderDerivativeSupport = true;
shaderCaps->fGeometryShaderSupport = false;
if ((this->isMac() && fVersion >= 2) ||
(this->isIOS() && ((1 == fFamilyGroup && 4 == fVersion) ||
(2 == fFamilyGroup && 4 == fVersion) ||
(3 == fFamilyGroup && 3 == fVersion)))) {
shaderCaps->fDualSourceBlendingSupport = true;
}
if (this->isIOS()) {
shaderCaps->fFBFetchSupport = true;
shaderCaps->fFBFetchNeedsCustomOutput = true; // ??
shaderCaps->fFBFetchColorName = ""; // Somehow add [[color(0)]] to arguments to frag shader
}
shaderCaps->fDstReadInShaderSupport = shaderCaps->fFBFetchSupport;
shaderCaps->fIntegerSupport = true;
shaderCaps->fTexelBufferSupport = false;
shaderCaps->fTexelFetchSupport = false;
shaderCaps->fVertexIDSupport = false;
shaderCaps->fImageLoadStoreSupport = false;
shaderCaps->fShaderPrecisionVaries = false; // ???
// Metal uses IEEE float and half floats so using those values here.
for (int s = 0; s < kGrShaderTypeCount; ++s) {
auto& highp = shaderCaps->fFloatPrecisions[s][kHigh_GrSLPrecision];
highp.fLogRangeLow = highp.fLogRangeHigh = 127;
highp.fBits = 23;
auto& mediump = shaderCaps->fFloatPrecisions[s][kMedium_GrSLPrecision];
mediump.fLogRangeLow = mediump.fLogRangeHigh = 15;
mediump.fBits = 10;
shaderCaps->fFloatPrecisions[s][kLow_GrSLPrecision] = mediump;
}
shaderCaps->initSamplerPrecisionTable();
shaderCaps->fMaxVertexSamplers =
shaderCaps->fMaxFragmentSamplers = 16;
// For now just cap at the per stage max. If we hit this limit we can come back to adjust this
shaderCaps->fMaxCombinedSamplers = shaderCaps->fMaxVertexSamplers;
}
void GrMtlCaps::initConfigTable() {
ConfigInfo* info;
// Alpha_8 uses R8Unorm
info = &fConfigTable[kAlpha_8_GrPixelConfig];
info->fFlags = ConfigInfo::kAllFlags;
// Gray_8 uses R8Unorm
info = &fConfigTable[kGray_8_GrPixelConfig];
info->fFlags = ConfigInfo::kAllFlags;
// RGB_565 uses B5G6R5Unorm, even though written opposite this format packs how we want
info = &fConfigTable[kRGB_565_GrPixelConfig];
if (this->isMac()) {
info->fFlags = 0;
} else {
info->fFlags = ConfigInfo::kAllFlags;
}
// RGBA_4444 uses ABGR4Unorm
info = &fConfigTable[kRGBA_4444_GrPixelConfig];
if (this->isMac()) {
info->fFlags = 0;
} else {
info->fFlags = ConfigInfo::kAllFlags;
}
// RGBA_8888 uses RGBA8Unorm
info = &fConfigTable[kRGBA_8888_GrPixelConfig];
info->fFlags = ConfigInfo::kAllFlags;
// BGRA_8888 uses BGRA8Unorm
info = &fConfigTable[kBGRA_8888_GrPixelConfig];
info->fFlags = ConfigInfo::kAllFlags;
// SRGBA_8888 uses RGBA8Unorm_sRGB
info = &fConfigTable[kSRGBA_8888_GrPixelConfig];
info->fFlags = ConfigInfo::kAllFlags;
// SBGRA_8888 uses BGRA8Unorm_sRGB
info = &fConfigTable[kSBGRA_8888_GrPixelConfig];
info->fFlags = ConfigInfo::kAllFlags;
// RGBA_8888_sint uses RGBA8Sint
info = &fConfigTable[kRGBA_8888_sint_GrPixelConfig];
info->fFlags = ConfigInfo::kMSAA_Flag;
// RGBA_float uses RGBA32Float
info = &fConfigTable[kRGBA_float_GrPixelConfig];
if (this->isMac()) {
info->fFlags = ConfigInfo::kAllFlags;
} else {
info->fFlags = 0;
}
// RG_float uses RG32Float
info = &fConfigTable[kRG_float_GrPixelConfig];
if (this->isMac()) {
info->fFlags = ConfigInfo::kAllFlags;
} else {
info->fFlags = ConfigInfo::kRenderable_Flag;
}
// Alpha_half uses R16Float
info = &fConfigTable[kAlpha_half_GrPixelConfig];
info->fFlags = ConfigInfo::kAllFlags;
// RGBA_half uses RGBA16Float
info = &fConfigTable[kRGBA_half_GrPixelConfig];
info->fFlags = ConfigInfo::kAllFlags;
}

View File

@ -13,6 +13,8 @@
#include "GrSemaphore.h"
#include "GrTexture.h"
#include "GrMtlCaps.h"
#import <Metal/Metal.h>
class GrSemaphore;
@ -24,6 +26,8 @@ public:
id<MTLDevice> device, id<MTLCommandQueue> queue);
~GrMtlGpu() override {}
const GrMtlCaps& mtlCaps() const { return *fMtlCaps.get(); }
bool onGetReadPixelsInfo(GrSurface* srcSurface, int readWidth, int readHeight, size_t rowBytes,
GrPixelConfig readConfig, DrawPreference*,
@ -61,7 +65,7 @@ public:
private:
GrMtlGpu(GrContext* context, const GrContextOptions& options,
id<MTLDevice> device, id<MTLCommandQueue> queue);
id<MTLDevice> device, id<MTLCommandQueue> queue, MTLFeatureSet featureSet);
void onResetContext(uint32_t resetBits) override {}
@ -141,6 +145,8 @@ private:
bool isTestingOnlyBackendTexture(GrBackendObject ) const override { return false; }
void deleteTestingOnlyBackendTexture(GrBackendObject, bool abandonTexture) override {}
sk_sp<GrMtlCaps> fMtlCaps;
id<MTLDevice> fDevice;
id<MTLCommandQueue> fQueue;

View File

@ -11,19 +11,83 @@
#error This file must be compiled with Arc. Use -fobjc-arc flag
#endif
static bool get_feature_set(id<MTLDevice> device, MTLFeatureSet* featureSet) {
// Mac OSX
#ifdef SK_BUILD_FOR_MAC
if ([device supportsFeatureSet:MTLFeatureSet_OSX_GPUFamily1_v2]) {
*featureSet = MTLFeatureSet_OSX_GPUFamily1_v2;
return true;
}
if ([device supportsFeatureSet:MTLFeatureSet_OSX_GPUFamily1_v1]) {
*featureSet = MTLFeatureSet_OSX_GPUFamily1_v1;
return true;
}
#endif
// iOS Family group 3
#ifdef SK_BUILD_FOR_IOS
if ([device supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily3_v2]) {
*featureSet = MTLFeatureSet_iOS_GPUFamily3_v2;
return true;
}
if ([device supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily3_v1]) {
*featureSet = MTLFeatureSet_iOS_GPUFamily3_v1;
return true;
}
// iOS Family group 2
if ([device supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily2_v3]) {
*featureSet = MTLFeatureSet_iOS_GPUFamily2_v3;
return true;
}
if ([device supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily2_v2]) {
*featureSet = MTLFeatureSet_iOS_GPUFamily2_v2;
return true;
}
if ([device supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily2_v1]) {
*featureSet = MTLFeatureSet_iOS_GPUFamily2_v1;
return true;
}
// iOS Family group 1
if ([device supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily1_v3]) {
*featureSet = MTLFeatureSet_iOS_GPUFamily1_v3;
return true;
}
if ([device supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily1_v2]) {
*featureSet = MTLFeatureSet_iOS_GPUFamily1_v2;
return true;
}
if ([device supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily1_v1]) {
*featureSet = MTLFeatureSet_iOS_GPUFamily1_v1;
return true;
}
#endif
// No supported feature sets were found
return false;
}
GrGpu* GrMtlGpu::Create(GrContext* context, const GrContextOptions& options,
id<MTLDevice> device, id<MTLCommandQueue> queue) {
if (!device || !queue) {
return nullptr;
}
return new GrMtlGpu(context, options, device, queue);
MTLFeatureSet featureSet;
if (!get_feature_set(device, &featureSet)) {
return nullptr;
}
return new GrMtlGpu(context, options, device, queue, featureSet);
}
GrMtlGpu::GrMtlGpu(GrContext* context, const GrContextOptions& options,
id<MTLDevice> device, id<MTLCommandQueue> queue)
id<MTLDevice> device, id<MTLCommandQueue> queue, MTLFeatureSet featureSet)
: INHERITED(context)
, fDevice(device)
, fQueue(queue) {
fMtlCaps.reset(new GrMtlCaps(options, fDevice, featureSet));
fCaps = fMtlCaps;
MTLTextureDescriptor* txDesc = [[MTLTextureDescriptor alloc] init];
txDesc.textureType = MTLTextureType3D;
txDesc.height = 64;