text: // Copyright 2018 The Dawn Authors
  //
  // Licensed under the Apache License, Version 2.0 (the "License");
  // you may not use this file except in compliance with the License.
  // You may obtain a copy of the License at
  //
  //     http://www.apache.org/licenses/LICENSE-2.0
  //
  // Unless required by applicable law or agreed to in writing, software
  // distributed under the License is distributed on an "AS IS" BASIS,
  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  // See the License for the specific language governing permissions and
  // limitations under the License.
  
  #ifndef DAWNNATIVE_METAL_DEVICEMTL_H_
  #define DAWNNATIVE_METAL_DEVICEMTL_H_
  
  #include "dawn_native/dawn_platform.h"
  
  #include "dawn_native/Commands.h"
  #include "dawn_native/Device.h"
  #include "dawn_native/metal/CommandRecordingContext.h"
  #include "dawn_native/metal/Forward.h"
  
  #import <IOSurface/IOSurfaceRef.h>
  #import <Metal/Metal.h>
  #import <QuartzCore/QuartzCore.h>
  
  #include <atomic>
  #include <memory>
  #include <mutex>
  
  namespace dawn_native { namespace metal {
  
      namespace {
          struct KalmanInfo;
      }
  
      class Device : public DeviceBase {
        public:
          static ResultOrError<Device*> Create(AdapterBase* adapter,
                                               NSPRef<id<MTLDevice>> mtlDevice,
                                               const DeviceDescriptor* descriptor);
          ~Device() override;
  
          MaybeError Initialize();
  
          MaybeError TickImpl() override;
  
          id<MTLDevice> GetMTLDevice();
          id<MTLCommandQueue> GetMTLQueue();
  
          CommandRecordingContext* GetPendingCommandContext();
          MaybeError SubmitPendingCommandBuffer();
  
          Ref<Texture> CreateTextureWrappingIOSurface(const ExternalImageDescriptor* descriptor,
                                                      IOSurfaceRef ioSurface,
                                                      uint32_t plane);
          void WaitForCommandsToBeScheduled();
  
          ResultOrError<std::unique_ptr<StagingBufferBase>> CreateStagingBuffer(size_t size) override;
          MaybeError CopyFromStagingToBuffer(StagingBufferBase* source,
                                             uint64_t sourceOffset,
                                             BufferBase* destination,
                                             uint64_t destinationOffset,
                                             uint64_t size) override;
          MaybeError CopyFromStagingToTexture(const StagingBufferBase* source,
                                              const TextureDataLayout& dataLayout,
                                              TextureCopy* dst,
                                              const Extent3D& copySizePixels) override;
  
          uint32_t GetOptimalBytesPerRowAlignment() const override;
          uint64_t GetOptimalBufferToTextureCopyOffsetAlignment() const override;
  
          float GetTimestampPeriodInNS() const override;
  
        private:
          Device(AdapterBase* adapter,
                 NSPRef<id<MTLDevice>> mtlDevice,
                 const DeviceDescriptor* descriptor);
  
          ResultOrError<Ref<BindGroupBase>> CreateBindGroupImpl(
              const BindGroupDescriptor* descriptor) override;
          ResultOrError<Ref<BindGroupLayoutBase>> CreateBindGroupLayoutImpl(
              const BindGroupLayoutDescriptor* descriptor) override;
          ResultOrError<Ref<BufferBase>> CreateBufferImpl(
              const BufferDescriptor* descriptor) override;
          ResultOrError<Ref<CommandBufferBase>> CreateCommandBuffer(
              CommandEncoder* encoder,
              const CommandBufferDescriptor* descriptor) override;
          ResultOrError<Ref<ComputePipelineBase>> CreateComputePipelineImpl(
              const ComputePipelineDescriptor* descriptor) override;
          ResultOrError<Ref<PipelineLayoutBase>> CreatePipelineLayoutImpl(
              const PipelineLayoutDescriptor* descriptor) override;
          ResultOrError<Ref<QuerySetBase>> CreateQuerySetImpl(
              const QuerySetDescriptor* descriptor) override;
          ResultOrError<Ref<RenderPipelineBase>> CreateRenderPipelineImpl(
              const RenderPipelineDescriptor* descriptor) override;
          ResultOrError<Ref<SamplerBase>> CreateSamplerImpl(
              const SamplerDescriptor* descriptor) override;
          ResultOrError<Ref<ShaderModuleBase>> CreateShaderModuleImpl(
              const ShaderModuleDescriptor* descriptor,
              ShaderModuleParseResult* parseResult) override;
          ResultOrError<Ref<SwapChainBase>> CreateSwapChainImpl(
              const SwapChainDescriptor* descriptor) override;
          ResultOrError<Ref<NewSwapChainBase>> CreateSwapChainImpl(
              Surface* surface,
              NewSwapChainBase* previousSwapChain,
              const SwapChainDescriptor* descriptor) override;
          ResultOrError<Ref<TextureBase>> CreateTextureImpl(
              const TextureDescriptor* descriptor) override;
          ResultOrError<Ref<TextureViewBase>> CreateTextureViewImpl(
              TextureBase* texture,
              const TextureViewDescriptor* descriptor) override;
          void CreateComputePipelineAsyncImpl(const ComputePipelineDescriptor* descriptor,
                                              size_t blueprintHash,
                                              WGPUCreateComputePipelineAsyncCallback callback,
                                              void* userdata) override;
  
          void InitTogglesFromDriver();
          void ShutDownImpl() override;
          MaybeError WaitForIdleForDestruction() override;
          ResultOrError<ExecutionSerial> CheckAndUpdateCompletedSerials() override;
  
          NSPRef<id<MTLDevice>> mMtlDevice;
          NSPRef<id<MTLCommandQueue>> mCommandQueue;
  
          CommandRecordingContext mCommandContext;
  
          // The completed serial is updated in a Metal completion handler that can be fired on a
          // different thread, so it needs to be atomic.
          std::atomic<uint64_t> mCompletedSerial;
  
          // mLastSubmittedCommands will be accessed in a Metal schedule handler that can be fired on
          // a different thread so we guard access to it with a mutex.
          std::mutex mLastSubmittedCommandsMutex;
          NSPRef<id<MTLCommandBuffer>> mLastSubmittedCommands;
  
          // The current estimation of timestamp period
          float mTimestampPeriod = 1.0f;
          // The base of CPU timestamp and GPU timestamp to measure the linear regression between GPU
          // and CPU timestamps.
          MTLTimestamp mCpuTimestamp API_AVAILABLE(macos(10.15), ios(14.0)) = 0;
          MTLTimestamp mGpuTimestamp API_AVAILABLE(macos(10.15), ios(14.0)) = 0;
          // The parameters for kalman filter
          std::unique_ptr<KalmanInfo> mKalmanInfo;
      };
  
  }}  // namespace dawn_native::metal
  
  #endif  // DAWNNATIVE_METAL_DEVICEMTL_H_
  