diff options
-rw-r--r-- | BUILD.gn | 3 | ||||
-rw-r--r-- | include/gpu/GrContext.h | 11 | ||||
-rw-r--r-- | src/gpu/GrContext.cpp | 23 | ||||
-rw-r--r-- | src/gpu/GrGpuFactory.cpp | 7 | ||||
-rw-r--r-- | src/gpu/mtl/GrMtlGpu.h | 24 | ||||
-rw-r--r-- | src/gpu/mtl/GrMtlGpu.mm | 29 | ||||
-rw-r--r-- | src/gpu/mtl/GrMtlTrampoline.h | 6 | ||||
-rw-r--r-- | src/gpu/mtl/GrMtlTrampoline.mm | 10 | ||||
-rw-r--r-- | tools/gpu/GrContextFactory.cpp | 18 | ||||
-rw-r--r-- | tools/gpu/TestContext.cpp | 6 | ||||
-rw-r--r-- | tools/gpu/TestContext.h | 8 | ||||
-rw-r--r-- | tools/gpu/gl/GLTestContext.h | 2 | ||||
-rw-r--r-- | tools/gpu/mock/MockTestContext.cpp | 1 | ||||
-rw-r--r-- | tools/gpu/mtl/MtlTestContext.h | 22 | ||||
-rw-r--r-- | tools/gpu/mtl/MtlTestContext.mm | 165 | ||||
-rw-r--r-- | tools/gpu/vk/VkTestContext.h | 2 |
16 files changed, 299 insertions, 38 deletions
@@ -994,6 +994,9 @@ if (skia_enable_tools) { libs += [ "vulkan" ] } } + if (skia_use_metal) { + sources += [ "tools/gpu/mtl/MtlTestContext.mm" ] + } } } diff --git a/include/gpu/GrContext.h b/include/gpu/GrContext.h index 64c1746078..c277ba7be8 100644 --- a/include/gpu/GrContext.h +++ b/include/gpu/GrContext.h @@ -52,6 +52,16 @@ public: static GrContext* Create(GrBackend, GrBackendContext, const GrContextOptions& options); static GrContext* Create(GrBackend, GrBackendContext); +#ifdef SK_METAL + /** + * Makes a GrContext which uses Metal as the backend. The device parameter is an MTLDevice + * and queue is an MTLCommandQueue which should be used by the backend. These objects must + * have a ref on them which can be transferred to Ganesh which will release the ref when the + * GrContext is destroyed. + */ + static sk_sp<GrContext> MakeMetal(void* device, void* queue, const GrContextOptions& options); +#endif + virtual ~GrContext(); sk_sp<GrContextThreadSafeProxy> threadSafeProxy(); @@ -328,6 +338,7 @@ private: GrContext(); // init must be called after the constructor. bool init(GrBackend, GrBackendContext, const GrContextOptions& options); + bool init(const GrContextOptions& options); /** * These functions create premul <-> unpremul effects. If the second argument is 'true', they diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp index 8cad6be20b..2f3c30d997 100644 --- a/src/gpu/GrContext.cpp +++ b/src/gpu/GrContext.cpp @@ -28,6 +28,10 @@ #include "effects/GrConfigConversionEffect.h" #include "text/GrTextBlobCache.h" +#ifdef SK_METAL +#include "mtl/GrMtlTrampoline.h" +#endif + #define ASSERT_OWNED_PROXY(P) \ SkASSERT(!(P) || !((P)->priv().peekTexture()) || (P)->priv().peekTexture()->getContext() == this) #define ASSERT_OWNED_PROXY_PRIV(P) \ @@ -61,6 +65,21 @@ GrContext* GrContext::Create(GrBackend backend, GrBackendContext backendContext, return context.release(); } +#ifdef SK_METAL +sk_sp<GrContext> GrContext::MakeMetal(void* device, void* queue, const GrContextOptions& options) { + sk_sp<GrContext> context(new GrContext); + context->fGpu = GrMtlTrampoline::CreateGpu(context.get(), options, device, queue); + if (!context->fGpu) { + return nullptr; + } + context->fBackend = kMetal_GrBackend; + if (!context->init(options)) { + return nullptr; + } + return context; +} +#endif + static int32_t gNextID = 1; static int32_t next_id() { int32_t id; @@ -89,7 +108,11 @@ bool GrContext::init(GrBackend backend, GrBackendContext backendContext, if (!fGpu) { return false; } + return this->init(options); +} +bool GrContext::init(const GrContextOptions& options) { + ASSERT_SINGLE_OWNER fCaps = SkRef(fGpu->caps()); fResourceCache = new GrResourceCache(fCaps, fUniqueID); fResourceProvider = new GrResourceProvider(fGpu, fResourceCache, &fSingleOwner); diff --git a/src/gpu/GrGpuFactory.cpp b/src/gpu/GrGpuFactory.cpp index 7cfec4a900..1fc19c144a 100644 --- a/src/gpu/GrGpuFactory.cpp +++ b/src/gpu/GrGpuFactory.cpp @@ -12,9 +12,6 @@ #ifdef SK_VULKAN #include "vk/GrVkGpu.h" #endif -#ifdef SK_METAL -#include "mtl/GrMtlTrampoline.h" -#endif GrGpu* GrGpu::Create(GrBackend backend, GrBackendContext backendContext, @@ -27,10 +24,6 @@ GrGpu* GrGpu::Create(GrBackend backend, case kVulkan_GrBackend: return GrVkGpu::Create(backendContext, options, context); #endif -#ifdef SK_METAL - case kMetal_GrBackend: - return GrMtlTrampoline::CreateGpu(backendContext, options, context); -#endif case kMock_GrBackend: return GrMockGpu::Create(backendContext, options, context); default: diff --git a/src/gpu/mtl/GrMtlGpu.h b/src/gpu/mtl/GrMtlGpu.h index 7ec9907675..b63f9080be 100644 --- a/src/gpu/mtl/GrMtlGpu.h +++ b/src/gpu/mtl/GrMtlGpu.h @@ -16,11 +16,12 @@ #import <Metal/Metal.h> class GrSemaphore; +struct GrMtlBackendContext; class GrMtlGpu : public GrGpu { public: - static GrGpu* Create(GrBackendContext backendContext, const GrContextOptions& options, - GrContext* context); + static GrGpu* Create(GrContext* context, const GrContextOptions& options, + id<MTLDevice> device, id<MTLCommandQueue> queue); ~GrMtlGpu() override {} @@ -59,19 +60,8 @@ public: sk_sp<GrSemaphore> prepareTextureForCrossContextUsage(GrTexture*) override { return nullptr; } private: - GrMtlGpu(GrContext* context, const GrContextOptions& options) : INHERITED(context) { - id<MTLDevice> device = MTLCreateSystemDefaultDevice(); - - MTLTextureDescriptor* txDesc = [[MTLTextureDescriptor alloc] init]; - txDesc.textureType = MTLTextureType3D; - txDesc.height = 64; - txDesc.width = 64; - txDesc.depth = 64; - txDesc.pixelFormat = MTLPixelFormatBGRA8Unorm; - txDesc.arrayLength = 1; - txDesc.mipmapLevelCount = 1; - fTestHeaderTexture = [device newTextureWithDescriptor:txDesc]; - } + GrMtlGpu(GrContext* context, const GrContextOptions& options, + id<MTLDevice> device, id<MTLCommandQueue> queue); void onResetContext(uint32_t resetBits) override {} @@ -146,7 +136,9 @@ private: bool isTestingOnlyBackendTexture(GrBackendObject ) const override { return false; } void deleteTestingOnlyBackendTexture(GrBackendObject, bool abandonTexture) override {} - id<MTLTexture> fTestHeaderTexture; + id<MTLDevice> fDevice; + id<MTLCommandQueue> fQueue; + typedef GrGpu INHERITED; }; diff --git a/src/gpu/mtl/GrMtlGpu.mm b/src/gpu/mtl/GrMtlGpu.mm index 7d9339cf29..986bb8a6f7 100644 --- a/src/gpu/mtl/GrMtlGpu.mm +++ b/src/gpu/mtl/GrMtlGpu.mm @@ -11,8 +11,31 @@ #error This file must be compiled with Arc. Use -fobjc-arc flag #endif -GrGpu* GrMtlGpu::Create(GrBackendContext backendContext, const GrContextOptions& options, - GrContext* context) { - return nullptr; +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); } +GrMtlGpu::GrMtlGpu(GrContext* context, const GrContextOptions& options, + id<MTLDevice> device, id<MTLCommandQueue> queue) + : INHERITED(context) + , fDevice(device) + , fQueue(queue) { + MTLTextureDescriptor* txDesc = [[MTLTextureDescriptor alloc] init]; + txDesc.textureType = MTLTextureType3D; + txDesc.height = 64; + txDesc.width = 64; + txDesc.depth = 64; + txDesc.pixelFormat = MTLPixelFormatRGBA8Unorm; + txDesc.arrayLength = 1; + txDesc.mipmapLevelCount = 1; + id<MTLTexture> testTexture = [fDevice newTextureWithDescriptor:txDesc]; + // To get ride of unused var warning + int width = [testTexture width]; + SkDebugf("width: %d\n", width); + // Unused queue warning fix + SkDebugf("ptr to queue: %p\n", fQueue); +} diff --git a/src/gpu/mtl/GrMtlTrampoline.h b/src/gpu/mtl/GrMtlTrampoline.h index acce98cd1f..531a4ce00c 100644 --- a/src/gpu/mtl/GrMtlTrampoline.h +++ b/src/gpu/mtl/GrMtlTrampoline.h @@ -20,8 +20,10 @@ struct GrContextOptions; */ class GrMtlTrampoline { public: - static GrGpu* CreateGpu(GrBackendContext backendContext, const GrContextOptions& options, - GrContext* context); + static GrGpu* CreateGpu(GrContext* context, + const GrContextOptions& options, + void* device, + void* queue); }; #endif diff --git a/src/gpu/mtl/GrMtlTrampoline.mm b/src/gpu/mtl/GrMtlTrampoline.mm index ea91ebb827..0f112e4da5 100644 --- a/src/gpu/mtl/GrMtlTrampoline.mm +++ b/src/gpu/mtl/GrMtlTrampoline.mm @@ -9,9 +9,13 @@ #include "GrMtlGpu.h" -GrGpu* GrMtlTrampoline::CreateGpu(GrBackendContext backendContext, +GrGpu* GrMtlTrampoline::CreateGpu(GrContext* context, const GrContextOptions& options, - GrContext* context) { - return GrMtlGpu::Create(backendContext, options, context); + void* device, + void* queue) { + return GrMtlGpu::Create(context, + options, + (__bridge_transfer id<MTLDevice>)device, + (__bridge_transfer id<MTLCommandQueue>)queue); } diff --git a/tools/gpu/GrContextFactory.cpp b/tools/gpu/GrContextFactory.cpp index d614b0643e..0686b79902 100644 --- a/tools/gpu/GrContextFactory.cpp +++ b/tools/gpu/GrContextFactory.cpp @@ -20,6 +20,9 @@ #ifdef SK_VULKAN #include "vk/VkTestContext.h" #endif +#ifdef SK_METAL +#include "mtl/MtlTestContext.h" +#endif #include "gl/null/NullGLTestContext.h" #include "gl/GrGLGpu.h" #include "mock/MockTestContext.h" @@ -221,6 +224,16 @@ ContextInfo GrContextFactory::getContextInfoInternal(ContextType type, ContextOv break; } #endif +#ifdef SK_METAL + case kMetal_GrBackend: { + SkASSERT(!masterContext); + testCtx.reset(CreatePlatformMtlTestContext(nullptr)); + if (!testCtx) { + return ContextInfo(); + } + break; + } +#endif case kMock_GrBackend: { TestContext* sharedContext = masterContext ? masterContext->fTestContext : nullptr; SkASSERT(kMock_ContextType == type); @@ -252,7 +265,10 @@ ContextInfo GrContextFactory::getContextInfoInternal(ContextType type, ContextOv if (ContextOverrides::kAvoidStencilBuffers & overrides) { grOptions.fAvoidStencilBuffers = true; } - sk_sp<GrContext> grCtx(GrContext::Create(backend, backendContext, grOptions)); + sk_sp<GrContext> grCtx = testCtx->makeGrContext(grOptions); + if (!grCtx.get() && kMetal_GrBackend != backend) { + grCtx.reset(GrContext::Create(backend, backendContext, grOptions)); + } if (!grCtx.get()) { return ContextInfo(); } diff --git a/tools/gpu/TestContext.cpp b/tools/gpu/TestContext.cpp index 90aba43880..c80c4ea4df 100644 --- a/tools/gpu/TestContext.cpp +++ b/tools/gpu/TestContext.cpp @@ -10,6 +10,8 @@ #include "GpuTimer.h" +#include "GrContext.h" + namespace sk_gpu_test { TestContext::TestContext() : fFenceSync(nullptr) @@ -29,6 +31,10 @@ TestContext::~TestContext() { SkASSERT(!fGpuTimer); } +sk_sp<GrContext> TestContext::makeGrContext(const GrContextOptions&) { + return nullptr; +} + void TestContext::makeCurrent() const { this->onPlatformMakeCurrent(); } void TestContext::swapBuffers() { this->onPlatformSwapBuffers(); } diff --git a/tools/gpu/TestContext.h b/tools/gpu/TestContext.h index ecb61e3b2a..84794f3c34 100644 --- a/tools/gpu/TestContext.h +++ b/tools/gpu/TestContext.h @@ -11,8 +11,12 @@ #include "FenceSync.h" #include "GrTypes.h" +#include "SkRefCnt.h" #include "../private/SkTemplates.h" +class GrContext; +struct GrContextOptions; + namespace sk_gpu_test { class GpuTimer; @@ -25,8 +29,6 @@ class TestContext : public SkNoncopyable { public: virtual ~TestContext(); - virtual bool isValid() const = 0; - bool fenceSyncSupport() const { return fFenceSync != nullptr; } FenceSync* fenceSync() { SkASSERT(fFenceSync); return fFenceSync.get(); } @@ -46,6 +48,8 @@ public: virtual GrBackend backend() = 0; virtual GrBackendContext backendContext() = 0; + virtual sk_sp<GrContext> makeGrContext(const GrContextOptions&); + /** Swaps front and back buffer (if the context has such buffers) */ void swapBuffers(); diff --git a/tools/gpu/gl/GLTestContext.h b/tools/gpu/gl/GLTestContext.h index 9bd10395f7..f5afa31a7f 100644 --- a/tools/gpu/gl/GLTestContext.h +++ b/tools/gpu/gl/GLTestContext.h @@ -25,7 +25,7 @@ public: return reinterpret_cast<GrBackendContext>(fGL.get()); } - bool isValid() const override { return SkToBool(this->gl()); } + bool isValid() const { return SkToBool(this->gl()); } const GrGLInterface *gl() const { return fGL.get(); } diff --git a/tools/gpu/mock/MockTestContext.cpp b/tools/gpu/mock/MockTestContext.cpp index c47fff5de3..56cd68cb59 100644 --- a/tools/gpu/mock/MockTestContext.cpp +++ b/tools/gpu/mock/MockTestContext.cpp @@ -21,7 +21,6 @@ public: virtual GrBackendContext backendContext() override { return reinterpret_cast<GrBackendContext>(nullptr); } - bool isValid() const override { return true; } void testAbandon() override {} void submit() override {} void finish() override {} diff --git a/tools/gpu/mtl/MtlTestContext.h b/tools/gpu/mtl/MtlTestContext.h new file mode 100644 index 0000000000..f703238c41 --- /dev/null +++ b/tools/gpu/mtl/MtlTestContext.h @@ -0,0 +1,22 @@ +/* + * 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 MtlTestContext_h +#define MtlTestContext_h + +#include "TestContext.h" + +#ifdef SK_METAL + +namespace sk_gpu_test { +TestContext* CreatePlatformMtlTestContext(TestContext*); +} // namespace sk_gpu_test + +#endif + + +#endif /* MtlTestContext_h */ diff --git a/tools/gpu/mtl/MtlTestContext.mm b/tools/gpu/mtl/MtlTestContext.mm new file mode 100644 index 0000000000..4014e2ba70 --- /dev/null +++ b/tools/gpu/mtl/MtlTestContext.mm @@ -0,0 +1,165 @@ +/* + * 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 "MtlTestContext.h" + +#include "GrContext.h" +#include "GrContextOptions.h" + +#import <Metal/Metal.h> + +#ifdef SK_METAL + +namespace { +/** + * Implements sk_gpu_test::FenceSync for Metal. + */ + +// TODO +#if 0 +class MtlFenceSync : public sk_gpu_test::FenceSync { +public: + MtlFenceSync(sk_sp<const GrVkInterface> vk, VkDevice device, VkQueue queue, + uint32_t queueFamilyIndex) + : fVk(std::move(vk)) + , fDevice(device) + , fQueue(queue) { + SkDEBUGCODE(fUnfinishedSyncs = 0;) + VkCommandPoolCreateInfo createInfo; + createInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; + createInfo.pNext = nullptr; + createInfo.flags = 0; + createInfo.queueFamilyIndex = queueFamilyIndex; + GR_VK_CALL_ERRCHECK(fVk, CreateCommandPool(fDevice, &createInfo, nullptr, &fCommandPool)); + + VkCommandBufferAllocateInfo allocateInfo; + allocateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + allocateInfo.pNext = nullptr; + allocateInfo.commandBufferCount = 1; + allocateInfo.commandPool = fCommandPool; + allocateInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + GR_VK_CALL_ERRCHECK(fVk, AllocateCommandBuffers(fDevice, &allocateInfo, &fCommandBuffer)); + + VkCommandBufferBeginInfo beginInfo; + beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + beginInfo.pNext = nullptr; + beginInfo.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT; + beginInfo.pInheritanceInfo = nullptr; + GR_VK_CALL_ERRCHECK(fVk, BeginCommandBuffer(fCommandBuffer, &beginInfo)); + GR_VK_CALL_ERRCHECK(fVk, EndCommandBuffer(fCommandBuffer)); + } + + ~VkFenceSync() override { + SkASSERT(!fUnfinishedSyncs); + // If the above assertion is true then the command buffer should not be in flight. + GR_VK_CALL(fVk, FreeCommandBuffers(fDevice, fCommandPool, 1, &fCommandBuffer)); + GR_VK_CALL(fVk, DestroyCommandPool(fDevice, fCommandPool, nullptr)); + } + + sk_gpu_test::PlatformFence SK_WARN_UNUSED_RESULT insertFence() const override { + VkFence fence; + VkFenceCreateInfo info; + info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; + info.pNext = nullptr; + info.flags = 0; + GR_VK_CALL_ERRCHECK(fVk, CreateFence(fDevice, &info, nullptr, &fence)); + VkSubmitInfo submitInfo; + submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submitInfo.pNext = nullptr; + submitInfo.waitSemaphoreCount = 0; + submitInfo.pWaitSemaphores = nullptr; + submitInfo.pWaitDstStageMask = nullptr; + submitInfo.commandBufferCount = 1; + submitInfo.pCommandBuffers = &fCommandBuffer; + submitInfo.signalSemaphoreCount = 0; + submitInfo.pSignalSemaphores = nullptr; + GR_VK_CALL_ERRCHECK(fVk, QueueSubmit(fQueue, 1, &submitInfo, fence)); + SkDEBUGCODE(++fUnfinishedSyncs;) + return (sk_gpu_test::PlatformFence)fence; + } + + bool waitFence(sk_gpu_test::PlatformFence opaqueFence) const override { + VkFence fence = (VkFence)opaqueFence; + static constexpr uint64_t kForever = ~((uint64_t)0); + auto result = GR_VK_CALL(fVk, WaitForFences(fDevice, 1, &fence, true, kForever)); + return result != VK_TIMEOUT; + } + + void deleteFence(sk_gpu_test::PlatformFence opaqueFence) const override { + VkFence fence = (VkFence)opaqueFence; + GR_VK_CALL(fVk, DestroyFence(fDevice, fence, nullptr)); + SkDEBUGCODE(--fUnfinishedSyncs;) + } + +private: + sk_sp<const GrVkInterface> fVk; + VkDevice fDevice; + VkQueue fQueue; + VkCommandPool fCommandPool; + VkCommandBuffer fCommandBuffer; + SkDEBUGCODE(mutable int fUnfinishedSyncs;) + typedef sk_gpu_test::FenceSync INHERITED; +}; + +GR_STATIC_ASSERT(sizeof(VkFence) <= sizeof(sk_gpu_test::PlatformFence)); +#endif + +class MtlTestContext : public sk_gpu_test::TestContext { +public: + static MtlTestContext* Create(TestContext* sharedContext) { + SkASSERT(!sharedContext); + id<MTLDevice> device = MTLCreateSystemDefaultDevice(); + id<MTLCommandQueue> queue = [device newCommandQueue]; + + return new MtlTestContext(device, queue); + } + + ~MtlTestContext() override { this->teardown(); } + + GrBackend backend() override { return kMetal_GrBackend; } + + GrBackendContext backendContext() override { return 0; } + + void testAbandon() override {} + + // There is really nothing to here since we don't own any unqueued command buffers here. + void submit() override {} + + void finish() override {} + + sk_sp<GrContext> makeGrContext(const GrContextOptions& options) override { + return GrContext::MakeMetal((__bridge_retained void*)fDevice, + (__bridge_retained void*)fQueue, + options); + } + +private: + MtlTestContext(id<MTLDevice> device, id<MTLCommandQueue> queue) + : fDevice(device), fQueue(queue) { + fFenceSync.reset(nullptr); + } + + void onPlatformMakeCurrent() const override {} + void onPlatformSwapBuffers() const override {} + + id<MTLDevice> fDevice; + id<MTLCommandQueue> fQueue; + + typedef sk_gpu_test::TestContext INHERITED; +}; + +} // anonymous namespace + +namespace sk_gpu_test { + +TestContext* CreatePlatformMtlTestContext(TestContext* sharedContext) { + return MtlTestContext::Create(sharedContext); +} +} // namespace sk_gpu_test + + +#endif diff --git a/tools/gpu/vk/VkTestContext.h b/tools/gpu/vk/VkTestContext.h index 85acb0e716..5090f556b4 100644 --- a/tools/gpu/vk/VkTestContext.h +++ b/tools/gpu/vk/VkTestContext.h @@ -26,8 +26,6 @@ public: return fVk; } - bool isValid() const override { return NULL != this->vk(); } - const GrVkInterface* vk() const { return fVk->fInterface.get(); } protected: |