Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'intern/cycles/device/metal/util.mm')
-rw-r--r--intern/cycles/device/metal/util.mm218
1 files changed, 218 insertions, 0 deletions
diff --git a/intern/cycles/device/metal/util.mm b/intern/cycles/device/metal/util.mm
new file mode 100644
index 00000000000..763a37cb503
--- /dev/null
+++ b/intern/cycles/device/metal/util.mm
@@ -0,0 +1,218 @@
+/*
+ * Copyright 2021 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifdef WITH_METAL
+
+# include "device/metal/util.h"
+# include "device/metal/device_impl.h"
+# include "util/md5.h"
+# include "util/path.h"
+# include "util/string.h"
+# include "util/time.h"
+
+# include <pwd.h>
+# include <sys/shm.h>
+# include <time.h>
+
+CCL_NAMESPACE_BEGIN
+
+MetalGPUVendor MetalInfo::get_vendor_from_device_name(string const &device_name)
+{
+ if (device_name.find("Intel") != string::npos) {
+ return METAL_GPU_INTEL;
+ }
+ else if (device_name.find("AMD") != string::npos) {
+ return METAL_GPU_AMD;
+ }
+ else if (device_name.find("Apple") != string::npos) {
+ return METAL_GPU_APPLE;
+ }
+ return METAL_GPU_UNKNOWN;
+}
+
+bool MetalInfo::device_version_check(id<MTLDevice> device)
+{
+ /* Metal Cycles doesn't work correctly on macOS versions older than 12.0 */
+ if (@available(macos 12.0, *)) {
+ MetalGPUVendor vendor = get_vendor_from_device_name([[device name] UTF8String]);
+
+ /* Metal Cycles works on Apple Silicon GPUs at present */
+ return (vendor == METAL_GPU_APPLE);
+ }
+
+ return false;
+}
+
+void MetalInfo::get_usable_devices(vector<MetalPlatformDevice> *usable_devices)
+{
+ static bool first_time = true;
+# define FIRST_VLOG(severity) \
+ if (first_time) \
+ VLOG(severity)
+
+ usable_devices->clear();
+
+ NSArray<id<MTLDevice>> *allDevices = MTLCopyAllDevices();
+ for (id<MTLDevice> device in allDevices) {
+ string device_name;
+ if (!get_device_name(device, &device_name)) {
+ FIRST_VLOG(2) << "Failed to get device name, ignoring.";
+ continue;
+ }
+
+ static const char *forceIntelStr = getenv("CYCLES_METAL_FORCE_INTEL");
+ bool forceIntel = forceIntelStr ? (atoi(forceIntelStr) != 0) : false;
+ if (forceIntel && device_name.find("Intel") == string::npos) {
+ FIRST_VLOG(2) << "CYCLES_METAL_FORCE_INTEL causing non-Intel device " << device_name
+ << " to be ignored.";
+ continue;
+ }
+
+ if (!device_version_check(device)) {
+ FIRST_VLOG(2) << "Ignoring device " << device_name << " due to too old compiler version.";
+ continue;
+ }
+ FIRST_VLOG(2) << "Adding new device " << device_name << ".";
+ string hardware_id;
+ usable_devices->push_back(MetalPlatformDevice(device, device_name));
+ }
+ first_time = false;
+}
+
+bool MetalInfo::get_num_devices(uint32_t *num_devices)
+{
+ *num_devices = MTLCopyAllDevices().count;
+ return true;
+}
+
+uint32_t MetalInfo::get_num_devices()
+{
+ uint32_t num_devices;
+ if (!get_num_devices(&num_devices)) {
+ return 0;
+ }
+ return num_devices;
+}
+
+bool MetalInfo::get_device_name(id<MTLDevice> device, string *platform_name)
+{
+ *platform_name = [device.name UTF8String];
+ return true;
+}
+
+string MetalInfo::get_device_name(id<MTLDevice> device)
+{
+ string platform_name;
+ if (!get_device_name(device, &platform_name)) {
+ return "";
+ }
+ return platform_name;
+}
+
+id<MTLBuffer> MetalBufferPool::get_buffer(id<MTLDevice> device,
+ id<MTLCommandBuffer> command_buffer,
+ NSUInteger length,
+ MTLResourceOptions options,
+ const void *pointer,
+ Stats &stats)
+{
+ id<MTLBuffer> buffer;
+
+ MTLStorageMode storageMode = MTLStorageMode((options & MTLResourceStorageModeMask) >>
+ MTLResourceStorageModeShift);
+ MTLCPUCacheMode cpuCacheMode = MTLCPUCacheMode((options & MTLResourceCPUCacheModeMask) >>
+ MTLResourceCPUCacheModeShift);
+
+ buffer_mutex.lock();
+ for (auto entry = buffer_free_list.begin(); entry != buffer_free_list.end(); entry++) {
+ MetalBufferListEntry bufferEntry = *entry;
+
+ /* Check if buffer matches size and storage mode and is old enough to reuse */
+ if (bufferEntry.buffer.length == length && storageMode == bufferEntry.buffer.storageMode &&
+ cpuCacheMode == bufferEntry.buffer.cpuCacheMode) {
+ buffer = bufferEntry.buffer;
+ buffer_free_list.erase(entry);
+ bufferEntry.command_buffer = command_buffer;
+ buffer_in_use_list.push_back(bufferEntry);
+ buffer_mutex.unlock();
+
+ /* Copy over data */
+ if (pointer) {
+ memcpy(buffer.contents, pointer, length);
+ if (bufferEntry.buffer.storageMode == MTLStorageModeManaged) {
+ [buffer didModifyRange:NSMakeRange(0, length)];
+ }
+ }
+
+ return buffer;
+ }
+ }
+ // NSLog(@"Creating buffer of length %lu (%lu)", length, frameCount);
+ if (pointer) {
+ buffer = [device newBufferWithBytes:pointer length:length options:options];
+ }
+ else {
+ buffer = [device newBufferWithLength:length options:options];
+ }
+
+ MetalBufferListEntry buffer_entry(buffer, command_buffer);
+
+ stats.mem_alloc(buffer.allocatedSize);
+
+ total_temp_mem_size += buffer.allocatedSize;
+ buffer_in_use_list.push_back(buffer_entry);
+ buffer_mutex.unlock();
+
+ return buffer;
+}
+
+void MetalBufferPool::process_command_buffer_completion(id<MTLCommandBuffer> command_buffer)
+{
+ assert(command_buffer);
+ thread_scoped_lock lock(buffer_mutex);
+ /* Release all buffers that have not been recently reused back into the free pool */
+ for (auto entry = buffer_in_use_list.begin(); entry != buffer_in_use_list.end();) {
+ MetalBufferListEntry buffer_entry = *entry;
+ if (buffer_entry.command_buffer == command_buffer) {
+ entry = buffer_in_use_list.erase(entry);
+ buffer_entry.command_buffer = nil;
+ buffer_free_list.push_back(buffer_entry);
+ }
+ else {
+ entry++;
+ }
+ }
+}
+
+MetalBufferPool::~MetalBufferPool()
+{
+ thread_scoped_lock lock(buffer_mutex);
+ /* Release all buffers that have not been recently reused */
+ for (auto entry = buffer_free_list.begin(); entry != buffer_free_list.end();) {
+ MetalBufferListEntry buffer_entry = *entry;
+
+ id<MTLBuffer> buffer = buffer_entry.buffer;
+ // NSLog(@"Releasing buffer of length %lu (%lu) (%lu outstanding)", buffer.length, frameCount,
+ // bufferFreeList.size());
+ total_temp_mem_size -= buffer.allocatedSize;
+ [buffer release];
+ entry = buffer_free_list.erase(entry);
+ }
+}
+
+CCL_NAMESPACE_END
+
+#endif /* WITH_METAL */