Skip to content

Slow performance setting VertexData properties with large arrays #34

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
limefrogyank opened this issue Jan 28, 2021 · 4 comments
Open

Comments

@limefrogyank
Copy link

There is a huge bottleneck for me right now when I try setting decimal arrays of length > 100,000 on the VertexData object. It's probably due to the JSInterop layer. I took a look at your other project and it seems you use IJSUnmarshalledRuntime only for certain getter scenarios.

I wonder if it would make sense to include a new set function that has an option to use IJSUnmarshalledRuntime to transfer binary data. Maybe this belongs on your other project...

@canhorn
Copy link
Owner

canhorn commented Jan 28, 2021

I can see having a binary transfer abstraction might work here, I would have to do some testing see for sure.

I will create an issue in the other project to track it.

@limefrogyank
Copy link
Author

I'm also a little curious if there's a way to make the "default" number type be a double or float instead of a decimal. I haven't dived too deeply into it but using decimal makes the arrays twice as big when they don't need to be. I'm still exploring some of the options for your generator.

Regardless, this is a great project! Thanks

@canhorn
Copy link
Owner

canhorn commented Jan 28, 2021

It has to be decimal sadly, it was not my first choice.
This is a JavaScript issue, since JS has no other number types other everything is a decimal.
Moving numbers through the interop, using the UnmarshalledRuntime, causes issues typing and it looses its value.

I have spent many hours on this and it is a headache.

@limefrogyank
Copy link
Author

This hack seems to be a decent workaround to loading large arrays into BabylonJS. And it works with float arrays, too :)
C#

        [Inject] IJSRuntime JSRuntime { get; set; }
        private IJSUnmarshalledRuntime UnmarshalledRuntime;

protected override async Task OnAfterRenderAsync(bool firstRender)
        {
            if (firstRender)
            {
                UnmarshalledRuntime = (IJSUnmarshalledRuntime)JSRuntime;   
            }
        }

------- functions used like this
var r = UnmarshalledRuntime.InvokeUnmarshalled<string, string, float[], bool>("setFast", vertexData.___guid, "positions", data.Positions);
r = UnmarshalledRuntime.InvokeUnmarshalled<string, string, float[], bool>("setFast", vertexData.___guid, "colors", data.Colors);
r = UnmarshalledRuntime.InvokeUnmarshalled<string, string, float[], bool>("setFast", vertexData.___guid, "indices", data.Indices);
r = UnmarshalledRuntime.InvokeUnmarshalled<string, string, float[], bool>("setFast", vertexData.___guid, "uvs", data.ST);
r = UnmarshalledRuntime.InvokeUnmarshalled<string, string, float[], bool>("setFast", vertexData.___guid, "uvs2", data.RowCol);
r = UnmarshalledRuntime.InvokeUnmarshalled<string, string, float[], bool>("setFast", vertexData.___guid, "uvs3", data.Radius);

Typescript:

declare var BINDING: any; //mono functions
declare var Blazor: Blazor;  //blazor object
declare var Module: any;  //emscripten object
declare var blazorInterop: any;

interface Blazor {
    platform: Platform;
}

interface HeapLock {
    release();
}

interface Platform {
    start(resourceLoader: any): Promise<void>;

    callEntryPoint(assemblyName: string): void;

    toUint8Array(array: any): Uint8Array;

    getArrayLength(array: any): number;
    getArrayEntryPtr<TPtr>(array: TPtr, index: number, itemSize: number): TPtr;

    getObjectFieldsBaseAddress(referenceTypedObject: any): any;
    readInt16Field(baseAddress: any, fieldOffset?: number): number;
    readInt32Field(baseAddress: any, fieldOffset?: number): number;
    readUint64Field(baseAddress: any, fieldOffset?: number): number;
    readFloatField(baseAddress: any, fieldOffset?: number): number;
    readObjectField<T>(baseAddress: any, fieldOffset?: number): T;
    readStringField(baseAddress: any, fieldOffset?: number, readBoolValueAsString?: boolean): string | null;
    readStructField<T extends any>(baseAddress: any, fieldOffset?: number): T;

    beginHeapLock(): HeapLock;
    invokeWhenHeapUnlocked(callback: Function): void;
}

function setFast(root, identifier, value) {
    try {
        let rootName = BINDING.conv_string(root);
        let identifierName = BINDING.conv_string(identifier);
        let arr = toFloat32Array(value);

        blazorInterop.set(rootName, identifierName, arr);

    } catch (ex) {
        console.log("error", ex);
    }
}

function toFloat32Array(array: any): Float32Array {
    const dataPtr = Blazor.platform.getArrayEntryPtr(array, 0, 4);
    const length = Blazor.platform.getArrayLength(array);
    return new Float32Array(Module.HEAPF32.buffer, dataPtr, length);
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants