MetalGraphicsDevice.mm 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. #include "pch.h"
  2. #include <third_party/libyuv/include/libyuv/convert.h>
  3. #include "GraphicsDevice/GraphicsUtility.h"
  4. #include "MetalDevice.h"
  5. #include "MetalGraphicsDevice.h"
  6. #include "MetalTexture2D.h"
  7. namespace unity
  8. {
  9. namespace webrtc
  10. {
  11. MetalGraphicsDevice::MetalGraphicsDevice(
  12. MetalDevice* device, UnityGfxRenderer renderer, ProfilerMarkerFactory* profiler)
  13. : IGraphicsDevice(renderer, profiler)
  14. , m_device(device)
  15. {
  16. }
  17. bool MetalGraphicsDevice::InitV()
  18. {
  19. m_queue = [m_device->Device() newCommandQueue];
  20. return true;
  21. }
  22. void MetalGraphicsDevice::ShutdownV() { }
  23. ITexture2D*
  24. MetalGraphicsDevice::CreateDefaultTextureV(uint32_t w, uint32_t h, UnityRenderingExtTextureFormat textureFormat)
  25. {
  26. id<MTLDevice> device = m_device->Device();
  27. MTLTextureDescriptor* textureDescriptor = [[MTLTextureDescriptor alloc] init];
  28. textureDescriptor.pixelFormat = ConvertFormat(textureFormat);
  29. textureDescriptor.width = w;
  30. textureDescriptor.height = h;
  31. id<MTLTexture> texture = [device newTextureWithDescriptor:textureDescriptor];
  32. return new MetalTexture2D(w, h, texture);
  33. }
  34. ITexture2D* MetalGraphicsDevice::CreateDefaultTextureFromNativeV(uint32_t w, uint32_t h, void* nativeTexturePtr)
  35. {
  36. id<MTLTexture> texture = (__bridge id<MTLTexture>)nativeTexturePtr;
  37. return new MetalTexture2D(w, h, texture);
  38. }
  39. bool MetalGraphicsDevice::CopyResourceV(ITexture2D* dest, ITexture2D* src)
  40. {
  41. id<MTLTexture> dstTexture = (__bridge id<MTLTexture>)dest->GetNativeTexturePtrV();
  42. id<MTLTexture> srcTexture = (__bridge id<MTLTexture>)src->GetNativeTexturePtrV();
  43. return CopyTexture(dstTexture, srcTexture);
  44. }
  45. bool MetalGraphicsDevice::CopyResourceFromNativeV(ITexture2D* dest, void* nativeTexturePtr)
  46. {
  47. if (nativeTexturePtr == nullptr)
  48. {
  49. return false;
  50. }
  51. id<MTLTexture> dstTexture = (__bridge id<MTLTexture>)dest->GetNativeTexturePtrV();
  52. id<MTLTexture> srcTexture = (__bridge id<MTLTexture>)nativeTexturePtr;
  53. return CopyTexture(dstTexture, srcTexture);
  54. }
  55. bool MetalGraphicsDevice::CopyTexture(id<MTLTexture> dest, id<MTLTexture> src)
  56. {
  57. RTC_DCHECK_NE(dest, src);
  58. RTC_DCHECK_EQ(src.pixelFormat, dest.pixelFormat);
  59. RTC_DCHECK_EQ(src.width, dest.width);
  60. RTC_DCHECK_EQ(src.height, dest.height);
  61. m_device->EndCurrentCommandEncoder();
  62. id<MTLCommandBuffer> commandBuffer = [m_queue commandBuffer];
  63. id<MTLBlitCommandEncoder> blit = [commandBuffer blitCommandEncoder];
  64. NSUInteger width = src.width;
  65. NSUInteger height = src.height;
  66. MTLSize inTxtSize = MTLSizeMake(width, height, 1);
  67. MTLOrigin inTxtOrigin = MTLOriginMake(0, 0, 0);
  68. MTLOrigin outTxtOrigin = MTLOriginMake(0, 0, 0);
  69. [blit copyFromTexture:src
  70. sourceSlice:0
  71. sourceLevel:0
  72. sourceOrigin:inTxtOrigin
  73. sourceSize:inTxtSize
  74. toTexture:dest
  75. destinationSlice:0
  76. destinationLevel:0
  77. destinationOrigin:outTxtOrigin];
  78. #if TARGET_OS_OSX
  79. // must be explicitly synchronized if the storageMode is Managed.
  80. if (dest.storageMode == MTLStorageModeManaged)
  81. [blit synchronizeResource:dest];
  82. #endif
  83. [blit endEncoding];
  84. // Commit the current command buffer and wait until the GPU process is completed.
  85. [commandBuffer commit];
  86. [commandBuffer waitUntilCompleted];
  87. return true;
  88. }
  89. //---------------------------------------------------------------------------------------------------------------------
  90. ITexture2D* MetalGraphicsDevice::CreateCPUReadTextureV(
  91. uint32_t width, uint32_t height, UnityRenderingExtTextureFormat textureFormat)
  92. {
  93. id<MTLDevice> device = m_device->Device();
  94. MTLTextureDescriptor* textureDescriptor = [[MTLTextureDescriptor alloc] init];
  95. textureDescriptor.pixelFormat = ConvertFormat(textureFormat);
  96. textureDescriptor.width = width;
  97. textureDescriptor.height = height;
  98. if (@available(macOS 10.14, iOS 12.0, *))
  99. {
  100. // This texture is a managed or shared resource.
  101. textureDescriptor.allowGPUOptimizedContents = false;
  102. }
  103. else
  104. {
  105. // Fallback on earlier versions
  106. }
  107. #if TARGET_OS_OSX
  108. textureDescriptor.storageMode = MTLStorageMode(MTLStorageModeManaged);
  109. #else
  110. textureDescriptor.storageMode = MTLStorageMode(MTLStorageModeShared);
  111. #endif
  112. id<MTLTexture> texture = [device newTextureWithDescriptor:textureDescriptor];
  113. return new MetalTexture2D(width, height, texture);
  114. }
  115. rtc::scoped_refptr<webrtc::I420Buffer> MetalGraphicsDevice::ConvertRGBToI420(ITexture2D* tex)
  116. {
  117. id<MTLTexture> source = (__bridge id<MTLTexture>)tex->GetNativeTexturePtrV();
  118. const uint32_t width = tex->GetWidth();
  119. const uint32_t height = tex->GetHeight();
  120. RTC_DCHECK(source);
  121. RTC_DCHECK_GT(width, 0);
  122. RTC_DCHECK_GT(height, 0);
  123. const uint32_t BYTES_PER_PIXEL = 4;
  124. const uint32_t bytesPerRow = width * BYTES_PER_PIXEL;
  125. const uint32_t bufferSize = bytesPerRow * height;
  126. std::vector<uint8_t> buffer;
  127. buffer.resize(bufferSize);
  128. [source getBytes:buffer.data()
  129. bytesPerRow:bytesPerRow
  130. fromRegion:MTLRegionMake2D(0, 0, width, height)
  131. mipmapLevel:0];
  132. rtc::scoped_refptr<webrtc::I420Buffer> i420_buffer = webrtc::I420Buffer::Create(
  133. static_cast<int32_t>(width), static_cast<int32_t>(height));
  134. libyuv::ARGBToI420(
  135. buffer.data(),
  136. static_cast<int32_t>(bytesPerRow),
  137. i420_buffer->MutableDataY(),
  138. i420_buffer->StrideY(),
  139. i420_buffer->MutableDataU(),
  140. i420_buffer->StrideU(),
  141. i420_buffer->MutableDataV(),
  142. i420_buffer->StrideV(),
  143. static_cast<int32_t>(width),
  144. static_cast<int32_t>(height));
  145. return i420_buffer;
  146. }
  147. MTLPixelFormat MetalGraphicsDevice::ConvertFormat(UnityRenderingExtTextureFormat format)
  148. {
  149. switch (format)
  150. {
  151. case kUnityRenderingExtFormatB8G8R8A8_SRGB:
  152. return MTLPixelFormatBGRA8Unorm_sRGB;
  153. case kUnityRenderingExtFormatB8G8R8A8_UNorm:
  154. return MTLPixelFormatBGRA8Unorm;
  155. case kUnityRenderingExtFormatR8G8B8A8_SRGB:
  156. return MTLPixelFormatRGBA8Unorm_sRGB;
  157. default:
  158. return MTLPixelFormatInvalid;
  159. }
  160. }
  161. } // end namespace webrtc
  162. } // end namespace unity