Skip to content

[API Proposal]: JavaScript marshalling support float[], Span<float> and ArraySegment<float> #123706

@ArcadeMode

Description

@ArcadeMode

Background and motivation

Ability to access floats in the WASM linear memory from in WebGPU contexts, without requiring data copies.
Performance of rendering and also neural networks (AI) depends on no-copy interop.
In those scenarios buffers of float[] are in many cases preferred over double[] buffers because of memory bandwidth and size of RAM on the GPU.

See #97268 and #97380.

We already have the same API for copy-by-value JS interop of double[] and no-copy interop of , Span<double>, ArraySegment<double>

API Proposal

namespace System.Runtime.InteropServices.JavaScript;

[Versioning.SupportedOSPlatformAttribute("browser")]
[CLSCompliant(false)]
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)]
public struct JSMarshalerArgument
{
    ....
+   public void ToManaged(out float[]? value) { throw null; }
    public void ToManaged(out double[]? value) { throw null; }
+   public void ToJS(float[]? value) { throw null; }
    public void ToJS(double[]? value) { throw null; }
+   public void ToManaged(out Span<float> value) { throw null; }
    public void ToManaged(out Span<double> value) { throw null; }
+   public void ToJS(Span<float> value) { throw null; }
    public void ToJS(Span<double> value) { throw null; }
+   public void ToManaged(out ArraySegment<float> value) { throw null; }
    public void ToManaged(out ArraySegment<double> value) { throw null; }
+   public void ToJS(ArraySegment<float> value) { throw null; }
    public void ToJS(ArraySegment<double> value) { throw null; }
}

API Usage

This is API for code generated by Roslyn analyzer when users use [JSImport] or [JSExport].
It's not human facing API, but it needs to be public API because Roslyn generated code is consuming only visible APIs.

The generated code looks similar to this, just with float data type.

global::System.DateTime a10 = default;
global::System.DateTimeOffset a11 = default;
global::System.Threading.Tasks.Task<global::System.DateTime> a12 = default;
global::System.Threading.Tasks.Task<global::System.DateTimeOffset> a13 = default;
global::System.Threading.Tasks.Task<long> a14 = default;
global::System.Threading.Tasks.Task<long> a15 = default;
ref global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument ____arg_exception_native = ref *____arg_exception_native__param;
try
{
// UnmarshalCapture - Capture the native data into marshaller instances in case conversion to managed data throws an exception.
__a11_native.ToManaged(out a11);
__a10_native.ToManaged(out a10);
__a9_native.ToManaged(out a9);
__a7_native.ToManaged(out a7);
__a6_native.ToManaged(out a6);
__a3_native.ToManagedBig(out a3);
__a2_native.ToManaged(out a2);
__a1_native.ToManaged(out a1);

User facing API

This doesn't change because this is all user code.

[JSImport("echo1", "JavaScriptTestHelper")]
static partial float[]? Echo1(float[]? value);

[JSExport]
internal static ArraySegment<float> Echo2(ArraySegment<float> value)
{
    return value;
}

[JSImport("echo3", "JavaScriptTestHelper")]
static partial Span<float> Echo3(Span<float> value);

[JSExport]
static Span<float> EchoSpanSingle(Span<float> value)
{
    return value;
}

There is draft implementation #123642

Alternative Designs

No response

Risks

No known risks.

Metadata

Metadata

Assignees

Labels

api-ready-for-reviewAPI is ready for review, it is NOT ready for implementationarch-wasmWebAssembly architecturearea-System.Runtime.InteropServicesin-prThere is an active PR which will close this issue when it is mergedos-browserBrowser variant of arch-wasm

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions