15
15
#include " Cafe/HW/Latte/Core/LatteShader.h"
16
16
#include " Cafe/HW/Latte/Core/LatteIndices.h"
17
17
#include " Cemu/Logging/CemuDebugLogging.h"
18
+ #include " Common/precompiled.h"
18
19
#include " Metal/MTLPixelFormat.hpp"
19
20
#include " gui/guiWrapper.h"
20
21
22
+ #define COMMIT_TRESHOLD 256
23
+
21
24
extern bool hasValidFramebufferAttached;
22
25
23
26
float supportBufferData[512 * 4 ];
@@ -113,7 +116,7 @@ MetalRenderer::~MetalRenderer()
113
116
m_device->release ();
114
117
}
115
118
116
- // TODO: don't ignore "mainWindow" argument
119
+ // TODO: don't ignore "mainWindow" argument and respect size
117
120
void MetalRenderer::InitializeLayer (const Vector2i& size, bool mainWindow)
118
121
{
119
122
const auto & windowInfo = gui_getWindowInfo ().window_main ;
@@ -168,19 +171,23 @@ void MetalRenderer::DrawEmptyFrame(bool mainWindow)
168
171
169
172
void MetalRenderer::SwapBuffers (bool swapTV, bool swapDRC)
170
173
{
171
- EndEncoding ();
172
174
173
175
if (m_drawable)
174
176
{
175
- EnsureCommandBuffer ();
176
- m_commandBuffer->presentDrawable (m_drawable);
177
- } else
177
+ auto commandBuffer = GetCommandBuffer ();
178
+ commandBuffer->presentDrawable (m_drawable);
179
+ }
180
+ else
178
181
{
179
182
debug_printf (" skipped present!\n " );
180
183
}
181
184
m_drawable = nullptr ;
182
185
186
+ // Release all the command buffers
183
187
CommitCommandBuffer ();
188
+ for (uint32 i = 0 ; i < m_commandBuffers.size (); i++)
189
+ m_commandBuffers[i].m_commandBuffer ->release ();
190
+ m_commandBuffers.clear ();
184
191
185
192
// Reset temporary buffers
186
193
m_memoryManager->ResetTemporaryBuffers ();
@@ -223,18 +230,20 @@ bool MetalRenderer::BeginFrame(bool mainWindow)
223
230
224
231
void MetalRenderer::Flush (bool waitIdle)
225
232
{
226
- // TODO: should we?
227
- CommitCommandBuffer ();
233
+ // TODO: commit if commit on idle is requested
234
+ if (m_recordedDrawcalls > 0 )
235
+ CommitCommandBuffer ();
228
236
if (waitIdle)
229
237
{
230
- // TODO
238
+ // TODO: shouldn't we wait for all command buffers?
239
+ WaitForCommandBufferCompletion (GetCurrentCommandBuffer ());
231
240
}
232
241
}
233
242
234
243
void MetalRenderer::NotifyLatteCommandProcessorIdle ()
235
244
{
236
- // TODO: should we?
237
- CommitCommandBuffer ();
245
+ // TODO: commit if commit on idle is requested
246
+ // CommitCommandBuffer();
238
247
}
239
248
240
249
void MetalRenderer::AppendOverlayDebugInfo ()
@@ -452,7 +461,7 @@ LatteTextureReadbackInfo* MetalRenderer::texture_createReadback(LatteTextureView
452
461
453
462
void MetalRenderer::surfaceCopy_copySurfaceWithFormatConversion (LatteTexture* sourceTexture, sint32 srcMip, sint32 srcSlice, LatteTexture* destinationTexture, sint32 dstMip, sint32 dstSlice, sint32 width, sint32 height)
454
463
{
455
- EnsureCommandBuffer ();
464
+ GetCommandBuffer ();
456
465
457
466
// scale copy size to effective size
458
467
sint32 effectiveCopyWidth = width;
@@ -809,11 +818,15 @@ void MetalRenderer::draw_endSequence()
809
818
if (pixelShader)
810
819
LatteRenderTarget_trackUpdates ();
811
820
bool hasReadback = LatteTextureReadback_Update ();
812
- // m_recordedDrawcalls++;
813
- // if (m_recordedDrawcalls >= m_submitThreshold || hasReadback)
814
- // {
815
- // SubmitCommandBuffer();
816
- // }
821
+ m_recordedDrawcalls++;
822
+ // The number of draw calls needs to twice as big, since we are interrupting the render pass
823
+ if (m_recordedDrawcalls >= COMMIT_TRESHOLD * 2 || hasReadback)
824
+ {
825
+ CommitCommandBuffer ();
826
+
827
+ // TODO: where should this be called?
828
+ LatteTextureReadback_UpdateFinishedTransfers (false );
829
+ }
817
830
}
818
831
819
832
void * MetalRenderer::indexData_reserveIndexMemory (uint32 size, uint32& offset, uint32& bufferIndex)
@@ -830,22 +843,38 @@ void MetalRenderer::indexData_uploadIndexMemory(uint32 offset, uint32 size)
830
843
// Do nothing, since the buffer has shared storage mode
831
844
}
832
845
833
- void MetalRenderer::EnsureCommandBuffer ()
846
+ MTL::CommandBuffer* MetalRenderer::GetCommandBuffer ()
834
847
{
835
- if (!m_commandBuffer)
848
+ bool needsNewCommandBuffer = (m_commandBuffers.empty () || m_commandBuffers.back ().m_commited );
849
+ if (needsNewCommandBuffer)
836
850
{
837
851
// Debug
838
852
// m_commandQueue->insertDebugCaptureBoundary();
839
853
840
- m_commandBuffer = m_commandQueue->commandBuffer ();
854
+ MTL::CommandBuffer* mtlCommandBuffer = m_commandQueue->commandBuffer ();
855
+ m_commandBuffers.push_back ({mtlCommandBuffer});
856
+
857
+ return mtlCommandBuffer;
858
+ }
859
+ else
860
+ {
861
+ return m_commandBuffers.back ().m_commandBuffer ;
841
862
}
842
863
}
843
864
865
+ bool MetalRenderer::CommandBufferCompleted (MTL::CommandBuffer* commandBuffer)
866
+ {
867
+ return commandBuffer->status () == MTL::CommandBufferStatusCompleted;
868
+ }
869
+
870
+ void MetalRenderer::WaitForCommandBufferCompletion (MTL::CommandBuffer* commandBuffer)
871
+ {
872
+ commandBuffer->waitUntilCompleted ();
873
+ }
874
+
844
875
// Some render passes clear the attachments, forceRecreate is supposed to be used in those cases
845
876
MTL::RenderCommandEncoder* MetalRenderer::GetRenderCommandEncoder (MTL::RenderPassDescriptor* renderPassDescriptor, MTL::Texture* colorRenderTargets[8 ], MTL::Texture* depthRenderTarget, bool forceRecreate, bool rebindStateIfNewEncoder)
846
877
{
847
- EnsureCommandBuffer ();
848
-
849
878
// Check if we need to begin a new render pass
850
879
if (m_commandEncoder)
851
880
{
@@ -881,6 +910,8 @@ MTL::RenderCommandEncoder* MetalRenderer::GetRenderCommandEncoder(MTL::RenderPas
881
910
EndEncoding ();
882
911
}
883
912
913
+ auto commandBuffer = GetCommandBuffer ();
914
+
884
915
// Update state
885
916
m_state.m_lastUsedFBO = m_state.m_activeFBO ;
886
917
for (uint8 i = 0 ; i < 8 ; i++)
@@ -889,7 +920,7 @@ MTL::RenderCommandEncoder* MetalRenderer::GetRenderCommandEncoder(MTL::RenderPas
889
920
}
890
921
m_state.m_depthRenderTarget = depthRenderTarget;
891
922
892
- auto renderCommandEncoder = m_commandBuffer ->renderCommandEncoder (renderPassDescriptor);
923
+ auto renderCommandEncoder = commandBuffer ->renderCommandEncoder (renderPassDescriptor);
893
924
m_commandEncoder = renderCommandEncoder;
894
925
m_encoderType = MetalEncoderType::Render;
895
926
@@ -914,7 +945,9 @@ MTL::ComputeCommandEncoder* MetalRenderer::GetComputeCommandEncoder()
914
945
EndEncoding ();
915
946
}
916
947
917
- auto computeCommandEncoder = m_commandBuffer->computeCommandEncoder ();
948
+ auto commandBuffer = GetCommandBuffer ();
949
+
950
+ auto computeCommandEncoder = commandBuffer->computeCommandEncoder ();
918
951
m_commandEncoder = computeCommandEncoder;
919
952
m_encoderType = MetalEncoderType::Compute;
920
953
@@ -933,7 +966,9 @@ MTL::BlitCommandEncoder* MetalRenderer::GetBlitCommandEncoder()
933
966
EndEncoding ();
934
967
}
935
968
936
- auto blitCommandEncoder = m_commandBuffer->blitCommandEncoder ();
969
+ auto commandBuffer = GetCommandBuffer ();
970
+
971
+ auto blitCommandEncoder = commandBuffer->blitCommandEncoder ();
937
972
m_commandEncoder = blitCommandEncoder;
938
973
m_encoderType = MetalEncoderType::Blit;
939
974
@@ -942,30 +977,35 @@ MTL::BlitCommandEncoder* MetalRenderer::GetBlitCommandEncoder()
942
977
943
978
void MetalRenderer::EndEncoding ()
944
979
{
945
- if (m_commandEncoder )
980
+ if (m_encoderType != MetalEncoderType::None )
946
981
{
947
982
m_commandEncoder->endEncoding ();
948
983
m_commandEncoder->release ();
949
- m_commandEncoder = nullptr ;
950
984
m_encoderType = MetalEncoderType::None;
985
+
986
+ // Commit the command buffer if enough draw calls have been recorded
987
+ if (m_recordedDrawcalls >= COMMIT_TRESHOLD)
988
+ CommitCommandBuffer ();
951
989
}
952
990
}
953
991
954
992
void MetalRenderer::CommitCommandBuffer ()
955
993
{
956
- EndEncoding () ;
994
+ m_recordedDrawcalls = 0 ;
957
995
958
- if (m_commandBuffer )
996
+ if (m_commandBuffers. size () != 0 )
959
997
{
960
- m_commandBuffer->commit ();
961
- m_commandBuffer->release ();
962
- m_commandBuffer = nullptr ;
998
+ EndEncoding ();
963
999
964
- // TODO: where should this be called?
965
- LatteTextureReadback_UpdateFinishedTransfers (false );
1000
+ auto & commandBuffer = m_commandBuffers.back ();
1001
+ if (!commandBuffer.m_commited )
1002
+ {
1003
+ commandBuffer.m_commandBuffer ->commit ();
1004
+ commandBuffer.m_commited = true ;
966
1005
967
- // Debug
968
- // m_commandQueue->insertDebugCaptureBoundary();
1006
+ // Debug
1007
+ // m_commandQueue->insertDebugCaptureBoundary();
1008
+ }
969
1009
}
970
1010
}
971
1011
0 commit comments