MVKMTLBufferAllocation: Mark temp buffers as volatile.

They are not expected to be useful beyond the commands that use them,
but they take up memory nonetheless. This is exactly the use case
purgeability was designed for. Tell the system that it's OK to reclaim
their memory if necessary.

Doing this every time the buffer is used will cause the purgeable state
to be reset from `MTLPurgeableStateEmpty`, in case the system really did
reclaim their memory.

In accordance with Apple's advice, lock the pages for the buffer when
loading it, so the memory isn't pulled out from under us.
diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm b/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm
index be7718d..5bee3c0 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm
+++ b/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm
@@ -28,6 +28,7 @@
 #include "MVKEnvironment.h"
 #include "mvk_datatypes.hpp"
 #include <algorithm>
+#include <sys/mman.h>
 
 
 #pragma mark -
@@ -1615,7 +1616,10 @@
 
     // Copy data to the source MTLBuffer
     MVKMTLBufferAllocation* srcMTLBufferAlloc = (MVKMTLBufferAllocation*)cmdEncoder->getCommandEncodingPool()->acquireMTLBufferAllocation(_dataSize);
-    memcpy(srcMTLBufferAlloc->getContents(), _srcDataCache.data(), _dataSize);
+    void* pBuffData = srcMTLBufferAlloc->getContents();
+    mlock(pBuffData, _dataSize);
+    memcpy(pBuffData, _srcDataCache.data(), _dataSize);
+    munlock(pBuffData, _dataSize);
 
     [mtlBlitEnc copyFromBuffer: srcMTLBufferAlloc->_mtlBuffer
                   sourceOffset: srcMTLBufferAlloc->_offset
diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm b/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm
index 6b41c3a..3f8706b 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm
+++ b/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm
@@ -26,6 +26,7 @@
 #include "MTLRenderPassDescriptor+MoltenVK.h"
 #include "MVKCmdDraw.h"
 #include "MVKCmdRenderPass.h"
+#include <sys/mman.h>
 
 using namespace std;
 
@@ -675,7 +676,9 @@
 const MVKMTLBufferAllocation* MVKCommandEncoder::copyToTempMTLBufferAllocation(const void* bytes, NSUInteger length) {
     const MVKMTLBufferAllocation* mtlBuffAlloc = getTempMTLBuffer(length);
     void* pBuffData = mtlBuffAlloc->getContents();
+    mlock(pBuffData, length);
     memcpy(pBuffData, bytes, length);
+    munlock(pBuffData, length);
 
     return mtlBuffAlloc;
 }
diff --git a/MoltenVK/MoltenVK/Commands/MVKMTLBufferAllocation.mm b/MoltenVK/MoltenVK/Commands/MVKMTLBufferAllocation.mm
index e1e9f7c..606b5f7 100644
--- a/MoltenVK/MoltenVK/Commands/MVKMTLBufferAllocation.mm
+++ b/MoltenVK/MoltenVK/Commands/MVKMTLBufferAllocation.mm
@@ -82,7 +82,11 @@
     // Convert max length to the next power-of-two exponent to use as a lookup
     NSUInteger p2Exp = mvkPowerOfTwoExponent(length);
 	MVKMTLBufferAllocationPool* pRP = _regionPools[p2Exp];
-	return _makeThreadSafe ? pRP->acquireObjectSafely() : pRP->acquireObject();
+	const MVKMTLBufferAllocation* region = _makeThreadSafe ? pRP->acquireObjectSafely() : pRP->acquireObject();
+	if (region) {
+		[region->_mtlBuffer setPurgeableState: MTLPurgeableStateVolatile];
+	}
+	return region;
 }
 
 MVKMTLBufferAllocator::MVKMTLBufferAllocator(MVKDevice* device, NSUInteger maxRegionLength, bool makeThreadSafe) : MVKBaseDeviceObject(device) {
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKQueryPool.mm b/MoltenVK/MoltenVK/GPUObjects/MVKQueryPool.mm
index 86fb43f..db18657 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKQueryPool.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKQueryPool.mm
@@ -23,6 +23,7 @@
 #include "MVKCommandEncodingPool.h"
 #include "MVKOSExtensions.h"
 #include "MVKFoundation.h"
+#include <sys/mman.h>
 
 using namespace std;
 
@@ -220,7 +221,11 @@
 
 id<MTLBuffer> MVKTimestampQueryPool::getResultBuffer(MVKCommandEncoder* cmdEncoder, uint32_t firstQuery, uint32_t queryCount, NSUInteger& offset) {
 	const MVKMTLBufferAllocation* tempBuff = cmdEncoder->getTempMTLBuffer(queryCount * _queryElementCount * sizeof(uint64_t));
-	memcpy(tempBuff->getContents(), &_timestamps[firstQuery], queryCount * _queryElementCount * sizeof(uint64_t));
+	void* pBuffData = tempBuff->getContents();
+	size_t size = queryCount * _queryElementCount * sizeof(uint64_t);
+	mlock(pBuffData, size);
+	memcpy(pBuffData, &_timestamps[firstQuery], size);
+	munlock(pBuffData, size);
 	offset = tempBuff->_offset;
 	return tempBuff->_mtlBuffer;
 }