From d29d885c882c5ff67b117aaa4e5009365ec8d1bd Mon Sep 17 00:00:00 2001 From: Jim Van Verth Date: Wed, 18 Mar 2020 13:36:32 -0400 Subject: [PATCH] Reland "Set up eGPU/discrete support for MacOS." This is a reland of 1c3bea4593b131004912f3214726e64e514ecd56 Original change's description: > Set up eGPU/discrete support for MacOS. > > Pulled out of https://skia-review.googlesource.com/c/skia/+/271319. > > For Metal, will default to an eGPU or discrete GPU if one is available. > For GL, will attempt to use a Radeon eGPU, and will fallback > if one can't be found. > > Change-Id: I0a1efb3afca612ac75be56f633d811dda68f9d10 > Reviewed-on: https://skia-review.googlesource.com/c/skia/+/277516 > Reviewed-by: Brian Salomon > Commit-Queue: Jim Van Verth Change-Id: I1f9dcbf82465533ae8bce96b5cc73a7c627071a4 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/277696 Reviewed-by: Jim Van Verth Reviewed-by: Greg Daniel Commit-Queue: Jim Van Verth --- src/gpu/mtl/GrMtlCaps.h | 1 + src/gpu/mtl/GrMtlCaps.mm | 40 ++++++ src/gpu/mtl/GrMtlGpu.h | 4 + src/gpu/mtl/GrMtlGpu.mm | 134 ++++++++++++++++++ .../mac/CreatePlatformGLTestContext_mac.cpp | 29 +++- tools/gpu/mtl/MtlTestContext.mm | 18 +++ 6 files changed, 223 insertions(+), 3 deletions(-) diff --git a/src/gpu/mtl/GrMtlCaps.h b/src/gpu/mtl/GrMtlCaps.h index f09976a94f..347328a19b 100644 --- a/src/gpu/mtl/GrMtlCaps.h +++ b/src/gpu/mtl/GrMtlCaps.h @@ -96,6 +96,7 @@ public: #if GR_TEST_UTILS std::vector getTestingCombinations() const override; #endif + void onDumpJSON(SkJSONWriter*) const override; private: void initFeatureSet(MTLFeatureSet featureSet); diff --git a/src/gpu/mtl/GrMtlCaps.mm b/src/gpu/mtl/GrMtlCaps.mm index 59edf6a3c3..99a3ff2256 100644 --- a/src/gpu/mtl/GrMtlCaps.mm +++ b/src/gpu/mtl/GrMtlCaps.mm @@ -1104,3 +1104,43 @@ std::vector GrMtlCaps::getTestingCombina return combos; } #endif + +#ifdef SK_ENABLE_DUMP_GPU +#include "src/utils/SkJSONWriter.h" +void GrMtlCaps::onDumpJSON(SkJSONWriter* writer) const { + + // We are called by the base class, which has already called beginObject(). We choose to nest + // all of our caps information in a named sub-object. + writer->beginObject("Metal caps"); + + writer->beginObject("Preferred Stencil Format"); + writer->appendS32("stencil bits", fPreferredStencilFormat.fStencilBits); + writer->appendS32("total bits", fPreferredStencilFormat.fTotalBits); + writer->endObject(); + + switch (fPlatform) { + case Platform::kMac: + writer->appendString("Platform", "Mac"); + break; + case Platform::kIOS: + writer->appendString("Platform", "iOS"); + break; + default: + writer->appendString("Platform", "unknown"); + break; + } + + writer->appendS32("Family Group", fFamilyGroup); + writer->appendS32("Version", fVersion); + + writer->beginArray("Sample Counts"); + for (int v : fSampleCounts) { + writer->appendS32(nullptr, v); + } + writer->endArray(); + + writer->endObject(); +} +#else +void GrMtlCaps::onDumpJSON(SkJSONWriter* writer) const { } +#endif diff --git a/src/gpu/mtl/GrMtlGpu.h b/src/gpu/mtl/GrMtlGpu.h index 3e30f471d3..5f4e92e580 100644 --- a/src/gpu/mtl/GrMtlGpu.h +++ b/src/gpu/mtl/GrMtlGpu.h @@ -224,6 +224,10 @@ private: void testingOnly_endCapture() override; #endif +#ifdef SK_ENABLE_DUMP_GPU + void onDumpJSON(SkJSONWriter*) const override; +#endif + sk_sp fMtlCaps; id fDevice; diff --git a/src/gpu/mtl/GrMtlGpu.mm b/src/gpu/mtl/GrMtlGpu.mm index 29453a2015..cedd00db6f 100644 --- a/src/gpu/mtl/GrMtlGpu.mm +++ b/src/gpu/mtl/GrMtlGpu.mm @@ -1421,3 +1421,137 @@ void GrMtlGpu::testingOnly_endCapture() { } } #endif + +#ifdef SK_ENABLE_DUMP_GPU +#include "src/utils/SkJSONWriter.h" +void GrMtlGpu::onDumpJSON(SkJSONWriter* writer) const { + // We are called by the base class, which has already called beginObject(). We choose to nest + // all of our caps information in a named sub-object. + writer->beginObject("Metal GPU"); + + writer->beginObject("Device"); + writer->appendString("name", fDevice.name.UTF8String); +#ifdef SK_BUILD_FOR_MAC + if (@available(macOS 10.11, *)) { + writer->appendBool("isHeadless", fDevice.isHeadless); + writer->appendBool("isLowPower", fDevice.isLowPower); + } + if (@available(macOS 10.13, *)) { + writer->appendBool("isRemovable", fDevice.isRemovable); + } +#endif + if (@available(macOS 10.13, iOS 11.0, *)) { + writer->appendU64("registryID", fDevice.registryID); + } +#ifdef SK_BUILD_FOR_MAC + if (@available(macOS 10.15, *)) { + switch (fDevice.location) { + case MTLDeviceLocationBuiltIn: + writer->appendString("location", "builtIn"); + break; + case MTLDeviceLocationSlot: + writer->appendString("location", "slot"); + break; + case MTLDeviceLocationExternal: + writer->appendString("location", "external"); + break; + case MTLDeviceLocationUnspecified: + writer->appendString("location", "unspecified"); + break; + default: + writer->appendString("location", "unknown"); + break; + } + writer->appendU64("locationNumber", fDevice.locationNumber); + writer->appendU64("maxTransferRate", fDevice.maxTransferRate); + } +#endif // SK_BUILD_FOR_MAC + if (@available(macOS 10.15, iOS 13.0, *)) { + writer->appendBool("hasUnifiedMemory", fDevice.hasUnifiedMemory); + } +#ifdef SK_BUILD_FOR_MAC + if (@available(macOS 10.15, *)) { + writer->appendU64("peerGroupID", fDevice.peerGroupID); + writer->appendU32("peerCount", fDevice.peerCount); + writer->appendU32("peerIndex", fDevice.peerIndex); + } + if (@available(macOS 10.12, *)) { + writer->appendU64("recommendedMaxWorkingSetSize", fDevice.recommendedMaxWorkingSetSize); + } +#endif // SK_BUILD_FOR_MAC + if (@available(macOS 10.13, iOS 11.0, *)) { + writer->appendU64("currentAllocatedSize", fDevice.currentAllocatedSize); + writer->appendU64("maxThreadgroupMemoryLength", fDevice.maxThreadgroupMemoryLength); + } + + writer->beginObject("maxThreadsPerThreadgroup"); + writer->appendU64("width", fDevice.maxThreadsPerThreadgroup.width); + writer->appendU64("height", fDevice.maxThreadsPerThreadgroup.height); + writer->appendU64("depth", fDevice.maxThreadsPerThreadgroup.depth); + writer->endObject(); + + if (@available(macOS 10.13, iOS 11.0, *)) { + writer->appendBool("areProgrammableSamplePositionsSupported", + fDevice.areProgrammableSamplePositionsSupported); + writer->appendBool("areRasterOrderGroupsSupported", + fDevice.areRasterOrderGroupsSupported); + } +#ifdef SK_BUILD_FOR_MAC + if (@available(macOS 10.11, *)) { + writer->appendBool("isDepth24Stencil8PixelFormatSupported", + fDevice.isDepth24Stencil8PixelFormatSupported); + + } + if (@available(macOS 10.15, *)) { + writer->appendBool("areBarycentricCoordsSupported", + fDevice.areBarycentricCoordsSupported); + writer->appendBool("supportsShaderBarycentricCoordinates", + fDevice.supportsShaderBarycentricCoordinates); + } +#endif // SK_BUILD_FOR_MAC + if (@available(macOS 10.14, iOS 12.0, *)) { + writer->appendU64("maxBufferLength", fDevice.maxBufferLength); + } + if (@available(macOS 10.13, iOS 11.0, *)) { + switch (fDevice.readWriteTextureSupport) { + case MTLReadWriteTextureTier1: + writer->appendString("readWriteTextureSupport", "tier1"); + break; + case MTLReadWriteTextureTier2: + writer->appendString("readWriteTextureSupport", "tier2"); + break; + case MTLReadWriteTextureTierNone: + writer->appendString("readWriteTextureSupport", "tierNone"); + break; + default: + writer->appendString("readWriteTextureSupport", "unknown"); + break; + } + switch (fDevice.argumentBuffersSupport) { + case MTLArgumentBuffersTier1: + writer->appendString("argumentBuffersSupport", "tier1"); + break; + case MTLArgumentBuffersTier2: + writer->appendString("argumentBuffersSupport", "tier2"); + break; + default: + writer->appendString("argumentBuffersSupport", "unknown"); + break; + } + } + if (@available(macOS 10.14, iOS 12.0, *)) { + writer->appendU64("maxArgumentBufferSamplerCount", fDevice.maxArgumentBufferSamplerCount); + } +#ifdef SK_BUILD_FOR_IOS + if (@available(iOS 13.0, *)) { + writer->appendU64("sparseTileSizeInBytes", fDevice.sparseTileSizeInBytes); + } +#endif + writer->endObject(); + + writer->appendString("queue", fQueue.label.UTF8String); + writer->appendBool("disconnected", fDisconnected); + + writer->endObject(); +} +#endif diff --git a/tools/gpu/gl/mac/CreatePlatformGLTestContext_mac.cpp b/tools/gpu/gl/mac/CreatePlatformGLTestContext_mac.cpp index c289e39b77..e5ff2fa448 100644 --- a/tools/gpu/gl/mac/CreatePlatformGLTestContext_mac.cpp +++ b/tools/gpu/gl/mac/CreatePlatformGLTestContext_mac.cpp @@ -40,18 +40,41 @@ private: MacGLTestContext::MacGLTestContext(MacGLTestContext* shareContext) : fContext(nullptr) , fGLLibrary(RTLD_DEFAULT) { + // We first try to request a Radeon eGPU if one is available. + // This will be a Radeon HD7000 and up, which includes all eGPU configs. + // If that fails, we try again with only the base parameters. CGLPixelFormatAttribute attributes[] = { + // base parameters #if MAC_OS_X_VERSION_10_7 - kCGLPFAOpenGLProfile, (CGLPixelFormatAttribute) kCGLOGLPVersion_3_2_Core, + kCGLPFAOpenGLProfile, + (CGLPixelFormatAttribute) kCGLOGLPVersion_3_2_Core, #endif kCGLPFADoubleBuffer, - (CGLPixelFormatAttribute)0 + +#if MAC_OS_X_VERSION_10_8 + // eGPU parameters + kCGLPFAAllowOfflineRenderers, // Enables e-GPU. + kCGLPFANoRecovery, // Disallows software rendering. + kCGLPFARendererID, (CGLPixelFormatAttribute)kCGLRendererATIRadeonX4000ID, // Select Radeon +#endif + (CGLPixelFormatAttribute)NULL }; +#if MAC_OS_X_VERSION_10_8 + static const int kFirstEGPUParameter = 3; + SkASSERT(kCGLPFAAllowOfflineRenderers == attributes[kFirstEGPUParameter]); +#endif + CGLPixelFormatObj pixFormat; GLint npix; - CGLChoosePixelFormat(attributes, &pixFormat, &npix); +#if MAC_OS_X_VERSION_10_8 + if (nullptr == pixFormat) { + // Move the NULL-termination up to remove the eGPU parameters and try again + attributes[kFirstEGPUParameter] = (CGLPixelFormatAttribute)NULL; + CGLChoosePixelFormat(attributes, &pixFormat, &npix); + } +#endif if (nullptr == pixFormat) { SkDebugf("CGLChoosePixelFormat failed."); return; diff --git a/tools/gpu/mtl/MtlTestContext.mm b/tools/gpu/mtl/MtlTestContext.mm index b20a1f8dee..9a654cfe06 100644 --- a/tools/gpu/mtl/MtlTestContext.mm +++ b/tools/gpu/mtl/MtlTestContext.mm @@ -27,7 +27,25 @@ public: device = sharedContextImpl->device(); queue = sharedContextImpl->queue(); } else { +#ifdef SK_BUILD_FOR_MAC + NSArray>* availableDevices = MTLCopyAllDevices(); + // Choose the non-integrated CPU if available + for (id dev in availableDevices) { + if (!dev.isLowPower) { + device = dev; + break; + } + if (dev.isRemovable) { + device = dev; + break; + } + } + if (!device) { + device = MTLCreateSystemDefaultDevice(); + } +#else device = MTLCreateSystemDefaultDevice(); +#endif queue = [device newCommandQueue]; }