diff --git a/intern/cycles/device/metal/bvh.h b/intern/cycles/device/metal/bvh.h index 75d8e326941..46c810c9b72 100644 --- a/intern/cycles/device/metal/bvh.h +++ b/intern/cycles/device/metal/bvh.h @@ -19,6 +19,9 @@ class BVHMetal : public BVH { API_AVAILABLE(macos(11.0)) id accel_struct = nil; + API_AVAILABLE(macos(11.0)) + id null_BLAS = nil; + API_AVAILABLE(macos(11.0)) vector> blas_array; diff --git a/intern/cycles/device/metal/bvh.mm b/intern/cycles/device/metal/bvh.mm index a4de673a0f5..ba86e80f587 100644 --- a/intern/cycles/device/metal/bvh.mm +++ b/intern/cycles/device/metal/bvh.mm @@ -124,6 +124,66 @@ BVHMetal::~BVHMetal() stats.mem_free(accel_struct.allocatedSize); [accel_struct release]; } + + if (null_BLAS) { + [null_BLAS release]; + } + } +} + +id make_null_BLAS(id device, id queue) +{ + if (@available(macos 12.0, *)) { + MTLResourceOptions storage_mode = MTLResourceStorageModeManaged; + if (device.hasUnifiedMemory) { + storage_mode = MTLResourceStorageModeShared; + } + + id nullBuf = [device newBufferWithLength:0 options:storage_mode]; + + /* Create an acceleration structure. */ + MTLAccelerationStructureTriangleGeometryDescriptor *geomDesc = + [MTLAccelerationStructureTriangleGeometryDescriptor descriptor]; + geomDesc.vertexBuffer = nullBuf; + geomDesc.vertexBufferOffset = 0; + geomDesc.vertexStride = sizeof(float3); + geomDesc.indexBuffer = nullBuf; + geomDesc.indexBufferOffset = 0; + geomDesc.indexType = MTLIndexTypeUInt32; + geomDesc.triangleCount = 0; + geomDesc.intersectionFunctionTableOffset = 0; + geomDesc.opaque = true; + geomDesc.allowDuplicateIntersectionFunctionInvocation = false; + + MTLPrimitiveAccelerationStructureDescriptor *accelDesc = + [MTLPrimitiveAccelerationStructureDescriptor descriptor]; + accelDesc.geometryDescriptors = @[ geomDesc ]; + accelDesc.usage |= MTLAccelerationStructureUsageExtendedLimits; + + MTLAccelerationStructureSizes accelSizes = [device + accelerationStructureSizesWithDescriptor:accelDesc]; + id accel_struct = [device + newAccelerationStructureWithSize:accelSizes.accelerationStructureSize]; + id scratchBuf = [device newBufferWithLength:accelSizes.buildScratchBufferSize + options:MTLResourceStorageModePrivate]; + id sizeBuf = [device newBufferWithLength:8 options:MTLResourceStorageModeShared]; + id accelCommands = [queue commandBuffer]; + id accelEnc = + [accelCommands accelerationStructureCommandEncoder]; + [accelEnc buildAccelerationStructure:accel_struct + descriptor:accelDesc + scratchBuffer:scratchBuf + scratchBufferOffset:0]; + [accelEnc endEncoding]; + [accelCommands commit]; + [accelCommands waitUntilCompleted]; + + /* free temp resources */ + [scratchBuf release]; + [nullBuf release]; + [sizeBuf release]; + + return accel_struct; } } @@ -1005,7 +1065,7 @@ bool BVHMetal::build_TLAS(Progress &progress, int blas_index = (int)[all_blas count]; instance_mapping[blas] = blas_index; if (@available(macos 12.0, *)) { - [all_blas addObject:blas->accel_struct]; + [all_blas addObject:(blas ? blas->accel_struct : null_BLAS)]; } return blas_index; } @@ -1052,22 +1112,18 @@ bool BVHMetal::build_TLAS(Progress &progress, if (!blas || !blas->accel_struct) { /* Place a degenerate instance, to ensure [[instance_id]] equals ob->get_device_index() * in our intersection functions */ - if (motion_blur) { - MTLAccelerationStructureMotionInstanceDescriptor *instances = - (MTLAccelerationStructureMotionInstanceDescriptor *)[instanceBuf contents]; - MTLAccelerationStructureMotionInstanceDescriptor &desc = instances[instance_index++]; - memset(&desc, 0x00, sizeof(desc)); + blas = nullptr; + + /* Workaround for issue in macOS <= 14.1: Insert degenerate BLAS instead of zero-filling + * the descriptor. */ + if (!null_BLAS) { + null_BLAS = make_null_BLAS(device, queue); } - else { - MTLAccelerationStructureUserIDInstanceDescriptor *instances = - (MTLAccelerationStructureUserIDInstanceDescriptor *)[instanceBuf contents]; - MTLAccelerationStructureUserIDInstanceDescriptor &desc = instances[instance_index++]; - memset(&desc, 0x00, sizeof(desc)); - } - blas_array.push_back(nil); - continue; + blas_array.push_back(null_BLAS); + } + else { + blas_array.push_back(blas->accel_struct); } - blas_array.push_back(blas->accel_struct); uint32_t accel_struct_index = get_blas_index(blas);