Razza
Razza

Reputation: 1

Having problem with MPSMatrixMultiplication encodeToBuffer

I am using MPSMatrixMultiplication, and when I call encodeToCommandBuffer it is stating error "The starting matrix must be contained within each of the MPSMatrix objects." I am not sure what it means.

I am just trying to do a simple calculation and it seems if I apply similar code and pattern in swift, it works perfectly, but in Objective-c it is giving me error.

    #import <Foundation/Foundation.h>
    #import <Metal/Metal.h>
    #import <MetalKit/MetalKit.h>
    #import <MetalPerformanceShaders/MetalPerformanceShaders.h>

    NS_ASSUME_NONNULL_BEGIN

     //Interface
    @interface KernelCalculator: NSObject

    ///Properties
    @property id<MTLDevice> device;
    @property id<MTLBuffer> bufferA;
    @property id<MTLBuffer> bufferB;
    @property id<MTLBuffer> bufferC;
    @property MTKView *view;
    @property id<MTLCommandQueue> commandQueue;
    @property id<MTLCommandBuffer> commandBuffer;
    @property MPSMatrixMultiplication *mmKernel;

    @end

    NS_ASSUME_NONNULL_END


    #import "KernelCalculator.h"
    @implementation KernelCalculator

    - (instancetype)init
    {
       self = [super init];
       if (self) 
     {

        _view = [[MTKView alloc] init];

        _view.device = MTLCreateSystemDefaultDevice();

        if(!_view.device){
             NSLog(@"Metal is not supported on this device");
            return self;
        }

        _device = _view.device;
        _commandQueue = [_device newCommandQueue];
        _commandBuffer = [_commandQueue commandBuffer];

//Float array A
        float _matrix_A[] = {
            2.0, 3.0, 4.0
        };
//Float array B
        float _matrix_B[] = {
            2.0, 2.0, 2.0
        };

//size of each array
        int matrix_A_length= sizeof(_matrix_A)/sizeof(float);
        int matrix_B_length= sizeof(_matrix_B)/sizeof(float);

        ///<A>
        int totalBytesA = sizeof(_matrix_A);

        _bufferA = [_device newBufferWithBytes:_matrix_A length:totalBytesA options: MTLResourceCPUCacheModeDefaultCache];

        MPSMatrixDescriptor *descriptionA = [[MPSMatrixDescriptor alloc] init];

        [descriptionA setRows:3];
        [descriptionA setColumns:1];
        [descriptionA setRowBytes:totalBytesA/3];
        [descriptionA setDataType:MPSDataTypeFloat32];

        MPSMatrix *A = [[MPSMatrix alloc] initWithBuffer:_bufferA descriptor:descriptionA];

        printf("\n A row: %lu ", (unsigned long)A.rows);

        printf("\n A columns: %lu ", (unsigned long)A.columns);
        printf("\n A rowBytes: %lu", (unsigned long)A.rowBytes);

        printf("\n A totalBytes: %lu \n\n", (unsigned long)totalBytesA);

        ///</A>

        ///<B>
        int totalBytesB = sizeof(_matrix_B);

        _bufferB = [_device newBufferWithBytes:_matrix_B length:totalBytesB options: MTLResourceCPUCacheModeDefaultCache];

        MPSMatrixDescriptor *descriptionB = [[MPSMatrixDescriptor alloc] init];

        [descriptionB setRows:1];
        [descriptionB setColumns:3];
        [descriptionB setRowBytes:totalBytesB/1];
        [descriptionB setDataType: MPSDataTypeFloat32];

        MPSMatrix *B = [[MPSMatrix alloc] initWithBuffer:_bufferB descriptor:descriptionB];

        printf("\n B row: %lu ", (unsigned long)B.rows);

        printf("\n B columns: %lu ", (unsigned long)B.columns);
        printf("\n B rowBytes: %lu", (unsigned long)B.rowBytes);

        printf("\n B totalBytes: %lu \n\n", (unsigned long)totalBytesB);
        ///</B>

        ///<C>

        int totalBytesC = matrix_A_length* matrix_B_length*sizeof(float);

        _bufferC = [_device newBufferWithLength:totalBytesC options:MTLResourceCPUCacheModeDefaultCache];

        MPSMatrixDescriptor *descriptionC = [[MPSMatrixDescriptor alloc] init];

        [descriptionC setRows:A.rows];
        [descriptionC setColumns:B.columns];
        [descriptionC setRowBytes:totalBytesC/A.rows];
        [descriptionC setDataType: MPSDataTypeFloat32];

        MPSMatrix *C = [[MPSMatrix alloc] initWithBuffer:_bufferC descriptor:descriptionC];

        printf("\n C row: %lu ", (unsigned long)C.rows);

        printf("\n C columns: %lu ", (unsigned long)C.columns);
        printf("\n C rowBytes: %lu", (unsigned long)C.rowBytes);

        printf("\n C totalBytes: %lu \n\n", (unsigned long)totalBytesC);
        ///</C>

        _mmKernel = [[MPSMatrixMultiplication alloc]
            initWithDevice:_device
            transposeLeft:false
            transposeRight:false
            resultRows:3
            resultColumns:1
            interiorColumns:1
            alpha:1.0
            beta:0.0];

        [_mmKernel encodeToCommandBuffer: _commandBuffer leftMatrix:B rightMatrix:A resultMatrix:C];

        [_commandBuffer commit];
        [_commandBuffer waitUntilCompleted];

    }
    return self;
    }
    @end

I would be grateful if just point out the problem I have in my code.

Upvotes: 0

Views: 232

Answers (1)

warrenm
warrenm

Reputation: 31782

That's a bizarre error message, and is worth a bug report on its own.

The problem is that you're manually filling out your matrix descriptors, but you're not initializing all of the necessary fields. In particular, your matrix descriptors each have their matrices and matrixBytes properties set to 0, which is an invalid configuration.

Although these properties doesn't seem to be checked at matrix-creation time, they do seem to get validated at encoding time, leading to this failure. In my opinion, there should be stricter validation in place at the time the matrix is created, but because MPSMatrix is such a lightweight wrapper around a buffer, this probably wasn't deemed necessary.

In any event, the best way to avoid this is to use the matrix descriptor factory method to fill out the remaining fields for you. It's less code, and it's more stylish. For example:

MPSMatrixDescriptor * descriptionA =
    [MPSMatrixDescriptor matrixDescriptorWithRows:3
                                          columns:1
                                         rowBytes:totalBytesA/3
                                         dataType:MPSDataTypeFloat32];

Also, you seem to have an error in your kernel creation and encoding calls: resultColumns should be 3, not 1; leftMatrix should be A; and rightMatrix should be B, to produce a 3x3 result matrix.

Upvotes: 1

Related Questions