Class MPSAccelerationStructure

  • All Implemented Interfaces:
    NSCoding, NSCopying, NSSecureCoding, NSObject
    Direct Known Subclasses:
    MPSInstanceAccelerationStructure, MPSPolygonAccelerationStructure

    public class MPSAccelerationStructure
    extends MPSKernel
    implements NSSecureCoding, NSCopying
    A data structure built over geometry used to accelerate ray tracing Do not use this base class directly. Use one of the derived classes instead. The general pattern for creating an acceleration structure is as follows. First, create the acceleration structure: [@code] MPSTriangleAccelerationStructure *accelerationStructure = nil; accelerationStructure = [[MPSTriangleAccelerationStructure alloc] initWithDevice:device]; [@endcode] Then, assign values to the acceleration structure's properties: [@code] accelerationStructure.vertexBuffer = vertexBuffer; accelerationStructure.triangleCount = triangleCount; [@endcode] Finally, the acceleration structure must be built: [@code] [accelerationStructure rebuild]; [@endcode] The acceleration structure can then be used to encode ray intersection tests with an MPSRayIntersector: [@code] [raytracer encodeIntersectionToCommandBuffer:commandBuffer intersectionType:MPSIntersectionTypeNearest rayBuffer:rayBuffer rayBufferOffset:0 intersectionBuffer:intersectionBuffer intersectionBufferOffset:0 rayCount:rayCount accelerationStructure:accelerationStructure]; [@endcode] Asynchronous Acceleration Structure Builds: Rebuilding an acceleration structure is an expensive operation. Note that there is also a method to rebuild the acceleration structure asynchronously to avoid blocking the main thread. [@code] [accelerationStructure rebuildWithCompletionHandler:^(MPSAccelerationStructure *accel) { // Kick off ray intersection work }]; [@endcode] Streaming Geometry Updates: It is generally safe to change buffer properties such as the vertex buffer after intersection tests have been encoded into a command buffer, but the contents of those buffers cannot be safely changed by the CPU until the command buffer has finished executing on the GPU. It is also not safe to rebuild the acceleration structure until the command buffer has completed. If the CPU needs to stream geometry updates to the GPU, ensure the vertex and other buffers are double or triple buffered. [@code] #define MAX_ASYNC_OPERATIONS 3 // Initialization: // Create a semaphore with the maximum number of asynchronous operations in flight dispatch_semaphore_t asyncOperationSemaphore = dispatch_semaphore_create(MAX_ASYNC_OPERATIONS); // Create an acceleration structure for each vertex buffer range NSMutableArray *accelerationStructures = [NSMutableArray array]; NSUInteger vertexBufferLength = sizeof(float3) * vertexCount * MAX_ASYNC_OPERATIONS; id vertexBuffer = [device newBufferWithLength:vertexBufferLength options:MTLResourceStorageModeManaged]; for (NSUInteger i = 0; i < MAX_ASYNC_OPERATIONS; i++) { MPSTriangleAccelerationStructure *accel = nil; accel = [[MPSTriangleAccelerationStructure alloc] initWithDevice:device]; // Configure acceleration structure accel.vertexBuffer = vertexBuffer; accel.vertexBufferOffset = i * sizeof(float3) * vertexCount; [accelerationStructures addObject:accel]; } NSUInteger asyncOperationIndex = 0; // Encode intersection testing: // Wait until there is a free acceleration structure dispatch_semaphore_wait(asyncOperationSemaphore, DISPATCH_TIME_FOREVER); MPSTriangleAccelerationStructure *accel = accelerationStructures[asyncOperationIndex]; asyncOperationIndex = (asyncOperationIndex + 1) % MAX_ASYNC_OPERATIONS; float3 *vertices = (float3 *)((uint8_t *)vertexBuffer.contents + accel.vertexBufferOffset); // Update vertices MPSDidModifyRange(vertexBuffer, NSMakeRange(accel.vertexBufferOffset, sizeof(float3) * vertexCount)); // Rebuild the acceleration structure [accel rebuild]; // Encode actual intersection work [raytracer encodeIntersectionToCommandBuffer:commandBuffer intersectionType:MPSIntersectionTypeNearest rayBuffer:rayBuffer rayBufferOffset:rayBufferOffset intersectionBuffer:intersectionBuffer intersectionBufferOffset:intersectionBufferOffset rayCount:rayCount accelerationStructure:accel]; // Register a completion handler to run when the GPU finishes executing [commandBuffer addCompletedHandler:^(id commandBuffer) { Intersection *intersections = (Intersection *)((uint8_t *)intersectionBuffer.contents + intersectionBufferOffset); // Process intersections // Signal that the acceleration structure is now available for reuse dispatch_semaphore_signal(asyncOperationSemaphore); }]; // Commit the command buffer to allow the GPU to start executing [commandBuffer commit]; [@endcode] Refitting acceleration structures: If geometry has only moved slightly and not added or removed from the scene, it can be much faster to refit the existing topology of an acceleration structure to the new geometry than to rebuild the acceleration structure from scratch. Refitting can also be pipelined with other GPU work such as intersection testing. If the geometry is transformed entirely on the GPU, it is not necessary to use double or triple buffering. For example: [@code] id commandBuffer = [commandQueue commandBuffer]; id encoder = [commandBuffer computeCommandEncoder]; [encoder setBuffer:untransformedVertexBuffer offset:0 atIndex:0]; [encoder setBuffer:accelerationStructure.vertexBuffer offset:accelerationStructure.vertexBufferOffset atIndex:1]; [encoder setBuffer:transformationMatrices offset:0 atIndex:2]; [encoder setComputePipelineState:transformVerticesPipeline]; [encoder dispatchThreads:MTLSizeMake(accelerationStructure.triangleCount * 3, 1, 1) threadsPerThreadgroup:MTLSizeMake(64, 1, 1)]; [encoder endEncoding]; [accelerationStructure encodeRefitToCommandBuffer:commandBuffer]; [commandBuffer commit]; [@endcode] Serializing Acceleration Structures: Instead of rebuilding acceleration structures from scratch they can be built offline, serialized, and reloaded at runtime using the NSSecureCoding protocol: [@code] // Build time: NSError *error = nil; NSData *data = [NSKeyedArchiver archivedDataWithRootObject:accel requiringSecureCoding:YES error:&error]; if (!data) NSLog(@"Error archiving MPSAccelerationStructure: %@", error.localizedDescription); // Runtime: MPSTriangleAccelerationStructure *accel; accel = [NSKeyedUnarchiver unarchivedObjectOfClass:[MPSTriangleAccelerationStructure class] fromData:data error:&error]; if (!accel) NSLog(@"Error unarchiving MPSAccelerationStructure: %@", error.localizedDescription); [@endcode] Copying Acceleration Structures: Acceleration structures can be copied using the NSCopying protocol, even to a different Metal device. This can be used for multi-GPU raytracing. Buffer properties are not copied to the new acceleration structure. These buffers must instead be copied to the new Metal device and assigned to the new acceleration structure. For example: [@code] MPSTriangleAccelerationStructure *copy = [accelerationStructure copyWithZone:nil device:newDevice]; copy.vertexBuffer = [self copyBuffer:accelerationStructure.vertexBuffer withDevice:newDevice]; [@endcode] Performance Guidelines: - Provide accurate acceleration structure hints: if an acceleration structure does not require support for refitting, a higher quality construction algorithm can be used. However, if an acceleration structure must be rebuilt frequently, a lower quality but higher performance construction algorithm can be used. - Consider refitting existing acceleration structures rather than rebuilding them from scratch. This is typically much faster and can result in a reasonably high quality tree if the geometry has not been modified dramatically. Refitting can also be pipelined with other GPU work. If objects have been added to or removed from the scene, it is typically necessary to rebuild the acceleration structure rather than refit it. - Rebuild acceleration structures asynchronously when possible to avoid blocking the main thread. Consider presenting a UI indicating that work is happening in the background while allowing the user to consider interacting with your application. - If you need to mix intersection testing with acceleration structure builds (e.g. if the user is interactively editing the scene while rendering or if objects are moving significantly) consider allocating two independent acceleration structures that refer to two copies of the scene data. Then, asynchronously rebuild one acceleration structure while the other one is used for rendering. Once the rebuild has completed, swap the acceleration structures. The intermediate frames could be filled by refitting the rendering acceleration structure until the rebuilt acceleration structure is ready. - When running in Xcode, disable "Enable Backtrace Recording" in your scheme settings. Enabling this setting can significantly increase acceleration structure build time. - Consider using quadrilaterals instead of triangles to represent your geometry. The cost of intersecting a quadrilateral is typically less than the cost of intersecting two triangles, so quadrilaterals can improve performance. Quadrilaterals also typically require 30-40% less memory than triangles including vertex data and internal buffers allocated by the acceleration structure. Whether quadrilaterals improve or hurt performance can depend on the geometry and ray distribution, so you should choose whichever performs better for your application. Thread Safety: MPSAccelerationStructures are generally not thread safe. Changing properties and rebuilding acceleration structures from multiple threads result in undefined behavior. However, it is safe to encode intersection tests with a single acceleration structure from multiple threads as long as each thread uses its own MPSRayIntersector.
    • Constructor Detail

      • MPSAccelerationStructure

        protected MPSAccelerationStructure​(org.moe.natj.general.Pointer peer)
    • Method Detail

      • accessInstanceVariablesDirectly

        public static boolean accessInstanceVariablesDirectly()
      • allocWithZone

        public static java.lang.Object allocWithZone​(org.moe.natj.general.ptr.VoidPtr zone)
      • automaticallyNotifiesObserversForKey

        public static boolean automaticallyNotifiesObserversForKey​(java.lang.String key)
      • cancelPreviousPerformRequestsWithTarget

        public static void cancelPreviousPerformRequestsWithTarget​(java.lang.Object aTarget)
      • cancelPreviousPerformRequestsWithTargetSelectorObject

        public static void cancelPreviousPerformRequestsWithTargetSelectorObject​(java.lang.Object aTarget,
                                                                                 org.moe.natj.objc.SEL aSelector,
                                                                                 java.lang.Object anArgument)
      • classFallbacksForKeyedArchiver

        public static NSArray<java.lang.String> classFallbacksForKeyedArchiver()
      • classForKeyedUnarchiver

        public static org.moe.natj.objc.Class classForKeyedUnarchiver()
      • copyWithZoneDevice

        public java.lang.Object copyWithZoneDevice​(org.moe.natj.general.ptr.VoidPtr zone,
                                                   MTLDevice device)
        Create a a copy of this acceleration structure The acceleration structure may be copied to a different Metal device. Buffer properties of the acceleration structure such as the vertex buffer, instance, buffer, etc. are set to nil. Copy these buffers to the new Metal device and assign them to the new acceleration structure instead. Do not copy the acceleration structure until any prior refit or rebuild operations have completed.
        Overrides:
        copyWithZoneDevice in class MPSKernel
        Parameters:
        zone - This parameter is ignored. Memory zones are no longer used by Objective-C.
        device - New Metal device
        Returns:
        a pointer to a copy of this MPSKernel. This will fail, returning nil if the device is not supported. Devices must be MTLFeatureSet_iOS_GPUFamily2_v1 or later.
      • copyWithZoneGroup

        public java.lang.Object copyWithZoneGroup​(org.moe.natj.general.ptr.VoidPtr zone,
                                                  MPSAccelerationStructureGroup group)
        Create a a copy of this acceleration structure The acceleration structure may be copied with a different acceleration structure group. Buffer properties of the acceleration structure such as the vertex buffer, instance buffer, etc. are set to nil. Copy these buffers with the new Metal device and assign them to the new acceleration structure instead. Do not copy the acceleration structure until any prior refit or rebuild operations have completed.
        Parameters:
        zone - This parameter is ignored. Memory zones are no longer used by Objective-C.
        group - New acceleration structure group
      • debugDescription_static

        public static java.lang.String debugDescription_static()
      • description_static

        public static java.lang.String description_static()
      • encodeRefitToCommandBuffer

        public void encodeRefitToCommandBuffer​(MTLCommandBuffer commandBuffer)
        Refit the existing acceleration structure to new data This method is used to refit the acceleration structure to new vertex data, index data, instance data, etc. while preserving the existing acceleration structure topology. This is typically much faster than a full rebuild of the acceleration structure. Refitting can also be pipelined with other GPU work such as ray intersection. Until the command buffer has completed, the acceleration structure cannot be copied, encoded with NSSecureCoding, or rebuilt. Changes to properties such as the triangle count or instance count might not be reflected. These changes require that the acceleration structure be rebuilt instead. The acceleration structure must be rebuilt at least once before this method can be called.
      • hash_static

        public static long hash_static()
      • initWithCoderDevice

        public MPSAccelerationStructure initWithCoderDevice​(NSCoder aDecoder,
                                                            java.lang.Object device)
        Initialize the acceleration structure with an NSCoder and a Metal device. Buffer properties such as the vertex buffer, instance buffer, etc. are set to nil. Encode and decode these buffers along with the acceleration structure instead.
        Overrides:
        initWithCoderDevice in class MPSKernel
        Parameters:
        aDecoder - The NSCoder subclass with your serialized MPSKernel
        device - The MTLDevice on which to make the MPSKernel
        Returns:
        A new MPSKernel object, or nil if failure.
      • initWithCoderGroup

        public MPSAccelerationStructure initWithCoderGroup​(NSCoder aDecoder,
                                                           MPSAccelerationStructureGroup group)
        Initialize the acceleration structure with an NSCoder and an acceleration structure group, if the acceleration structure will be used in an instance hierarchy. All acceleration structures in the instance hierarchy must share the same group. Buffer properties such as the vertex buffer, instance buffer, etc. are set to nil. Encode and decode these buffers along with the acceleration structure instead.
      • initWithDevice

        public MPSAccelerationStructure initWithDevice​(java.lang.Object device)
        Initialize the acceleration structure with a Metal device
        Overrides:
        initWithDevice in class MPSKernel
        Parameters:
        device - The device that the filter will be used on. May not be NULL.
        Returns:
        a pointer to the newly initialized object. This will fail, returning nil if the device is not supported. Devices must be MTLFeatureSet_iOS_GPUFamily2_v1 or later.
      • initWithGroup

        public MPSAccelerationStructure initWithGroup​(MPSAccelerationStructureGroup group)
        Initialize the acceleration structure with an acceleration structure group, if the acceleration structure will be used in an instance hierarchy. The Metal device is determined from the acceleration structure group. All acceleration structures in the instance hierarchy must share the same group.
      • instanceMethodSignatureForSelector

        public static NSMethodSignature instanceMethodSignatureForSelector​(org.moe.natj.objc.SEL aSelector)
      • instancesRespondToSelector

        public static boolean instancesRespondToSelector​(org.moe.natj.objc.SEL aSelector)
      • isSubclassOfClass

        public static boolean isSubclassOfClass​(org.moe.natj.objc.Class aClass)
      • keyPathsForValuesAffectingValueForKey

        public static NSSet<java.lang.String> keyPathsForValuesAffectingValueForKey​(java.lang.String key)
      • new_objc

        public static java.lang.Object new_objc()
      • rebuild

        public void rebuild()
        Rebuild the acceleration structure This method must be called before any intersection tests can be scheduled with this acceleration structure. Before calling this method, fill out the properties of the acceleration structure such as vertex buffer, instance buffer, etc. The acceleration structure should be rebuilt when its contents (e.g. vertices in a triangle acceleration structure) have been modified significantly and must be rebuilt when properties such as triangle count, vertex stride, etc. have changed. When the contents of the acceleration structure have only been modified slightly, it may be cheaper to refit the acceleration structure instead. This method blocks until the acceleration structure has been rebuilt. Until the rebuild has completed, the acceleration structure cannot be copied, encoded with NSSecureCoding, rebuilt, or refit. Before this method can be called, any pending GPU writes to the vertex buffer, index buffer, etc. must be completed (and, for managed buffers, synchronized). Any prior intersection tests must also be completed before the acceleration structure can be rebuilt.
      • rebuildWithCompletionHandler

        public void rebuildWithCompletionHandler​(MPSAccelerationStructure.Block_rebuildWithCompletionHandler completionHandler)
        Rebuild the acceleration structure asynchronously This method must be called before any intersection tests can be scheduled with this acceleration structure. Before calling this method, fill out the properties of the acceleration structure such as vertex buffer, instance buffer, etc. The acceleration structure should be rebuilt when its contents (e.g. vertices in a triangle acceleration structure) have been modified significantly and must be rebuilt when properties such as triangle count, vertex stride, etc. have changed. When the contents of the acceleration structure have only been modified slightly, it may be cheaper to refit the acceleration structure instead. Until the rebuild has completed, the acceleration structure cannot be copied, encoded with NSSecureCoding, rebuilt, or refit. Before this method can be called, any pending GPU writes to the vertex buffer, index buffer, etc. must be completed (and, for managed buffers, synchronized). Any prior intersection tests must also be completed before the acceleration structure can be rebuilt.
      • resolveClassMethod

        public static boolean resolveClassMethod​(org.moe.natj.objc.SEL sel)
      • resolveInstanceMethod

        public static boolean resolveInstanceMethod​(org.moe.natj.objc.SEL sel)
      • setUsage

        public void setUsage​(long value)
        Acceleration structure usage options. Changes to this property require rebuilding the acceleration structure. Defaults to MPSAccelerationStructureUsageNone.
      • setVersion_static

        public static void setVersion_static​(long aVersion)
      • status

        public long status()
        Status indicating whether the acceleration structure has finished building
      • superclass_static

        public static org.moe.natj.objc.Class superclass_static()
      • supportsSecureCoding

        public static boolean supportsSecureCoding()
      • _supportsSecureCoding

        public boolean _supportsSecureCoding()
        Description copied from interface: NSSecureCoding
        This property must return YES on all classes that allow secure coding. Subclasses of classes that adopt NSSecureCoding and override initWithCoder: must also override this method and return YES. The Secure Coding Guide should be consulted when writing methods that decode data.
        Specified by:
        _supportsSecureCoding in interface NSSecureCoding
        Overrides:
        _supportsSecureCoding in class MPSKernel
      • usage

        public long usage()
        Acceleration structure usage options. Changes to this property require rebuilding the acceleration structure. Defaults to MPSAccelerationStructureUsageNone.
      • version_static

        public static long version_static()