diff options
author | Greg Daniel <egdaniel@google.com> | 2017-07-31 10:45:52 -0400 |
---|---|---|
committer | Skia Commit-Bot <skia-commit-bot@chromium.org> | 2017-07-31 15:03:22 +0000 |
commit | cebcb84739c261e729a054ff097adca32a1b537f (patch) | |
tree | 6b936450dc9b90357152c94e32d4c77bdba66042 | |
parent | 6bd729d8ebc98548fd92e081e1d1163bbc2ec815 (diff) |
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>
-rw-r--r-- | gn/gpu.gni | 2 | ||||
-rw-r--r-- | include/gpu/GrShaderCaps.h | 1 | ||||
-rw-r--r-- | src/gpu/mtl/GrMtlCaps.h | 97 | ||||
-rw-r--r-- | src/gpu/mtl/GrMtlCaps.mm | 322 | ||||
-rw-r--r-- | src/gpu/mtl/GrMtlGpu.h | 8 | ||||
-rw-r--r-- | src/gpu/mtl/GrMtlGpu.mm | 68 |
6 files changed, 495 insertions, 3 deletions
diff --git a/gn/gpu.gni b/gn/gpu.gni index 3db9acc08e..49e3361ad2 100644 --- a/gn/gpu.gni +++ b/gn/gpu.gni @@ -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", diff --git a/include/gpu/GrShaderCaps.h b/include/gpu/GrShaderCaps.h index 006efb6125..60af6f6587 100644 --- a/include/gpu/GrShaderCaps.h +++ b/include/gpu/GrShaderCaps.h @@ -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; }; diff --git a/src/gpu/mtl/GrMtlCaps.h b/src/gpu/mtl/GrMtlCaps.h new file mode 100644 index 0000000000..9590bb9e12 --- /dev/null +++ b/src/gpu/mtl/GrMtlCaps.h @@ -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 diff --git a/src/gpu/mtl/GrMtlCaps.mm b/src/gpu/mtl/GrMtlCaps.mm new file mode 100644 index 0000000000..29e28cff03 --- /dev/null +++ b/src/gpu/mtl/GrMtlCaps.mm @@ -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; +} diff --git a/src/gpu/mtl/GrMtlGpu.h b/src/gpu/mtl/GrMtlGpu.h index f150e3034a..53c214943f 100644 --- a/src/gpu/mtl/GrMtlGpu.h +++ b/src/gpu/mtl/GrMtlGpu.h @@ -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; diff --git a/src/gpu/mtl/GrMtlGpu.mm b/src/gpu/mtl/GrMtlGpu.mm index 986bb8a6f7..7a9a673d69 100644 --- a/src/gpu/mtl/GrMtlGpu.mm +++ b/src/gpu/mtl/GrMtlGpu.mm @@ -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; |