Skip to content

Commit

Permalink
Merge pull request #165 from billhollings/master
Browse files Browse the repository at this point in the history
Synchronization and threading fixes.
  • Loading branch information
billhollings committed May 22, 2018
2 parents d527248 + acf2a6e commit f3355d1
Show file tree
Hide file tree
Showing 11 changed files with 77 additions and 42 deletions.
2 changes: 1 addition & 1 deletion MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ extern "C" {
*/
#define MVK_VERSION_MAJOR 1
#define MVK_VERSION_MINOR 0
#define MVK_VERSION_PATCH 8
#define MVK_VERSION_PATCH 9

#define MVK_MAKE_VERSION(major, minor, patch) (((major) * 10000) + ((minor) * 100) + (patch))
#define MVK_VERSION MVK_MAKE_VERSION(MVK_VERSION_MAJOR, MVK_VERSION_MINOR, MVK_VERSION_PATCH)
Expand Down
4 changes: 2 additions & 2 deletions MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ class MVKRenderPipelineCompiler : public MVKMetalCompiler {
~MVKRenderPipelineCompiler() override;

protected:
void compileComplete(id<MTLRenderPipelineState> pipelineState, NSError *error);
bool compileComplete(id<MTLRenderPipelineState> pipelineState, NSError *error);

id<MTLRenderPipelineState> _mtlRenderPipelineState = nil;
};
Expand Down Expand Up @@ -265,7 +265,7 @@ class MVKComputePipelineCompiler : public MVKMetalCompiler {
~MVKComputePipelineCompiler() override;

protected:
void compileComplete(id<MTLComputePipelineState> pipelineState, NSError *error);
bool compileComplete(id<MTLComputePipelineState> pipelineState, NSError *error);

id<MTLComputePipelineState> _mtlComputePipelineState = nil;
};
14 changes: 8 additions & 6 deletions MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm
Original file line number Diff line number Diff line change
Expand Up @@ -747,18 +747,19 @@ void serialize(Archive & archive, MVKShaderModuleKey& k) {
compile(lock, ^{
[getMTLDevice() newRenderPipelineStateWithDescriptor: mtlRPLDesc
completionHandler: ^(id<MTLRenderPipelineState> ps, NSError* error) {
compileComplete(ps, error);
bool isLate = compileComplete(ps, error);
if (isLate) { destroy(); }
}];
});

return [_mtlRenderPipelineState retain];
}

void MVKRenderPipelineCompiler::compileComplete(id<MTLRenderPipelineState> mtlRenderPipelineState, NSError* compileError) {
bool MVKRenderPipelineCompiler::compileComplete(id<MTLRenderPipelineState> mtlRenderPipelineState, NSError* compileError) {
lock_guard<mutex> lock(_completionLock);

_mtlRenderPipelineState = [mtlRenderPipelineState retain]; // retained
endCompile(compileError);
return endCompile(compileError);
}

#pragma mark Construction
Expand All @@ -777,18 +778,19 @@ void serialize(Archive & archive, MVKShaderModuleKey& k) {
compile(lock, ^{
[getMTLDevice() newComputePipelineStateWithFunction: mtlFunction
completionHandler: ^(id<MTLComputePipelineState> ps, NSError* error) {
compileComplete(ps, error);
bool isLate = compileComplete(ps, error);
if (isLate) { destroy(); }
}];
});

return [_mtlComputePipelineState retain];
}

void MVKComputePipelineCompiler::compileComplete(id<MTLComputePipelineState> mtlComputePipelineState, NSError* compileError) {
bool MVKComputePipelineCompiler::compileComplete(id<MTLComputePipelineState> mtlComputePipelineState, NSError* compileError) {
lock_guard<mutex> lock(_completionLock);

_mtlComputePipelineState = [mtlComputePipelineState retain]; // retained
endCompile(compileError);
return endCompile(compileError);
}

#pragma mark Construction
Expand Down
4 changes: 2 additions & 2 deletions MoltenVK/MoltenVK/GPUObjects/MVKShaderModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ class MVKShaderLibraryCompiler : public MVKMetalCompiler {
~MVKShaderLibraryCompiler() override;

protected:
void compileComplete(id<MTLLibrary> mtlLibrary, NSError *error);
bool compileComplete(id<MTLLibrary> mtlLibrary, NSError *error);
void handleError() override;

id<MTLLibrary> _mtlLibrary = nil;
Expand Down Expand Up @@ -250,7 +250,7 @@ class MVKFunctionSpecializer : public MVKMetalCompiler {
~MVKFunctionSpecializer() override;

protected:
void compileComplete(id<MTLFunction> mtlFunction, NSError *error);
bool compileComplete(id<MTLFunction> mtlFunction, NSError *error);

id<MTLFunction> _mtlFunction = nil;
};
14 changes: 8 additions & 6 deletions MoltenVK/MoltenVK/GPUObjects/MVKShaderModule.mm
Original file line number Diff line number Diff line change
Expand Up @@ -350,7 +350,8 @@ static uint32_t getOffsetForConstantId(const VkSpecializationInfo* pSpecInfo, ui
[getMTLDevice() newLibraryWithSource: mslSourceCode
options: options
completionHandler: ^(id<MTLLibrary> mtlLib, NSError* error) {
compileComplete(mtlLib, error);
bool isLate = compileComplete(mtlLib, error);
if (isLate) { destroy(); }
}];
});

Expand All @@ -366,11 +367,11 @@ static uint32_t getOffsetForConstantId(const VkSpecializationInfo* pSpecInfo, ui
}
}

void MVKShaderLibraryCompiler::compileComplete(id<MTLLibrary> mtlLibrary, NSError* compileError) {
bool MVKShaderLibraryCompiler::compileComplete(id<MTLLibrary> mtlLibrary, NSError* compileError) {
lock_guard<mutex> lock(_completionLock);

_mtlLibrary = [mtlLibrary retain]; // retained
endCompile(compileError);
return endCompile(compileError);
}

#pragma mark Construction
Expand All @@ -392,18 +393,19 @@ static uint32_t getOffsetForConstantId(const VkSpecializationInfo* pSpecInfo, ui
[mtlLibrary newFunctionWithName: funcName
constantValues: constantValues
completionHandler: ^(id<MTLFunction> mtlFunc, NSError* error) {
compileComplete(mtlFunc, error);
bool isLate = compileComplete(mtlFunc, error);
if (isLate) { destroy(); }
}];
});

return [_mtlFunction retain];
}

void MVKFunctionSpecializer::compileComplete(id<MTLFunction> mtlFunction, NSError* compileError) {
bool MVKFunctionSpecializer::compileComplete(id<MTLFunction> mtlFunction, NSError* compileError) {
lock_guard<mutex> lock(_completionLock);

_mtlFunction = [mtlFunction retain]; // retained
endCompile(compileError);
return endCompile(compileError);
}

#pragma mark Construction
Expand Down
4 changes: 3 additions & 1 deletion MoltenVK/MoltenVK/GPUObjects/MVKSurface.mm
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "MVKSurface.h"
#include "MVKInstance.h"
#include "MVKFoundation.h"
#include "MVKOSExtensions.h"


#pragma mark MVKSurface
Expand All @@ -29,7 +30,8 @@
const Vk_PLATFORM_SurfaceCreateInfoMVK* pCreateInfo,
const VkAllocationCallbacks* pAllocator) {

CALayer* viewLayer = ((PLATFORM_VIEW_CLASS*)pCreateInfo->pView).layer;
__block CALayer* viewLayer = nil;
mvkDispatchToMainAndWait(^{ viewLayer = ((PLATFORM_VIEW_CLASS*)pCreateInfo->pView).layer; });
if ( [viewLayer isKindOfClass: [CAMetalLayer class]] ) {
_mtlCAMetalLayer = (CAMetalLayer*)[viewLayer retain]; // retained
} else {
Expand Down
9 changes: 6 additions & 3 deletions MoltenVK/MoltenVK/GPUObjects/MVKSync.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include <mutex>
#include <condition_variable>
#include <unordered_set>
#include <vector>

class MVKFenceSitter;

Expand Down Expand Up @@ -122,7 +123,8 @@ class MVKSignalable : public MVKBaseDeviceObject {
MVKSignalable(MVKDevice* device) : MVKBaseDeviceObject(device) {}

protected:
void maybeDestroy();
bool decrementSignalerCount();
bool markDestroyed();

std::mutex _signalerLock;
uint32_t _signalerCount = 0;
Expand Down Expand Up @@ -246,6 +248,7 @@ class MVKFenceSitter : public MVKBaseObject {

void addUnsignaledFence(MVKFence* fence);
void fenceSignaled(MVKFence* fence);
void getUnsignaledFences(std::vector<MVKFence*>& fences);

std::mutex _lock;
std::unordered_set<MVKFence*> _unsignaledFences;
Expand Down Expand Up @@ -295,8 +298,8 @@ class MVKMetalCompiler : public MVKBaseDeviceObject {
protected:
void compile(std::unique_lock<std::mutex>& lock, dispatch_block_t block);
virtual void handleError();
void endCompile(NSError* compileError);
void maybeDestroy();
bool endCompile(NSError* compileError);
bool markDestroyed();

NSError* _compileError = nil;
uint64_t _startTime = 0;
Expand Down
56 changes: 37 additions & 19 deletions MoltenVK/MoltenVK/GPUObjects/MVKSync.mm
Original file line number Diff line number Diff line change
Expand Up @@ -75,23 +75,27 @@
}

void MVKSignalable::wasRemovedFromSignaler() {
if (decrementSignalerCount()) { destroy(); }
}

// Decrements the signaler count, and returns whether it's time to destroy this object.
bool MVKSignalable::decrementSignalerCount() {
lock_guard<mutex> lock(_signalerLock);

if (_signalerCount > 0) { _signalerCount--; }
maybeDestroy();
return (_isDestroyed && _signalerCount == 0);
}

void MVKSignalable::destroy() {
if (markDestroyed()) { MVKBaseDeviceObject::destroy(); }
}

// Marks this object as destroyed, and returns whether the compilation is complete.
bool MVKSignalable::markDestroyed() {
lock_guard<mutex> lock(_signalerLock);

_isDestroyed = true;
maybeDestroy();
}

void MVKSignalable::maybeDestroy() {
if (_isDestroyed && _signalerCount == 0) {
MVKBaseDeviceObject::destroy();
}
return _signalerCount == 0;
}


Expand Down Expand Up @@ -190,12 +194,25 @@
#pragma mark Construction

MVKFenceSitter::~MVKFenceSitter() {
lock_guard<mutex> lock(_lock);
for (auto& uf : _unsignaledFences) {
// Use copy of collection to avoid deadlocks with the fences if lock in place here when removing sitters
vector<MVKFence*> ufsCopy;
getUnsignaledFences(ufsCopy);
for (auto& uf : ufsCopy) {
uf->removeSitter(this);
}
}

// Fills the vector with the collection of unsignaled fences
void MVKFenceSitter::getUnsignaledFences(vector<MVKFence*>& fences) {
fences.clear();
fences.reserve(_unsignaledFences.size());

lock_guard<mutex> lock(_lock);
for (auto& uf : _unsignaledFences) {
fences.push_back(uf);
}
}


#pragma mark -
#pragma mark Support functions
Expand Down Expand Up @@ -231,7 +248,7 @@ VkResult mvkWaitForFences(uint32_t fenceCount,
// The thread dispatch is needed because even the sync portion of the async Metal compilation methods can take well
// over a second to return when a compiler failure occurs!
void MVKMetalCompiler::compile(unique_lock<mutex>& lock, dispatch_block_t block) {
MVKAssert( _startTime == 0, "%s compile occurred already in this instance. Instances of %s should only be used for a single compile activity.", _compilerType.c_str(), className().c_str());
MVKAssert( _startTime == 0, "%s compile occurred already in this instance. Instances of %s should only be used for a single compile activity.", _compilerType.c_str(), getClassName().c_str());
_startTime = _device->getPerformanceTimestamp();

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), block);
Expand All @@ -254,25 +271,26 @@ VkResult mvkWaitForFences(uint32_t fenceCount,
setConfigurationResult(mvkNotifyErrorWithText(VK_ERROR_INITIALIZATION_FAILED, "%s compile failed (error code %li):\n%s.", _compilerType.c_str(), (long)_compileError.code, _compileError.localizedDescription.UTF8String));
}

void MVKMetalCompiler::endCompile(NSError* compileError) {
// Returns whether the compilation came in late, after the compiler was destroyed.
bool MVKMetalCompiler::endCompile(NSError* compileError) {
_compileError = [compileError retain]; // retained
_isCompileDone = true;
_blocker.notify_all();
maybeDestroy();
return _isDestroyed;
}

void MVKMetalCompiler::destroy() {
if (markDestroyed()) { MVKBaseDeviceObject::destroy(); }
}

// Marks this object as destroyed, and returns whether the compilation is complete.
bool MVKMetalCompiler::markDestroyed() {
lock_guard<mutex> lock(_completionLock);

_isDestroyed = true;
maybeDestroy();
return _isCompileDone;
}

void MVKMetalCompiler::maybeDestroy() {
if (_isDestroyed && _isCompileDone) {
MVKBaseDeviceObject::destroy();
}
}

#pragma mark Construction

Expand Down
2 changes: 1 addition & 1 deletion MoltenVK/MoltenVK/Utility/MVKBaseObject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ using namespace std;
#pragma mark -
#pragma mark MVKBaseObject

string MVKBaseObject::className() {
string MVKBaseObject::getClassName() {
int status;
char* demangled = abi::__cxa_demangle(typeid(*this).name(), 0, 0, &status);
string clzName = demangled;
Expand Down
2 changes: 1 addition & 1 deletion MoltenVK/MoltenVK/Utility/MVKBaseObject.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ class MVKBaseObject {
public:

/** Returns the name of the class of which this object is an instance. */
std::string className();
std::string getClassName();

/** Destroys this object. Default behaviour simply deletes it. Subclasses may override to delay deletion. */
virtual void destroy() { delete this; }
Expand Down
8 changes: 8 additions & 0 deletions MoltenVK/MoltenVK/Utility/MVKOSExtensions.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,3 +71,11 @@ uint64_t mvkRecommendedMaxWorkingSetSize(id<MTLDevice> mtlDevice);
/** Populate the propertes with info about the GPU represented by the MTLDevice. */
void mvkPopulateGPUInfo(VkPhysicalDeviceProperties& devProps, id<MTLDevice> mtlDevice);

/** Ensures the block is executed on the main thread. */
inline void mvkDispatchToMainAndWait(dispatch_block_t block) {
if (NSThread.isMainThread) {
block();
} else {
dispatch_sync(dispatch_get_main_queue(), block);
}
}

0 comments on commit f3355d1

Please sign in to comment.