aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorGravatar Greg Daniel <egdaniel@google.com>2017-07-31 10:45:52 -0400
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2017-07-31 15:03:22 +0000
commitcebcb84739c261e729a054ff097adca32a1b537f (patch)
tree6b936450dc9b90357152c94e32d4c77bdba66042 /src
parent6bd729d8ebc98548fd92e081e1d1163bbc2ec815 (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>
Diffstat (limited to 'src')
-rw-r--r--src/gpu/mtl/GrMtlCaps.h97
-rw-r--r--src/gpu/mtl/GrMtlCaps.mm322
-rw-r--r--src/gpu/mtl/GrMtlGpu.h8
-rw-r--r--src/gpu/mtl/GrMtlGpu.mm68
4 files changed, 492 insertions, 3 deletions
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;