1/* 2 * Copyright 2017 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8#include "tools/gpu/mtl/MtlTestContext.h" 9 10#include "include/gpu/GrContext.h" 11#include "include/gpu/GrContextOptions.h" 12 13#include "src/gpu/mtl/GrMtlUtil.h" 14 15#ifdef SK_METAL 16 17#import <Metal/Metal.h> 18 19namespace { 20/** 21 * Implements sk_gpu_test::FenceSync for Metal. 22 * 23 * Fences as MTLSharedEvents are not supported across all Metal platforms, so we do 24 * the next best thing and submit an empty MTLCommandBuffer and track when it's complete. 25 */ 26class MtlFenceSync : public sk_gpu_test::FenceSync { 27public: 28 MtlFenceSync(id<MTLCommandQueue> queue) 29 : fQueue(queue) { 30 SkDEBUGCODE(fUnfinishedSyncs = 0;) 31 } 32 33 ~MtlFenceSync() override { 34 SkASSERT(!fUnfinishedSyncs); 35 } 36 37 sk_gpu_test::PlatformFence SK_WARN_UNUSED_RESULT insertFence() const override { 38 id<MTLCommandBuffer> cmdBuffer = [fQueue commandBuffer]; 39 cmdBuffer.label = @"Fence"; 40 [cmdBuffer commit]; 41 42 SkDEBUGCODE(++fUnfinishedSyncs;) 43 44 void* cfCmdBuffer = (__bridge_retained void*)cmdBuffer; 45 return (sk_gpu_test::PlatformFence)cfCmdBuffer; 46 } 47 48 bool waitFence(sk_gpu_test::PlatformFence opaqueFence) const override { 49 void* cfCmdBuffer = (void*) opaqueFence; 50 id<MTLCommandBuffer> cmdBuffer = (__bridge id<MTLCommandBuffer>) cfCmdBuffer; 51 52 [cmdBuffer waitUntilCompleted]; 53 54 return (MTLCommandBufferStatusError != cmdBuffer.status); 55 } 56 57 void deleteFence(sk_gpu_test::PlatformFence opaqueFence) const override { 58 CFRelease((void*) opaqueFence); 59 SkDEBUGCODE(--fUnfinishedSyncs;) 60 } 61 62private: 63 id<MTLCommandQueue> fQueue; 64 SkDEBUGCODE(mutable int fUnfinishedSyncs;) 65 typedef sk_gpu_test::FenceSync INHERITED; 66}; 67 68GR_STATIC_ASSERT(sizeof(uint64_t) <= sizeof(sk_gpu_test::PlatformFence)); 69 70class MtlTestContextImpl : public sk_gpu_test::MtlTestContext { 71public: 72 static MtlTestContext* Create(MtlTestContext* sharedContext) { 73 id<MTLDevice> device; 74 id<MTLCommandQueue> queue; 75 if (sharedContext) { 76 MtlTestContextImpl* sharedContextImpl = (MtlTestContextImpl*) sharedContext; 77 device = sharedContextImpl->device(); 78 queue = sharedContextImpl->queue(); 79 } else { 80 device = MTLCreateSystemDefaultDevice(); 81 queue = [device newCommandQueue]; 82 } 83 84 return new MtlTestContextImpl(device, queue); 85 } 86 87 ~MtlTestContextImpl() override { this->teardown(); } 88 89 void testAbandon() override {} 90 91 // There is really nothing to do here since we don't own any unqueued command buffers here. 92 void submit() override {} 93 94 void finish() override {} 95 96 sk_sp<GrContext> makeGrContext(const GrContextOptions& options) override { 97 return GrContext::MakeMetal((__bridge void*)fDevice, 98 (__bridge void*)fQueue, 99 options); 100 } 101 102 id<MTLDevice> device() { return fDevice; } 103 id<MTLCommandQueue> queue() { return fQueue; } 104 105private: 106 MtlTestContextImpl(id<MTLDevice> device, id<MTLCommandQueue> queue) 107 : INHERITED(), fDevice(device), fQueue(queue) { 108 fFenceSync.reset(new MtlFenceSync(queue)); 109 } 110 111 void onPlatformMakeCurrent() const override {} 112 std::function<void()> onPlatformGetAutoContextRestore() const override { return nullptr; } 113 void onPlatformSwapBuffers() const override {} 114 115 id<MTLDevice> fDevice; 116 id<MTLCommandQueue> fQueue; 117 118 typedef sk_gpu_test::MtlTestContext INHERITED; 119}; 120 121} // anonymous namespace 122 123namespace sk_gpu_test { 124 125MtlTestContext* CreatePlatformMtlTestContext(MtlTestContext* sharedContext) { 126 return MtlTestContextImpl::Create(sharedContext); 127} 128 129} // namespace sk_gpu_test 130 131 132#endif 133