MetalWindowContext.mm 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. /*
  2. * Copyright 2019 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. #include "include/core/SkCanvas.h"
  8. #include "include/core/SkSurface.h"
  9. #include "include/gpu/GrBackendSurface.h"
  10. #include "include/gpu/GrContext.h"
  11. #include "include/gpu/mtl/GrMtlTypes.h"
  12. #include "src/core/SkMathPriv.h"
  13. #include "src/gpu/GrCaps.h"
  14. #include "src/gpu/GrContextPriv.h"
  15. #include "src/image/SkImage_Base.h"
  16. #include "tools/sk_app/MetalWindowContext.h"
  17. using sk_app::DisplayParams;
  18. using sk_app::MetalWindowContext;
  19. namespace sk_app {
  20. MetalWindowContext::MetalWindowContext(const DisplayParams& params)
  21. : WindowContext(params)
  22. , fValid(false) {
  23. fDisplayParams.fMSAASampleCount = GrNextPow2(fDisplayParams.fMSAASampleCount);
  24. }
  25. void MetalWindowContext::initializeContext() {
  26. SkASSERT(!fContext);
  27. fDevice = MTLCreateSystemDefaultDevice();
  28. fQueue = [fDevice newCommandQueue];
  29. if (fDisplayParams.fMSAASampleCount > 1) {
  30. if (![fDevice supportsTextureSampleCount:fDisplayParams.fMSAASampleCount]) {
  31. return;
  32. }
  33. }
  34. fSampleCount = fDisplayParams.fMSAASampleCount;
  35. fStencilBits = 8;
  36. fMetalLayer = [CAMetalLayer layer];
  37. fMetalLayer.device = fDevice;
  38. fMetalLayer.pixelFormat = MTLPixelFormatBGRA8Unorm;
  39. fValid = this->onInitializeContext();
  40. fContext = GrContext::MakeMetal((__bridge void*)fDevice, (__bridge void*)fQueue,
  41. fDisplayParams.fGrContextOptions);
  42. if (!fContext && fDisplayParams.fMSAASampleCount > 1) {
  43. fDisplayParams.fMSAASampleCount /= 2;
  44. this->initializeContext();
  45. return;
  46. }
  47. }
  48. void MetalWindowContext::destroyContext() {
  49. if (fContext) {
  50. // in case we have outstanding refs to this guy (lua?)
  51. fContext->abandonContext();
  52. fContext.reset();
  53. }
  54. this->onDestroyContext();
  55. fMetalLayer = nil;
  56. fValid = false;
  57. [fQueue release];
  58. [fDevice release];
  59. }
  60. sk_sp<SkSurface> MetalWindowContext::getBackbufferSurface() {
  61. sk_sp<SkSurface> surface;
  62. if (fContext) {
  63. // TODO: Apple recommends grabbing the drawable (which we're implicitly doing here)
  64. // for as little time as possible. I'm not sure it matters for our test apps, but
  65. // you can get better throughput by doing any offscreen renders, texture uploads, or
  66. // other non-dependant tasks first before grabbing the drawable.
  67. fCurrentDrawable = [fMetalLayer nextDrawable];
  68. GrMtlTextureInfo fbInfo;
  69. fbInfo.fTexture.retain((__bridge const void*)(fCurrentDrawable.texture));
  70. if (fSampleCount == 1) {
  71. GrBackendRenderTarget backendRT(fWidth,
  72. fHeight,
  73. fSampleCount,
  74. fbInfo);
  75. surface = SkSurface::MakeFromBackendRenderTarget(fContext.get(), backendRT,
  76. kTopLeft_GrSurfaceOrigin,
  77. kBGRA_8888_SkColorType,
  78. fDisplayParams.fColorSpace,
  79. &fDisplayParams.fSurfaceProps);
  80. } else {
  81. GrBackendTexture backendTexture(fWidth,
  82. fHeight,
  83. GrMipMapped::kNo,
  84. fbInfo);
  85. surface = SkSurface::MakeFromBackendTexture(
  86. fContext.get(), backendTexture, kTopLeft_GrSurfaceOrigin, fSampleCount,
  87. kBGRA_8888_SkColorType, fDisplayParams.fColorSpace,
  88. &fDisplayParams.fSurfaceProps);
  89. }
  90. }
  91. return surface;
  92. }
  93. void MetalWindowContext::swapBuffers() {
  94. id<MTLCommandBuffer> commandBuffer = [fQueue commandBuffer];
  95. commandBuffer.label = @"Present";
  96. [commandBuffer presentDrawable:fCurrentDrawable];
  97. [commandBuffer commit];
  98. fCurrentDrawable = nil;
  99. }
  100. void MetalWindowContext::setDisplayParams(const DisplayParams& params) {
  101. this->destroyContext();
  102. fDisplayParams = params;
  103. this->initializeContext();
  104. }
  105. } //namespace sk_app