Cocoa Port: Improve the performance and robustness of Metal display views.
- Add a unique sequence number to fetched frames to ensure that older frames are not drawn after newer frames. - After much research, finally settle on a method for fetching the NDS framebuffers -- using a MTLBlitCommandEncoder to blit a MTLBuffer to a MTLTexture. It is faster than uploading a texture using [id<MTLTexture> replaceRegion:mipmapLevel:withBytes:bytesPerRow:], and also faster than using a pinned-memory backed linear texture. This method will be the way going forward for fetching framebuffers in Metal.
This commit is contained in:
parent
064527e24e
commit
da3970d817
|
@ -8104,7 +8104,7 @@ GPUSubsystem::GPUSubsystem()
|
|||
_pending3DRendererID = RENDERID_NULL;
|
||||
_needChange3DRenderer = false;
|
||||
|
||||
_videoFrameCount = 0;
|
||||
_videoFrameIndex = 0;
|
||||
_render3DFrameCount = 0;
|
||||
_frameNeedsFinish = false;
|
||||
_willFrameSkip = false;
|
||||
|
@ -8134,6 +8134,7 @@ GPUSubsystem::GPUSubsystem()
|
|||
_displayInfo.isDisplayEnabled[NDSDisplayID_Touch] = true;
|
||||
|
||||
_displayInfo.bufferIndex = 0;
|
||||
_displayInfo.sequenceNumber = 0;
|
||||
_displayInfo.masterNativeBuffer = _masterFramebuffer;
|
||||
_displayInfo.masterCustomBuffer = (u8 *)_masterFramebuffer + (GPU_FRAMEBUFFER_NATIVE_WIDTH * GPU_FRAMEBUFFER_NATIVE_HEIGHT * 2 * _displayInfo.pixelBytes);
|
||||
|
||||
|
@ -8205,12 +8206,12 @@ GPUSubsystem::~GPUSubsystem()
|
|||
|
||||
void GPUSubsystem::_UpdateFPSRender3D()
|
||||
{
|
||||
this->_videoFrameCount++;
|
||||
if (this->_videoFrameCount == 60)
|
||||
this->_videoFrameIndex++;
|
||||
if (this->_videoFrameIndex == 60)
|
||||
{
|
||||
this->_render3DFrameCount = gfx3d.render3DFrameCount;
|
||||
gfx3d.render3DFrameCount = 0;
|
||||
this->_videoFrameCount = 0;
|
||||
this->_videoFrameIndex = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -8232,7 +8233,7 @@ void GPUSubsystem::Reset()
|
|||
}
|
||||
|
||||
this->_willFrameSkip = false;
|
||||
this->_videoFrameCount = 0;
|
||||
this->_videoFrameIndex = 0;
|
||||
this->_render3DFrameCount = 0;
|
||||
this->_backlightIntensityTotal[NDSDisplayID_Main] = 0.0f;
|
||||
this->_backlightIntensityTotal[NDSDisplayID_Touch] = 0.0f;
|
||||
|
@ -8290,6 +8291,7 @@ void GPUSubsystem::ForceFrameStop()
|
|||
if (this->_frameNeedsFinish)
|
||||
{
|
||||
this->_frameNeedsFinish = false;
|
||||
this->_displayInfo.sequenceNumber++;
|
||||
this->_event->DidFrameEnd(this->_willFrameSkip, this->_displayInfo);
|
||||
}
|
||||
}
|
||||
|
@ -9009,6 +9011,7 @@ void GPUSubsystem::RenderLine(const size_t l)
|
|||
if (this->_frameNeedsFinish)
|
||||
{
|
||||
this->_frameNeedsFinish = false;
|
||||
this->_displayInfo.sequenceNumber++;
|
||||
this->_event->DidFrameEnd(this->_willFrameSkip, this->_displayInfo);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1156,7 +1156,10 @@ typedef struct
|
|||
|
||||
|
||||
// Frame render state information. These fields will change per frame, depending on how each display was rendered.
|
||||
u8 bufferIndex; // Index of this frame's buffer set.
|
||||
u8 bufferIndex; // Index of a specific framebuffer page for the GPU emulation to write data into.
|
||||
// Indexing starts at 0, and must be less than framebufferPageCount.
|
||||
// A specific index can be chosen at the DidFrameBegin event.
|
||||
size_t sequenceNumber; // A unique number assigned to each frame that increments for each DidFrameEnd event. Never resets.
|
||||
|
||||
void *masterNativeBuffer; // Pointer to the head of the master native buffer.
|
||||
void *masterCustomBuffer; // Pointer to the head of the master custom buffer.
|
||||
|
@ -1765,7 +1768,7 @@ private:
|
|||
int _pending3DRendererID;
|
||||
bool _needChange3DRenderer;
|
||||
|
||||
u32 _videoFrameCount; // Internal variable that increments when a video frame is completed. Resets every 60 video frames.
|
||||
u32 _videoFrameIndex; // Increments whenever a video frame is completed. Resets every 60 video frames.
|
||||
u32 _render3DFrameCount; // The current 3D rendering frame count, saved to this variable once every 60 video frames.
|
||||
bool _frameNeedsFinish;
|
||||
bool _willFrameSkip;
|
||||
|
|
|
@ -1235,24 +1235,6 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
// As a last resort, search for any buffer that is not currently writing, and then force wait
|
||||
// on its corresponding semaphore.
|
||||
if (stillSearching)
|
||||
{
|
||||
selectedIndex = (selectedIndex + 1) % pageCount;
|
||||
for (; selectedIndex != currentIndex; selectedIndex = (selectedIndex + 1) % pageCount)
|
||||
{
|
||||
if ( ([self framebufferStateAtIndex:selectedIndex] == ClientDisplayBufferState_Idle) ||
|
||||
([self framebufferStateAtIndex:selectedIndex] == ClientDisplayBufferState_Ready) ||
|
||||
([self framebufferStateAtIndex:selectedIndex] == ClientDisplayBufferState_Reading) ||
|
||||
([self framebufferStateAtIndex:selectedIndex] == ClientDisplayBufferState_PendingRead) )
|
||||
{
|
||||
stillSearching = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return selectedIndex;
|
||||
}
|
||||
|
||||
|
|
|
@ -42,17 +42,23 @@ class MacMetalFetchObject;
|
|||
class MacMetalDisplayPresenter;
|
||||
class MacMetalDisplayView;
|
||||
|
||||
union MetalTexturePair
|
||||
struct MetalTexturePair
|
||||
{
|
||||
id<MTLTexture> tex[2];
|
||||
uint8_t bufferIndex;
|
||||
size_t fetchSequenceNumber;
|
||||
|
||||
struct
|
||||
union
|
||||
{
|
||||
id<MTLTexture> main;
|
||||
id<MTLTexture> touch;
|
||||
id<MTLTexture> tex[2];
|
||||
|
||||
struct
|
||||
{
|
||||
id<MTLTexture> main;
|
||||
id<MTLTexture> touch;
|
||||
};
|
||||
};
|
||||
};
|
||||
typedef union MetalTexturePair MetalTexturePair;
|
||||
typedef struct MetalTexturePair MetalTexturePair;
|
||||
|
||||
struct MetalRenderFrameInfo
|
||||
{
|
||||
|
@ -116,7 +122,6 @@ typedef DisplayViewShaderProperties DisplayViewShaderProperties;
|
|||
|
||||
MetalTexturePair texPairFetch;
|
||||
id<MTLBlitCommandEncoder> bceFetch;
|
||||
BOOL willFetchImmediate;
|
||||
|
||||
id<MTLTexture> texLQ2xLUT;
|
||||
id<MTLTexture> texHQ2xLUT;
|
||||
|
@ -124,15 +129,11 @@ typedef DisplayViewShaderProperties DisplayViewShaderProperties;
|
|||
id<MTLTexture> texHQ4xLUT;
|
||||
id<MTLTexture> texCurrentHQnxLUT;
|
||||
|
||||
MTLResourceOptions preferredResourceStorageMode;
|
||||
|
||||
MTLSize _fetchThreadsPerGroup;
|
||||
MTLSize _fetchThreadGroupsPerGridNative;
|
||||
MTLSize _fetchThreadGroupsPerGridCustom;
|
||||
MTLSize deposterizeThreadsPerGroup;
|
||||
MTLSize deposterizeThreadGroupsPerGrid;
|
||||
|
||||
BOOL _isSharedBufferTextureSupported;
|
||||
}
|
||||
|
||||
@property (readonly, nonatomic) id<MTLDevice> device;
|
||||
|
@ -149,7 +150,6 @@ typedef DisplayViewShaderProperties DisplayViewShaderProperties;
|
|||
|
||||
@property (assign) MetalTexturePair texPairFetch;
|
||||
@property (assign) id<MTLBlitCommandEncoder> bceFetch;
|
||||
@property (assign) BOOL willFetchImmediate;
|
||||
|
||||
@property (readonly, nonatomic) id<MTLTexture> texLQ2xLUT;
|
||||
@property (readonly, nonatomic) id<MTLTexture> texHQ2xLUT;
|
||||
|
@ -163,7 +163,7 @@ typedef DisplayViewShaderProperties DisplayViewShaderProperties;
|
|||
@property (readonly, nonatomic) MTLSize deposterizeThreadGroupsPerGrid;
|
||||
|
||||
- (void) setFetchBuffersWithDisplayInfo:(const NDSDisplayInfo &)dispInfo;
|
||||
- (MetalTexturePair) setFetchTextureBindingsAtIndex:(const u8)index commandBuffer:(id<MTLCommandBuffer>)cb;
|
||||
- (MetalTexturePair) setFetchTextureBindingsAtIndex:(const uint8_t)index commandBuffer:(id<MTLCommandBuffer>)cb;
|
||||
- (void) fetchFromBufferIndex:(const u8)index;
|
||||
- (void) fetchNativeDisplayByID:(const NDSDisplayID)displayID bufferIndex:(const u8)bufferIndex blitCommandEncoder:(id<MTLBlitCommandEncoder>)bce;
|
||||
- (void) fetchCustomDisplayByID:(const NDSDisplayID)displayID bufferIndex:(const u8)bufferIndex blitCommandEncoder:(id<MTLBlitCommandEncoder>)bce;
|
||||
|
@ -265,6 +265,8 @@ typedef DisplayViewShaderProperties DisplayViewShaderProperties;
|
|||
MacMetalDisplayPresenterObject *presenterObject;
|
||||
dispatch_semaphore_t _semDrawable;
|
||||
id<CAMetalDrawable> layerDrawable;
|
||||
MetalTexturePair _displayTexturePair;
|
||||
size_t _displaySequenceNumber;
|
||||
}
|
||||
|
||||
@property (readonly, nonatomic) MacMetalDisplayPresenterObject *presenterObject;
|
||||
|
|
|
@ -37,7 +37,6 @@
|
|||
|
||||
@synthesize texPairFetch;
|
||||
@synthesize bceFetch;
|
||||
@synthesize willFetchImmediate;
|
||||
|
||||
@synthesize texLQ2xLUT;
|
||||
@synthesize texHQ2xLUT;
|
||||
|
@ -76,27 +75,6 @@
|
|||
_fetch666ConvertOnlyPipeline = [[device newComputePipelineStateWithFunction:[defaultLibrary newFunctionWithName:@"nds_fetch666ConvertOnly"] error:nil] retain];
|
||||
deposterizePipeline = [[device newComputePipelineStateWithFunction:[defaultLibrary newFunctionWithName:@"src_filter_deposterize"] error:nil] retain];
|
||||
|
||||
if ( IsOSXVersion(10, 13, 0) || IsOSXVersion(10, 13, 1) || IsOSXVersion(10, 13, 2) || IsOSXVersion(10, 13, 3) || IsOSXVersion(10, 13, 4) )
|
||||
{
|
||||
// On macOS High Sierra, there is currently a bug with newBufferWithBytesNoCopy:length:options:deallocator
|
||||
// that causes it to crash with MTLResourceStorageModeManaged. So for these macOS versions, replace
|
||||
// MTLResourceStorageModeManaged with MTLResourceStorageModeShared. While this solution causes a very small
|
||||
// drop in performance, it is still far superior to use Metal rather than OpenGL.
|
||||
//
|
||||
// As of this writing, the current version of macOS is v10.13.1. Disabling MTLResourceStorageModeManaged on
|
||||
// every point release up to v10.13.4 should, I hope, give Apple enough time to fix their bugs with this!
|
||||
preferredResourceStorageMode = MTLResourceStorageModeShared;
|
||||
}
|
||||
else
|
||||
{
|
||||
preferredResourceStorageMode = MTLResourceStorageModeManaged;
|
||||
}
|
||||
|
||||
// TODO: In practice, linear textures with buffer-backed storage won't actually work since synchronization has
|
||||
// been removed, so keep this feature disabled until synchronization is reworked.
|
||||
//_isSharedBufferTextureSupported = IsOSXVersionSupported(10, 13, 0) && (preferredResourceStorageMode == MTLResourceStorageModeManaged);
|
||||
_isSharedBufferTextureSupported = NO;
|
||||
|
||||
size_t tw = GetNearestPositivePOT((uint32_t)[_fetch555Pipeline threadExecutionWidth]);
|
||||
while ( (tw > [_fetch555Pipeline threadExecutionWidth]) || (tw > GPU_FRAMEBUFFER_NATIVE_WIDTH) )
|
||||
{
|
||||
|
@ -197,10 +175,8 @@
|
|||
width:GPU_FRAMEBUFFER_NATIVE_WIDTH
|
||||
height:GPU_FRAMEBUFFER_NATIVE_HEIGHT
|
||||
mipmapped:NO];
|
||||
|
||||
[newTexDisplayDesc setResourceOptions:MTLResourceStorageModeManaged | MTLResourceCPUCacheModeWriteCombined];
|
||||
[newTexDisplayDesc setStorageMode:MTLStorageModeManaged];
|
||||
[newTexDisplayDesc setCpuCacheMode:MTLCPUCacheModeWriteCombined];
|
||||
[newTexDisplayDesc setResourceOptions:MTLResourceStorageModePrivate];
|
||||
[newTexDisplayDesc setStorageMode:MTLStorageModePrivate];
|
||||
[newTexDisplayDesc setUsage:MTLTextureUsageShaderRead];
|
||||
|
||||
MTLTextureDescriptor *newTexPostprocessDesc = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatRGBA8Unorm
|
||||
|
@ -234,10 +210,11 @@
|
|||
_texDisplayPostprocessCustom[NDSDisplayID_Touch][i] = [device newTextureWithDescriptor:newTexPostprocessDesc];
|
||||
}
|
||||
|
||||
texPairFetch.bufferIndex = 0;
|
||||
texPairFetch.fetchSequenceNumber = 0;
|
||||
texPairFetch.main = [_texDisplayPostprocessNative[NDSDisplayID_Main][0] retain];
|
||||
texPairFetch.touch = [_texDisplayPostprocessNative[NDSDisplayID_Touch][0] retain];
|
||||
bceFetch = nil;
|
||||
willFetchImmediate = YES;
|
||||
|
||||
// Set up the HQnx LUT textures.
|
||||
SetupHQnxLUTs_Metal(device, _fetchCommandQueue, texLQ2xLUT, texHQ2xLUT, texHQ3xLUT, texHQ4xLUT);
|
||||
|
@ -312,10 +289,8 @@
|
|||
width:GPU_FRAMEBUFFER_NATIVE_WIDTH
|
||||
height:GPU_FRAMEBUFFER_NATIVE_HEIGHT
|
||||
mipmapped:NO];
|
||||
|
||||
[newTexDisplayNativeDesc setResourceOptions:MTLResourceStorageModeManaged | MTLResourceCPUCacheModeWriteCombined];
|
||||
[newTexDisplayNativeDesc setStorageMode:MTLStorageModeManaged];
|
||||
[newTexDisplayNativeDesc setCpuCacheMode:MTLCPUCacheModeWriteCombined];
|
||||
[newTexDisplayNativeDesc setResourceOptions:MTLResourceStorageModePrivate];
|
||||
[newTexDisplayNativeDesc setStorageMode:MTLStorageModePrivate];
|
||||
[newTexDisplayNativeDesc setUsage:MTLTextureUsageShaderRead];
|
||||
|
||||
MTLTextureDescriptor *newTexPostprocessNativeDesc = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatRGBA8Unorm
|
||||
|
@ -330,10 +305,8 @@
|
|||
width:w
|
||||
height:h
|
||||
mipmapped:NO];
|
||||
|
||||
[newTexDisplayCustomDesc setResourceOptions:MTLResourceStorageModeManaged | MTLResourceCPUCacheModeWriteCombined];
|
||||
[newTexDisplayCustomDesc setStorageMode:MTLStorageModeManaged];
|
||||
[newTexDisplayCustomDesc setCpuCacheMode:MTLCPUCacheModeWriteCombined];
|
||||
[newTexDisplayCustomDesc setResourceOptions:MTLResourceStorageModePrivate];
|
||||
[newTexDisplayCustomDesc setStorageMode:MTLStorageModePrivate];
|
||||
[newTexDisplayCustomDesc setUsage:MTLTextureUsageShaderRead];
|
||||
|
||||
MTLTextureDescriptor *newTexPostprocessCustomDesc = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatRGBA8Unorm
|
||||
|
@ -380,22 +353,8 @@
|
|||
[_texDisplayPostprocessNative[NDSDisplayID_Main][i] release];
|
||||
[_texDisplayPostprocessNative[NDSDisplayID_Touch][i] release];
|
||||
|
||||
#ifdef MAC_OS_X_VERSION_10_13
|
||||
if (_isSharedBufferTextureSupported)
|
||||
{
|
||||
if (@available(macOS 10_13, *))
|
||||
{
|
||||
_texDisplayFetchNative[NDSDisplayID_Main][i] = [_bufDisplayFetchNative[NDSDisplayID_Main][i] newTextureWithDescriptor:newTexDisplayNativeDesc offset:0 bytesPerRow:_nativeLineSize];
|
||||
_texDisplayFetchNative[NDSDisplayID_Touch][i] = [_bufDisplayFetchNative[NDSDisplayID_Touch][i] newTextureWithDescriptor:newTexDisplayNativeDesc offset:0 bytesPerRow:_nativeLineSize];
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
_texDisplayFetchNative[NDSDisplayID_Main][i] = [device newTextureWithDescriptor:newTexDisplayNativeDesc];
|
||||
_texDisplayFetchNative[NDSDisplayID_Touch][i] = [device newTextureWithDescriptor:newTexDisplayNativeDesc];
|
||||
}
|
||||
|
||||
_texDisplayFetchNative[NDSDisplayID_Main][i] = [device newTextureWithDescriptor:newTexDisplayNativeDesc];
|
||||
_texDisplayFetchNative[NDSDisplayID_Touch][i] = [device newTextureWithDescriptor:newTexDisplayNativeDesc];
|
||||
_texDisplayPostprocessNative[NDSDisplayID_Main][i] = [device newTextureWithDescriptor:newTexPostprocessNativeDesc];
|
||||
_texDisplayPostprocessNative[NDSDisplayID_Touch][i] = [device newTextureWithDescriptor:newTexPostprocessNativeDesc];
|
||||
}
|
||||
|
@ -409,22 +368,8 @@
|
|||
[_texDisplayPostprocessCustom[NDSDisplayID_Main][i] release];
|
||||
[_texDisplayPostprocessCustom[NDSDisplayID_Touch][i] release];
|
||||
|
||||
#ifdef MAC_OS_X_VERSION_10_13
|
||||
if (_isSharedBufferTextureSupported)
|
||||
{
|
||||
if (@available(macOS 10_13, *))
|
||||
{
|
||||
_texDisplayFetchCustom[NDSDisplayID_Main][i] = [_bufDisplayFetchCustom[NDSDisplayID_Main][i] newTextureWithDescriptor:newTexDisplayCustomDesc offset:0 bytesPerRow:_customLineSize];
|
||||
_texDisplayFetchCustom[NDSDisplayID_Touch][i] = [_bufDisplayFetchCustom[NDSDisplayID_Touch][i] newTextureWithDescriptor:newTexDisplayCustomDesc offset:0 bytesPerRow:_customLineSize];
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
_texDisplayFetchCustom[NDSDisplayID_Main][i] = [device newTextureWithDescriptor:newTexDisplayCustomDesc];
|
||||
_texDisplayFetchCustom[NDSDisplayID_Touch][i] = [device newTextureWithDescriptor:newTexDisplayCustomDesc];
|
||||
}
|
||||
|
||||
_texDisplayFetchCustom[NDSDisplayID_Main][i] = [device newTextureWithDescriptor:newTexDisplayCustomDesc];
|
||||
_texDisplayFetchCustom[NDSDisplayID_Touch][i] = [device newTextureWithDescriptor:newTexDisplayCustomDesc];
|
||||
_texDisplayPostprocessCustom[NDSDisplayID_Main][i] = [device newTextureWithDescriptor:newTexPostprocessCustomDesc];
|
||||
_texDisplayPostprocessCustom[NDSDisplayID_Touch][i] = [device newTextureWithDescriptor:newTexPostprocessCustomDesc];
|
||||
}
|
||||
|
@ -450,13 +395,14 @@
|
|||
[oldTexPair.touch release];
|
||||
}
|
||||
|
||||
- (MetalTexturePair) setFetchTextureBindingsAtIndex:(const u8)index commandBuffer:(id<MTLCommandBuffer>)cb
|
||||
- (MetalTexturePair) setFetchTextureBindingsAtIndex:(const uint8_t)index commandBuffer:(id<MTLCommandBuffer>)cb
|
||||
{
|
||||
MetalTexturePair targetTexPair = {nil, nil};
|
||||
const NDSDisplayInfo ¤tDisplayInfo = GPUFetchObject->GetFetchDisplayInfoForBufferIndex(index);
|
||||
const bool isMainEnabled = currentDisplayInfo.isDisplayEnabled[NDSDisplayID_Main];
|
||||
const bool isTouchEnabled = currentDisplayInfo.isDisplayEnabled[NDSDisplayID_Touch];
|
||||
|
||||
MetalTexturePair targetTexPair = {index, currentDisplayInfo.sequenceNumber, nil, nil};
|
||||
|
||||
if (isMainEnabled || isTouchEnabled)
|
||||
{
|
||||
if (isMainEnabled)
|
||||
|
@ -637,37 +583,24 @@
|
|||
id<MTLCommandBuffer> cb = [_fetchCommandQueue commandBufferWithUnretainedReferences];
|
||||
[cb enqueue];
|
||||
|
||||
[self setWillFetchImmediate:YES];
|
||||
semaphore_wait([self semaphoreFramebufferPageAtIndex:index]);
|
||||
[self setFramebufferState:ClientDisplayBufferState_Reading index:index];
|
||||
|
||||
if (!_isSharedBufferTextureSupported)
|
||||
{
|
||||
semaphore_wait([self semaphoreFramebufferPageAtIndex:index]);
|
||||
[self setFramebufferState:ClientDisplayBufferState_Reading index:index];
|
||||
|
||||
id<MTLBlitCommandEncoder> bce = [cb blitCommandEncoder];
|
||||
[self setBceFetch:bce];
|
||||
GPUFetchObject->GPUClientFetchObject::FetchFromBufferIndex(index);
|
||||
[self setBceFetch:nil];
|
||||
[bce endEncoding];
|
||||
|
||||
if ([self willFetchImmediate])
|
||||
{
|
||||
[self setFramebufferState:ClientDisplayBufferState_Idle index:index];
|
||||
semaphore_signal([self semaphoreFramebufferPageAtIndex:index]);
|
||||
}
|
||||
else
|
||||
{
|
||||
[cb addCompletedHandler:^(id<MTLCommandBuffer> block) {
|
||||
[self setFramebufferState:ClientDisplayBufferState_Idle index:index];
|
||||
semaphore_signal([self semaphoreFramebufferPageAtIndex:index]);
|
||||
}];
|
||||
|
||||
[cb commit];
|
||||
|
||||
cb = [_fetchCommandQueue commandBufferWithUnretainedReferences];
|
||||
[cb enqueue];
|
||||
}
|
||||
}
|
||||
id<MTLBlitCommandEncoder> bce = [cb blitCommandEncoder];
|
||||
[self setBceFetch:bce];
|
||||
GPUFetchObject->GPUClientFetchObject::FetchFromBufferIndex(index);
|
||||
[self setBceFetch:nil];
|
||||
[bce endEncoding];
|
||||
|
||||
[cb addCompletedHandler:^(id<MTLCommandBuffer> block) {
|
||||
[self setFramebufferState:ClientDisplayBufferState_Idle index:index];
|
||||
semaphore_signal([self semaphoreFramebufferPageAtIndex:index]);
|
||||
}];
|
||||
|
||||
[cb commit];
|
||||
|
||||
cb = [_fetchCommandQueue commandBufferWithUnretainedReferences];
|
||||
[cb enqueue];
|
||||
|
||||
const MetalTexturePair newTexPair = [self setFetchTextureBindingsAtIndex:index commandBuffer:cb];
|
||||
[newTexPair.main retain];
|
||||
|
@ -685,56 +618,43 @@
|
|||
|
||||
- (void) fetchNativeDisplayByID:(const NDSDisplayID)displayID bufferIndex:(const u8)bufferIndex blitCommandEncoder:(id<MTLBlitCommandEncoder>)bce
|
||||
{
|
||||
id<MTLTexture> targetDestination = _texDisplayFetchNative[displayID][bufferIndex];
|
||||
const NDSDisplayInfo ¤tDisplayInfo = GPUFetchObject->GetFetchDisplayInfoForBufferIndex(bufferIndex);
|
||||
if (bce == nil)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ([self willFetchImmediate])
|
||||
{
|
||||
[targetDestination replaceRegion:MTLRegionMake2D(0, 0, GPU_FRAMEBUFFER_NATIVE_WIDTH, GPU_FRAMEBUFFER_NATIVE_HEIGHT)
|
||||
mipmapLevel:0
|
||||
withBytes:currentDisplayInfo.nativeBuffer[displayID]
|
||||
bytesPerRow:_nativeLineSize];
|
||||
}
|
||||
else
|
||||
{
|
||||
[bce copyFromBuffer:_bufDisplayFetchNative[displayID][bufferIndex]
|
||||
sourceOffset:0
|
||||
sourceBytesPerRow:_nativeLineSize
|
||||
sourceBytesPerImage:_nativeBufferSize
|
||||
sourceSize:MTLSizeMake(GPU_FRAMEBUFFER_NATIVE_WIDTH, GPU_FRAMEBUFFER_NATIVE_HEIGHT, 1)
|
||||
toTexture:targetDestination
|
||||
destinationSlice:0
|
||||
destinationLevel:0
|
||||
destinationOrigin:MTLOriginMake(0, 0, 0)];
|
||||
}
|
||||
id<MTLTexture> targetDestination = _texDisplayFetchNative[displayID][bufferIndex];
|
||||
|
||||
[bce copyFromBuffer:_bufDisplayFetchNative[displayID][bufferIndex]
|
||||
sourceOffset:0
|
||||
sourceBytesPerRow:_nativeLineSize
|
||||
sourceBytesPerImage:_nativeBufferSize
|
||||
sourceSize:MTLSizeMake(GPU_FRAMEBUFFER_NATIVE_WIDTH, GPU_FRAMEBUFFER_NATIVE_HEIGHT, 1)
|
||||
toTexture:targetDestination
|
||||
destinationSlice:0
|
||||
destinationLevel:0
|
||||
destinationOrigin:MTLOriginMake(0, 0, 0)];
|
||||
}
|
||||
|
||||
- (void) fetchCustomDisplayByID:(const NDSDisplayID)displayID bufferIndex:(const u8)bufferIndex blitCommandEncoder:(id<MTLBlitCommandEncoder>)bce
|
||||
{
|
||||
if (bce == nil)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const NDSDisplayInfo ¤tDisplayInfo = GPUFetchObject->GetFetchDisplayInfoForBufferIndex(bufferIndex);
|
||||
id<MTLTexture> targetDestination = _texDisplayFetchCustom[displayID][bufferIndex];
|
||||
|
||||
if ( (currentDisplayInfo.customWidth < GPU_FRAMEBUFFER_NATIVE_WIDTH * 5) && (currentDisplayInfo.customHeight < GPU_FRAMEBUFFER_NATIVE_HEIGHT * 5) )
|
||||
{
|
||||
[targetDestination replaceRegion:MTLRegionMake2D(0, 0, currentDisplayInfo.customWidth, currentDisplayInfo.customHeight)
|
||||
mipmapLevel:0
|
||||
withBytes:currentDisplayInfo.customBuffer[displayID]
|
||||
bytesPerRow:_customLineSize];
|
||||
}
|
||||
else
|
||||
{
|
||||
[self setWillFetchImmediate:NO];
|
||||
|
||||
[bce copyFromBuffer:_bufDisplayFetchCustom[displayID][bufferIndex]
|
||||
sourceOffset:0
|
||||
sourceBytesPerRow:_customLineSize
|
||||
sourceBytesPerImage:_customBufferSize
|
||||
sourceSize:MTLSizeMake(currentDisplayInfo.customWidth, currentDisplayInfo.customHeight, 1)
|
||||
toTexture:targetDestination
|
||||
destinationSlice:0
|
||||
destinationLevel:0
|
||||
destinationOrigin:MTLOriginMake(0, 0, 0)];
|
||||
}
|
||||
[bce copyFromBuffer:_bufDisplayFetchCustom[displayID][bufferIndex]
|
||||
sourceOffset:0
|
||||
sourceBytesPerRow:_customLineSize
|
||||
sourceBytesPerImage:_customBufferSize
|
||||
sourceSize:MTLSizeMake(currentDisplayInfo.customWidth, currentDisplayInfo.customHeight, 1)
|
||||
toTexture:targetDestination
|
||||
destinationSlice:0
|
||||
destinationLevel:0
|
||||
destinationOrigin:MTLOriginMake(0, 0, 0)];
|
||||
}
|
||||
|
||||
- (void) flushMultipleViews:(const std::vector<ClientDisplay3DView *> &)cdvFlushList
|
||||
|
@ -851,6 +771,8 @@
|
|||
needsScreenVerticesUpdate = YES;
|
||||
needsHUDVerticesUpdate = YES;
|
||||
|
||||
texPairProcess.bufferIndex = 0;
|
||||
texPairProcess.fetchSequenceNumber = 0;
|
||||
texPairProcess.main = nil;
|
||||
texPairProcess.touch = nil;
|
||||
|
||||
|
@ -1178,8 +1100,11 @@
|
|||
_hudTexCoordBuffer[i] = [[sharedData device] newBufferWithLength:HUD_VERTEX_ATTRIBUTE_BUFFER_SIZE options:MTLResourceStorageModeShared | MTLResourceCPUCacheModeWriteCombined];
|
||||
}
|
||||
|
||||
texPairProcess.main = [[sharedData texPairFetch].main retain];
|
||||
texPairProcess.touch = [[sharedData texPairFetch].touch retain];
|
||||
MetalTexturePair texPairFetch = [sharedData texPairFetch];
|
||||
texPairProcess.bufferIndex = texPairFetch.bufferIndex;
|
||||
texPairProcess.fetchSequenceNumber = texPairFetch.fetchSequenceNumber;
|
||||
texPairProcess.main = [texPairFetch.main retain];
|
||||
texPairProcess.touch = [texPairFetch.touch retain];
|
||||
|
||||
VideoFilter *vfMain = cdp->GetPixelScalerObject(NDSDisplayID_Main);
|
||||
_bufCPUFilterSrcMain = [[sharedData device] newBufferWithBytesNoCopy:vfMain->GetSrcBufferPtr()
|
||||
|
@ -1322,16 +1247,16 @@
|
|||
|
||||
- (void) processDisplays
|
||||
{
|
||||
const uint8_t bufferIndex = [sharedData GPUFetchObject]->GetLastFetchIndex();
|
||||
const NDSDisplayInfo &fetchDisplayInfo = [sharedData GPUFetchObject]->GetFetchDisplayInfoForBufferIndex(bufferIndex);
|
||||
const MetalTexturePair texFetch = [sharedData texPairFetch];
|
||||
const NDSDisplayInfo &fetchDisplayInfo = [sharedData GPUFetchObject]->GetFetchDisplayInfoForBufferIndex(texFetch.bufferIndex);
|
||||
const ClientDisplayMode mode = cdp->GetPresenterProperties().mode;
|
||||
const bool useDeposterize = cdp->GetSourceDeposterize();
|
||||
const NDSDisplayID selectedDisplaySourceMain = cdp->GetSelectedDisplaySourceForDisplay(NDSDisplayID_Main);
|
||||
const NDSDisplayID selectedDisplaySourceTouch = cdp->GetSelectedDisplaySourceForDisplay(NDSDisplayID_Touch);
|
||||
|
||||
const MetalTexturePair texFetch = [sharedData texPairFetch];
|
||||
|
||||
MetalTexturePair newTexProcess;
|
||||
newTexProcess.bufferIndex = texFetch.bufferIndex;
|
||||
newTexProcess.fetchSequenceNumber = texFetch.fetchSequenceNumber;
|
||||
newTexProcess.main = (selectedDisplaySourceMain == NDSDisplayID_Main) ? texFetch.main : texFetch.touch;
|
||||
newTexProcess.touch = (selectedDisplaySourceTouch == NDSDisplayID_Touch) ? texFetch.touch : texFetch.main;
|
||||
|
||||
|
@ -1867,24 +1792,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
// As a last resort, search for any buffer that is not currently writing, and then force wait
|
||||
// on its corresponding semaphore.
|
||||
if (stillSearching)
|
||||
{
|
||||
selectedIndex = (selectedIndex + 1) % RENDER_BUFFER_COUNT;
|
||||
for (; selectedIndex != mrfi.renderIndex; selectedIndex = (selectedIndex + 1) % RENDER_BUFFER_COUNT)
|
||||
{
|
||||
if ( ([self renderBufferStateAtIndex:selectedIndex] == ClientDisplayBufferState_Idle) ||
|
||||
([self renderBufferStateAtIndex:selectedIndex] == ClientDisplayBufferState_Ready) ||
|
||||
([self renderBufferStateAtIndex:selectedIndex] == ClientDisplayBufferState_Reading) ||
|
||||
([self renderBufferStateAtIndex:selectedIndex] == ClientDisplayBufferState_PendingRead) )
|
||||
{
|
||||
stillSearching = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (forceWait)
|
||||
{
|
||||
dispatch_semaphore_wait(_semRenderBuffers[selectedIndex], DISPATCH_TIME_FOREVER);
|
||||
|
@ -2189,6 +2096,12 @@
|
|||
_cdv = NULL;
|
||||
_semDrawable = dispatch_semaphore_create(3);
|
||||
layerDrawable = nil;
|
||||
_displaySequenceNumber = 0;
|
||||
|
||||
_displayTexturePair.bufferIndex = 0;
|
||||
_displayTexturePair.fetchSequenceNumber = 0;
|
||||
_displayTexturePair.main = nil;
|
||||
_displayTexturePair.touch = nil;
|
||||
|
||||
presenterObject = thePresenterObject;
|
||||
if (thePresenterObject != nil)
|
||||
|
@ -2207,6 +2120,9 @@
|
|||
[self setLayerDrawable:nil];
|
||||
dispatch_release(_semDrawable);
|
||||
|
||||
[_displayTexturePair.main release];
|
||||
[_displayTexturePair.touch release];
|
||||
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
|
@ -2223,6 +2139,22 @@
|
|||
{
|
||||
@autoreleasepool
|
||||
{
|
||||
const MetalTexturePair texProcess = [presenterObject texPairProcess];
|
||||
|
||||
if (texProcess.fetchSequenceNumber >= _displayTexturePair.fetchSequenceNumber)
|
||||
{
|
||||
id<MTLTexture> oldTexMain = _displayTexturePair.main;
|
||||
id<MTLTexture> oldTexTouch = _displayTexturePair.touch;
|
||||
|
||||
_displayTexturePair.bufferIndex = texProcess.bufferIndex;
|
||||
_displayTexturePair.fetchSequenceNumber = texProcess.fetchSequenceNumber;
|
||||
_displayTexturePair.main = [texProcess.main retain];
|
||||
_displayTexturePair.touch = [texProcess.touch retain];
|
||||
|
||||
[oldTexMain release];
|
||||
[oldTexTouch release];
|
||||
}
|
||||
|
||||
// Now that everything is set up, go ahead and draw everything.
|
||||
dispatch_semaphore_wait(_semDrawable, DISPATCH_TIME_FOREVER);
|
||||
id<CAMetalDrawable> drawable = [self nextDrawable];
|
||||
|
@ -2231,13 +2163,12 @@
|
|||
{
|
||||
[[presenterObject colorAttachment0Desc] setTexture:[drawable texture]];
|
||||
|
||||
const MetalTexturePair texProcess = [presenterObject texPairProcess];
|
||||
const MetalRenderFrameInfo mrfi = [presenterObject renderFrameInfo];
|
||||
|
||||
[presenterObject renderForCommandBuffer:cb
|
||||
outputPipelineState:[presenterObject outputDrawablePipeline]
|
||||
hudPipelineState:[[presenterObject sharedData] hudPipeline]
|
||||
texDisplays:texProcess
|
||||
texDisplays:_displayTexturePair
|
||||
mrfi:mrfi
|
||||
doYFlip:NO];
|
||||
|
||||
|
|
Loading…
Reference in New Issue