public class MPSAccelerationStructure extends MPSKernel implements NSSecureCoding, NSCopying
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
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
// 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
id
[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.
| Modifier and Type | Class and Description |
|---|---|
static interface |
MPSAccelerationStructure.Block_rebuildWithCompletionHandler |
NSObject.Function_instanceMethodForSelector_ret, NSObject.Function_methodForSelector_ret| Modifier | Constructor and Description |
|---|---|
protected |
MPSAccelerationStructure(org.moe.natj.general.Pointer peer) |
| Modifier and Type | Method and Description |
|---|---|
boolean |
_supportsSecureCoding()
This property must return YES on all classes that allow secure coding.
|
static boolean |
accessInstanceVariablesDirectly() |
static MPSAccelerationStructure |
alloc() |
static MPSAccelerationStructure |
allocWithZone(org.moe.natj.general.ptr.VoidPtr zone) |
static boolean |
automaticallyNotifiesObserversForKey(java.lang.String key) |
static void |
cancelPreviousPerformRequestsWithTarget(java.lang.Object aTarget) |
static void |
cancelPreviousPerformRequestsWithTargetSelectorObject(java.lang.Object aTarget,
org.moe.natj.objc.SEL aSelector,
java.lang.Object anArgument) |
static NSArray<java.lang.String> |
classFallbacksForKeyedArchiver() |
static org.moe.natj.objc.Class |
classForKeyedUnarchiver() |
java.lang.Object |
copyWithZone(org.moe.natj.general.ptr.VoidPtr zone) |
MPSAccelerationStructure |
copyWithZoneDevice(org.moe.natj.general.ptr.VoidPtr zone,
MTLDevice device)
Create a a copy of this acceleration structure
|
MPSAccelerationStructure |
copyWithZoneGroup(org.moe.natj.general.ptr.VoidPtr zone,
MPSAccelerationStructureGroup group)
Create a a copy of this acceleration structure
|
static java.lang.String |
debugDescription_static() |
static java.lang.String |
description_static() |
void |
encodeRefitToCommandBuffer(MTLCommandBuffer commandBuffer)
Refit the existing acceleration structure to new data
|
void |
encodeWithCoder(NSCoder coder) |
MPSAccelerationStructureGroup |
group()
The group this acceleration structure was created with
|
static long |
hash_static() |
MPSAccelerationStructure |
init() |
MPSAccelerationStructure |
initWithCoder(NSCoder coder)
NS_DESIGNATED_INITIALIZER
|
MPSAccelerationStructure |
initWithCoderDevice(NSCoder aDecoder,
java.lang.Object device)
Initialize the acceleration structure with an NSCoder and a Metal device.
|
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.
|
MPSAccelerationStructure |
initWithDevice(java.lang.Object device)
Initialize the acceleration structure with a Metal device
|
MPSAccelerationStructure |
initWithGroup(MPSAccelerationStructureGroup group)
Initialize the acceleration structure with an acceleration structure group, if the
acceleration structure will be used in an instance hierarchy.
|
static NSObject.Function_instanceMethodForSelector_ret |
instanceMethodForSelector(org.moe.natj.objc.SEL aSelector) |
static NSMethodSignature |
instanceMethodSignatureForSelector(org.moe.natj.objc.SEL aSelector) |
static boolean |
instancesRespondToSelector(org.moe.natj.objc.SEL aSelector) |
static boolean |
isSubclassOfClass(org.moe.natj.objc.Class aClass) |
static NSSet<java.lang.String> |
keyPathsForValuesAffectingValueForKey(java.lang.String key) |
static MPSAccelerationStructure |
new_objc() |
void |
rebuild()
Rebuild the acceleration structure
|
void |
rebuildWithCompletionHandler(MPSAccelerationStructure.Block_rebuildWithCompletionHandler completionHandler)
Rebuild the acceleration structure asynchronously
|
static boolean |
resolveClassMethod(org.moe.natj.objc.SEL sel) |
static boolean |
resolveInstanceMethod(org.moe.natj.objc.SEL sel) |
void |
setUsage(long value)
Acceleration structure usage options.
|
static void |
setVersion_static(long aVersion) |
long |
status()
Status indicating whether the acceleration structure has finished building
|
static org.moe.natj.objc.Class |
superclass_static() |
static boolean |
supportsSecureCoding() |
long |
usage()
Acceleration structure usage options.
|
static long |
version_static() |
device, label, options, setLabel, setOptionsaccessibilityActivate, accessibilityActivationPoint, accessibilityAssistiveTechnologyFocusedIdentifiers, accessibilityAttributedHint, accessibilityAttributedLabel, accessibilityAttributedUserInputLabels, accessibilityAttributedValue, accessibilityContainerType, accessibilityCustomActions, accessibilityCustomRotors, accessibilityDecrement, accessibilityDragSourceDescriptors, accessibilityDropPointDescriptors, accessibilityElementAtIndex, accessibilityElementCount, accessibilityElementDidBecomeFocused, accessibilityElementDidLoseFocus, accessibilityElementIsFocused, accessibilityElements, accessibilityElementsHidden, accessibilityFrame, accessibilityHint, accessibilityIncrement, accessibilityLabel, accessibilityLanguage, accessibilityNavigationStyle, accessibilityPath, accessibilityPerformEscape, accessibilityPerformMagicTap, accessibilityRespondsToUserInteraction, accessibilityScroll, accessibilityTextualContext, accessibilityTraits, accessibilityUserInputLabels, accessibilityValue, accessibilityViewIsModal, addObserverForKeyPathOptionsContext, attemptRecoveryFromErrorOptionIndex, attemptRecoveryFromErrorOptionIndexDelegateDidRecoverSelectorContextInfo, autoContentAccessingProxy, awakeAfterUsingCoder, awakeFromNib, class_objc, classForCoder, classForKeyedArchiver, copy, dealloc, debugDescription, description, dictionaryWithValuesForKeys, didChangeValueForKey, didChangeValueForKeyWithSetMutationUsingObjects, didChangeValuesAtIndexesForKey, doesNotRecognizeSelector, fileManagerShouldProceedAfterError, fileManagerWillProcessPath, finalize_objc, forwardingTargetForSelector, forwardInvocation, hash, indexOfAccessibilityElement, isAccessibilityElement, isEqual, isKindOfClass, isMemberOfClass, isProxy, methodForSelector, methodSignatureForSelector, mutableArrayValueForKey, mutableArrayValueForKeyPath, mutableCopy, mutableOrderedSetValueForKey, mutableOrderedSetValueForKeyPath, mutableSetValueForKey, mutableSetValueForKeyPath, observationInfo, observeValueForKeyPathOfObjectChangeContext, performSelector, performSelectorInBackgroundWithObject, performSelectorOnMainThreadWithObjectWaitUntilDone, performSelectorOnMainThreadWithObjectWaitUntilDoneModes, performSelectorOnThreadWithObjectWaitUntilDone, performSelectorOnThreadWithObjectWaitUntilDoneModes, performSelectorWithObject, performSelectorWithObjectAfterDelay, performSelectorWithObjectAfterDelayInModes, performSelectorWithObjectWithObject, prepareForInterfaceBuilder, provideImageDataBytesPerRowOrigin_Size_UserInfo, removeObserverForKeyPath, removeObserverForKeyPathContext, replacementObjectForCoder, replacementObjectForKeyedArchiver, respondsToSelector, self, setAccessibilityActivationPoint, setAccessibilityAttributedHint, setAccessibilityAttributedLabel, setAccessibilityAttributedUserInputLabels, setAccessibilityAttributedValue, setAccessibilityContainerType, setAccessibilityCustomActions, setAccessibilityCustomRotors, setAccessibilityDragSourceDescriptors, setAccessibilityDropPointDescriptors, setAccessibilityElements, setAccessibilityElementsHidden, setAccessibilityFrame, setAccessibilityHint, setAccessibilityLabel, setAccessibilityLanguage, setAccessibilityNavigationStyle, setAccessibilityPath, setAccessibilityRespondsToUserInteraction, setAccessibilityTextualContext, setAccessibilityTraits, setAccessibilityUserInputLabels, setAccessibilityValue, setAccessibilityViewIsModal, setIsAccessibilityElement, setNilValueForKey, setObservationInfo, setShouldGroupAccessibilityChildren, setValueForKey, setValueForKeyPath, setValueForUndefinedKey, setValuesForKeysWithDictionary, shouldGroupAccessibilityChildren, superclass, validateValueForKeyError, validateValueForKeyPathError, valueForKey, valueForKeyPath, valueForUndefinedKey, willChangeValueForKey, willChangeValueForKeyWithSetMutationUsingObjects, willChangeValuesAtIndexesForKeyprotected MPSAccelerationStructure(org.moe.natj.general.Pointer peer)
public static boolean accessInstanceVariablesDirectly()
public static MPSAccelerationStructure alloc()
public static MPSAccelerationStructure allocWithZone(org.moe.natj.general.ptr.VoidPtr zone)
public static boolean automaticallyNotifiesObserversForKey(java.lang.String key)
public static void cancelPreviousPerformRequestsWithTarget(java.lang.Object aTarget)
public static void cancelPreviousPerformRequestsWithTargetSelectorObject(java.lang.Object aTarget,
org.moe.natj.objc.SEL aSelector,
java.lang.Object anArgument)
public static NSArray<java.lang.String> classFallbacksForKeyedArchiver()
public static org.moe.natj.objc.Class classForKeyedUnarchiver()
public java.lang.Object copyWithZone(org.moe.natj.general.ptr.VoidPtr zone)
copyWithZone in interface NSCopyingcopyWithZone in class MPSKernelpublic MPSAccelerationStructure copyWithZoneDevice(org.moe.natj.general.ptr.VoidPtr zone, MTLDevice device)
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.
copyWithZoneDevice in class MPSKernelzone - This parameter is ignored. Memory zones are no longer used by Objective-C.device - New Metal devicepublic MPSAccelerationStructure copyWithZoneGroup(org.moe.natj.general.ptr.VoidPtr zone, MPSAccelerationStructureGroup group)
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.
zone - This parameter is ignored. Memory zones are no longer used by Objective-C.group - New acceleration structure grouppublic static java.lang.String debugDescription_static()
public static java.lang.String description_static()
public void encodeRefitToCommandBuffer(MTLCommandBuffer commandBuffer)
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.
public void encodeWithCoder(NSCoder coder)
encodeWithCoder in interface NSCodingencodeWithCoder in class MPSKernelpublic MPSAccelerationStructureGroup group()
public static long hash_static()
public MPSAccelerationStructure init()
public MPSAccelerationStructure initWithCoder(NSCoder coder)
NSCodinginitWithCoder in interface NSCodinginitWithCoder in class MPSKernelpublic MPSAccelerationStructure initWithCoderDevice(NSCoder aDecoder, java.lang.Object device)
initWithCoderDevice in class MPSKernelaDecoder - The NSCoder subclass with your serialized MPSKerneldevice - The MTLDevice on which to make the MPSKernelpublic MPSAccelerationStructure initWithCoderGroup(NSCoder aDecoder, MPSAccelerationStructureGroup group)
public MPSAccelerationStructure initWithDevice(java.lang.Object device)
initWithDevice in class MPSKerneldevice - The device that the filter will be used on. May not be NULL.public MPSAccelerationStructure initWithGroup(MPSAccelerationStructureGroup group)
The Metal device is determined from the acceleration structure group. All acceleration structures in the instance hierarchy must share the same group.
public static NSObject.Function_instanceMethodForSelector_ret instanceMethodForSelector(org.moe.natj.objc.SEL aSelector)
public static NSMethodSignature instanceMethodSignatureForSelector(org.moe.natj.objc.SEL aSelector)
public static boolean instancesRespondToSelector(org.moe.natj.objc.SEL aSelector)
public static boolean isSubclassOfClass(org.moe.natj.objc.Class aClass)
public static NSSet<java.lang.String> keyPathsForValuesAffectingValueForKey(java.lang.String key)
public static MPSAccelerationStructure new_objc()
public void rebuild()
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.
public void rebuildWithCompletionHandler(MPSAccelerationStructure.Block_rebuildWithCompletionHandler completionHandler)
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.
public static boolean resolveClassMethod(org.moe.natj.objc.SEL sel)
public static boolean resolveInstanceMethod(org.moe.natj.objc.SEL sel)
public void setUsage(long value)
public static void setVersion_static(long aVersion)
public long status()
public static org.moe.natj.objc.Class superclass_static()
public static boolean supportsSecureCoding()
public boolean _supportsSecureCoding()
NSSecureCoding_supportsSecureCoding in interface NSSecureCoding_supportsSecureCoding in class MPSKernelpublic long usage()
public static long version_static()