T.J.
T.J.

Reputation: 3960

Create UnsafeMutableRawPointer from NSData

I'm converting a ObjC tutorial (Apple's Selecting Device Objects for Compute Processing tutorial, in particular) to Swift.

I am doing it in increments, so I have to interface to some code still written in ObjC. I'm getting this error:

Cannot convert value of type UnsafeRawPointer to specified type UnsafeMutableRawPointer

How can I fix this error without changing the parameter type passed into the func? My snippet of Swift code is:

  func providePositionData(_inout data: NSData) {
    // Synchronize since positions buffer will be used on another thread
    objc_sync_enter(self)
     
    let rawPtr: UnsafeMutableRawPointer = data.bytes
/* error here: Cannot convert value of type 'UnsafeRawPointer' to specified type 'UnsafeMutableRawPointer' */

 
    let positionsBuffer = device.makeBuffer(
      bytesNoCopy: rawPtr,
      length: data.count,
      options: .storageModeManaged,
      deallocator: nil)
    
    positionsBuffer!.label = "Provided Positions"
    
    positionsBuffer?.__didModifyRange(NSRange(location: 0, length: data.count))
    
    self.positionsBuffer = positionsBuffer
    objc_sync_exit(self)
  }

The working ObjC code is:

/// Called to provide positions data to be rendered on the next frame
- (void)providePositionData:(NSData *)data
{
    // Synchronize since positions buffer will be used on another thread
    @synchronized(self)
    {
        // Cast from 'const void *' to 'void *' which is okay in this case since updateData was
        // created with -[NSData initWithBytesNoCopy:length:deallocator:] and underlying memory was
        // allocated with vm_allocate
      void *vmAllocatedAddress = (void *)data.bytes;

        // Create a MTLBuffer with out copying the data
        id<MTLBuffer> positionsBuffer = [_device newBufferWithBytesNoCopy:vmAllocatedAddress
                                                                   length:data.length
                                                                  options:MTLResourceStorageModeManaged
                                                              deallocator:nil];

        positionsBuffer.label = @"Provided Positions";

        [positionsBuffer didModifyRange:NSMakeRange(0, data.length)];

        _positionsBuffer = positionsBuffer;
    }
}

The NSData that is sent in come from ObjC code that wraps the MTLBuffer in NSData to allow the app to perform memory management. Here is the working snippet:

// Wrap the memory allocated with vm_allocate with a NSData object which will allow the app to
// rely on ObjC ARC (or even MMR) to manage the memory's lifetime. Initialize NSData object
// with a deallocation block to free the vm_allocated memory when the object has been
// deallocated
{
  // Block to dealloc memory created with vm_allocate
  void (^deallocProvidedAddress)(void *bytes, NSUInteger length) =
  ^(void *bytes, NSUInteger length)
  {
    vm_deallocate((vm_map_t)mach_task_self(),
                  (vm_address_t)bytes,
                  length);
  };
  
  NSData *positionData = [[NSData alloc] initWithBytesNoCopy:positionDataAddress
                                                      length:positionDataSize
                                                 deallocator:deallocProvidedAddress];
  
  NSData *velocityData = [[NSData alloc] initWithBytesNoCopy:velocityDataAddress
                                                      length:velocityDataSize
                                                 deallocator:deallocProvidedAddress];
  
  dataProvider(positionData, velocityData, time);
}

Upvotes: 2

Views: 259

Answers (0)

Related Questions