Updates to Metal resource locking.

MVKBufferView add lock when creating MTLTexture.
MVKDeviceMemory add lock when creating MTLBuffer during memory mapping.
MVKMTLBufferAllocator does not need to be threadsafe.
Cleanup syntax on other lock handling to add consistency.
This commit is contained in:
Bill Hollings 2018-01-31 13:43:19 -05:00
parent a1b5ea5494
commit 13687d1a57
7 changed files with 36 additions and 21 deletions

View File

@ -130,14 +130,16 @@ public:
* maximum size. Because MVKMTLBufferRegions are created with a power-of-two size,
* the largest size of a MVKMTLBufferAllocation dispensed by this instance will be the
* next power-of-two value that is at least as big as the specified maximum size.
* If makeThreadSafe is true, a lock will be applied when an allocation is acquired.
*/
MVKMTLBufferAllocator(MVKDevice* device, NSUInteger maxRegionLength);
MVKMTLBufferAllocator(MVKDevice* device, NSUInteger maxRegionLength, bool makeThreadSafe = false);
~MVKMTLBufferAllocator() override;
protected:
std::vector<MVKMTLBufferAllocationPool*> _regionPools;
NSUInteger _maxAllocationLength;
bool _makeThreadSafe;
};

View File

@ -80,11 +80,13 @@ const MVKMTLBufferAllocation* MVKMTLBufferAllocator::acquireMTLBufferRegion(NSUI
// Convert max length to the next power-of-two exponent to use as a lookup
uint32_t p2Exp = mvkPowerOfTwoExponent(length);
return _regionPools[p2Exp]->acquireObjectSafely();
MVKMTLBufferAllocationPool* pRP = _regionPools[p2Exp];
return _makeThreadSafe ? pRP->acquireObjectSafely() : pRP->acquireObject();
}
MVKMTLBufferAllocator::MVKMTLBufferAllocator(MVKDevice* device, NSUInteger maxAllocationLength) : MVKBaseDeviceObject(device) {
_maxAllocationLength = maxAllocationLength;
MVKMTLBufferAllocator::MVKMTLBufferAllocator(MVKDevice* device, NSUInteger maxRegionLength, bool makeThreadSafe) : MVKBaseDeviceObject(device) {
_maxAllocationLength = maxRegionLength;
_makeThreadSafe = makeThreadSafe;
// Convert max length to the next power-of-two exponent
uint32_t maxP2Exp = mvkPowerOfTwoExponent(_maxAllocationLength);

View File

@ -122,5 +122,6 @@ protected:
id<MTLTexture> _mtlTexture;
VkDeviceSize _byteCount;
VkExtent2D _textureSize;
std::mutex _lock;
};

View File

@ -157,12 +157,9 @@ id<MTLBuffer> MVKBuffer::getMTLBuffer() {
id<MTLBuffer> devMemMTLBuff = _deviceMemory->getMTLBuffer();
if (devMemMTLBuff) { return devMemMTLBuff; }
// Lock and check again in case another thread has created the buffer.
lock_guard<mutex> lock(_lock);
// Check again in case another thread has created the buffer.
if (_mtlBuffer) {
return _mtlBuffer;
}
if (_mtlBuffer) { return _mtlBuffer; }
NSUInteger mtlBuffLen = mvkAlignByteOffset(_byteCount, _byteAlignment);
_mtlBuffer = [getMTLDevice() newBufferWithLength: mtlBuffLen
@ -203,6 +200,11 @@ MVKBuffer::~MVKBuffer() {
id<MTLTexture> MVKBufferView::getMTLTexture() {
if ( !_mtlTexture && _mtlPixelFormat && _device->_pMetalFeatures->texelBuffers) {
// Lock and check again in case another thread has created the texture.
lock_guard<mutex> lock(_lock);
if (_mtlTexture) { return _mtlTexture; }
VkDeviceSize byteAlign = _device->_pProperties->limits.minTexelBufferOffsetAlignment;
NSUInteger mtlByteCnt = mvkAlignByteOffset(_byteCount, byteAlign);
MTLTextureDescriptor* mtlTexDesc = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat: _mtlPixelFormat

View File

@ -120,6 +120,7 @@ protected:
VkDeviceSize _mapOffset;
VkDeviceSize _mapSize;
id<MTLBuffer> _mtlBuffer;
std::mutex _lock;
MTLResourceOptions _mtlResourceOptions;
MTLStorageMode _mtlStorageMode;
MTLCPUCacheMode _mtlCPUCacheMode;

View File

@ -62,10 +62,15 @@ VkResult MVKDeviceMemory::map(VkDeviceSize offset, VkDeviceSize size, VkMemoryMa
if ( !mapToSingleResource(offset, mapSize) ) {
if (isMemoryHostCoherent()) {
if ( !_mtlBuffer ) {
NSUInteger mtlBuffLen = mvkAlignByteOffset(_allocationSize, _device->_pMetalFeatures->mtlBufferAlignment);
_mtlBuffer = [getMTLDevice() newBufferWithLength: mtlBuffLen options: _mtlResourceOptions]; // retained
// MVKLogDebug("Allocating host mapped memory %p with offset %d and size %d via underlying coherent MTLBuffer %p of size %d.", this, offset, mapSize, _mtlBuffer , _mtlBuffer.length);
}
// Lock and check again in case another thread has created the buffer.
lock_guard<mutex> lock(_lock);
if ( !_mtlBuffer ) {
NSUInteger mtlBuffLen = mvkAlignByteOffset(_allocationSize, _device->_pMetalFeatures->mtlBufferAlignment);
_mtlBuffer = [getMTLDevice() newBufferWithLength: mtlBuffLen options: _mtlResourceOptions]; // retained
// MVKLogDebug("Allocating host mapped memory %p with offset %d and size %d via underlying coherent MTLBuffer %p of size %d.", this, offset, mapSize, _mtlBuffer , _mtlBuffer.length);
}
}
_pLogicalMappedMemory = _mtlBuffer.contents;
_pMappedMemory = (void*)((uintptr_t)_pLogicalMappedMemory + offset);
} else {

View File

@ -216,11 +216,12 @@ void* MVKImage::map(VkDeviceSize offset, VkDeviceSize size) {
id<MTLTexture> MVKImage::getMTLTexture() {
if ( !_mtlTexture && _mtlPixelFormat ) {
// Lock and check again in case another thread has created the texture.
lock_guard<mutex> lock(_lock);
// Check again in case another thread has created the texture.
if ( !_mtlTexture ) {
_mtlTexture = newMTLTexture(); // retained
}
if (_mtlTexture) { return _mtlTexture; }
_mtlTexture = newMTLTexture(); // retained
}
return _mtlTexture;
}
@ -544,11 +545,12 @@ id<MTLTexture> MVKImageView::getMTLTexture() {
// If we can use a Metal texture view, lazily create it, otherwise use the image texture directly.
if (_useMTLTextureView) {
if ( !_mtlTexture && _mtlPixelFormat ) {
// Lock and check again in case another thread created the texture view
lock_guard<mutex> lock(_lock);
// Check again in case another thread created the texture view
if ( !_mtlTexture ) {
_mtlTexture = newMTLTexture(); // retained
}
if (_mtlTexture) { return _mtlTexture; }
_mtlTexture = newMTLTexture(); // retained
}
return _mtlTexture;
} else {