RendererMTL.mm 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. // Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
  2. // SPDX-FileCopyrightText: 2025 Jorrit Rouwe
  3. // SPDX-License-Identifier: MIT
  4. #include <TestFramework.h>
  5. #include <Renderer/MTL/RendererMTL.h>
  6. #include <Renderer/MTL/RenderPrimitiveMTL.h>
  7. #include <Renderer/MTL/RenderInstancesMTL.h>
  8. #include <Renderer/MTL/PipelineStateMTL.h>
  9. #include <Renderer/MTL/VertexShaderMTL.h>
  10. #include <Renderer/MTL/PixelShaderMTL.h>
  11. #include <Renderer/MTL/TextureMTL.h>
  12. #include <Renderer/MTL/FatalErrorIfFailedMTL.h>
  13. #include <Window/ApplicationWindowMacOS.h>
  14. #include <Utils/Log.h>
  15. #include <Utils/AssetStream.h>
  16. #include <Jolt/Core/Profiler.h>
  17. RendererMTL::~RendererMTL()
  18. {
  19. [mCommandQueue release];
  20. [mShadowRenderPass release];
  21. [mShaderLibrary release];
  22. }
  23. void RendererMTL::Initialize(ApplicationWindow *inWindow)
  24. {
  25. Renderer::Initialize(inWindow);
  26. mView = static_cast<ApplicationWindowMacOS *>(inWindow)->GetMetalView();
  27. id<MTLDevice> device = GetDevice();
  28. // Load the shader library containing all shaders for the test framework
  29. NSError *error = nullptr;
  30. NSURL *url = [NSURL URLWithString: [NSString stringWithCString: (AssetStream::sGetAssetsBasePath() + "Shaders/MTL/Shaders.metallib").c_str() encoding: NSUTF8StringEncoding]];
  31. mShaderLibrary = [device newLibraryWithURL: url error: &error];
  32. FatalErrorIfFailed(error);
  33. // Create depth only texture (no color buffer, as seen from light)
  34. mShadowMap = new TextureMTL(this, cShadowMapSize, cShadowMapSize);
  35. // Create render pass descriptor for shadow pass
  36. mShadowRenderPass = [[MTLRenderPassDescriptor alloc] init];
  37. mShadowRenderPass.depthAttachment.texture = mShadowMap->GetTexture();
  38. mShadowRenderPass.depthAttachment.loadAction = MTLLoadActionClear;
  39. mShadowRenderPass.depthAttachment.storeAction = MTLStoreActionStore;
  40. mShadowRenderPass.depthAttachment.clearDepth = 0.0f;
  41. // Create the command queue
  42. mCommandQueue = [device newCommandQueue];
  43. }
  44. void RendererMTL::BeginFrame(const CameraState &inCamera, float inWorldScale)
  45. {
  46. JPH_PROFILE_FUNCTION();
  47. Renderer::BeginFrame(inCamera, inWorldScale);
  48. // Update frame index
  49. mFrameIndex = (mFrameIndex + 1) % cFrameCount;
  50. // Create a new command buffer
  51. mCommandBuffer = [mCommandQueue commandBuffer];
  52. // Create shadow render encoder
  53. mRenderEncoder = [mCommandBuffer renderCommandEncoderWithDescriptor: mShadowRenderPass];
  54. // Set viewport to size of shadow map
  55. [mRenderEncoder setViewport: (MTLViewport){ 0.0, 0.0, double(cShadowMapSize), double(cShadowMapSize), 0.0, 1.0 }];
  56. // Set pixel shader constants
  57. [mRenderEncoder setFragmentBytes: &mPSBuffer length: sizeof(mPSBuffer) atIndex: 0];
  58. // Counter clockwise is default winding order
  59. [mRenderEncoder setFrontFacingWinding: MTLWindingCounterClockwise];
  60. // Start with projection mode
  61. SetProjectionMode();
  62. }
  63. void RendererMTL::EndShadowPass()
  64. {
  65. // Finish the shadow encoder
  66. [mRenderEncoder endEncoding];
  67. mRenderEncoder = nil;
  68. // Get the descriptor for the main window
  69. MTLRenderPassDescriptor *render_pass_descriptor = mView.currentRenderPassDescriptor;
  70. if (render_pass_descriptor == nullptr)
  71. return;
  72. // Create render encoder
  73. mRenderEncoder = [mCommandBuffer renderCommandEncoderWithDescriptor: render_pass_descriptor];
  74. // Set viewport
  75. [mRenderEncoder setViewport: (MTLViewport){ 0.0, 0.0, double(mWindow->GetWindowWidth()), double(mWindow->GetWindowHeight()), 0.0, 1.0 }];
  76. // Set pixel shader constants
  77. [mRenderEncoder setFragmentBytes: &mPSBuffer length: sizeof(mPSBuffer) atIndex: 0];
  78. // Counter clockwise is default winding order
  79. [mRenderEncoder setFrontFacingWinding: MTLWindingCounterClockwise];
  80. // Start with projection mode
  81. SetProjectionMode();
  82. }
  83. void RendererMTL::EndFrame()
  84. {
  85. JPH_PROFILE_FUNCTION();
  86. // Finish the encoder
  87. [mRenderEncoder endEncoding];
  88. mRenderEncoder = nil;
  89. // Schedule a present
  90. [mCommandBuffer presentDrawable: mView.currentDrawable];
  91. // Commit the command buffer
  92. [mCommandBuffer commit];
  93. Renderer::EndFrame();
  94. }
  95. void RendererMTL::SetProjectionMode()
  96. {
  97. JPH_ASSERT(mInFrame);
  98. [mRenderEncoder setVertexBytes: &mVSBuffer length: sizeof(mVSBuffer) atIndex: 2];
  99. }
  100. void RendererMTL::SetOrthoMode()
  101. {
  102. JPH_ASSERT(mInFrame);
  103. [mRenderEncoder setVertexBytes: &mVSBufferOrtho length: sizeof(mVSBufferOrtho) atIndex: 2];
  104. }
  105. Ref<Texture> RendererMTL::CreateTexture(const Surface *inSurface)
  106. {
  107. return new TextureMTL(this, inSurface);
  108. }
  109. Ref<VertexShader> RendererMTL::CreateVertexShader(const char *inName)
  110. {
  111. id<MTLFunction> function = [mShaderLibrary newFunctionWithName: [NSString stringWithCString: inName encoding: NSUTF8StringEncoding]];
  112. if (function == nil)
  113. FatalError("Vertex shader %s not found", inName);
  114. return new VertexShaderMTL(function);
  115. }
  116. Ref<PixelShader> RendererMTL::CreatePixelShader(const char *inName)
  117. {
  118. id<MTLFunction> function = [mShaderLibrary newFunctionWithName: [NSString stringWithCString: inName encoding: NSUTF8StringEncoding]];
  119. if (function == nil)
  120. FatalError("Pixel shader %s not found", inName);
  121. return new PixelShaderMTL(function);
  122. }
  123. unique_ptr<PipelineState> RendererMTL::CreatePipelineState(const VertexShader *inVertexShader, const PipelineState::EInputDescription *inInputDescription, uint inInputDescriptionCount, const PixelShader *inPixelShader, PipelineState::EDrawPass inDrawPass, PipelineState::EFillMode inFillMode, PipelineState::ETopology inTopology, PipelineState::EDepthTest inDepthTest, PipelineState::EBlendMode inBlendMode, PipelineState::ECullMode inCullMode)
  124. {
  125. return make_unique<PipelineStateMTL>(this, static_cast<const VertexShaderMTL *>(inVertexShader), inInputDescription, inInputDescriptionCount, static_cast<const PixelShaderMTL *>(inPixelShader), inDrawPass, inFillMode, inTopology, inDepthTest, inBlendMode, inCullMode);
  126. }
  127. RenderPrimitive *RendererMTL::CreateRenderPrimitive(PipelineState::ETopology inType)
  128. {
  129. return new RenderPrimitiveMTL(this, inType == PipelineState::ETopology::Line? MTLPrimitiveTypeLine : MTLPrimitiveTypeTriangle);
  130. }
  131. RenderInstances *RendererMTL::CreateRenderInstances()
  132. {
  133. return new RenderInstancesMTL(this);
  134. }
  135. #ifndef JPH_ENABLE_VULKAN
  136. Renderer *Renderer::sCreate()
  137. {
  138. return new RendererMTL;
  139. }
  140. #endif