Pass entire RenderBatch to JS side in one call
This commit is contained in:
parent
55592f583b
commit
c81d537ea3
|
|
@ -1,5 +1,5 @@
|
||||||
import { invokeWithJsonMarshalling } from './InvokeWithJsonMarshalling';
|
import { invokeWithJsonMarshalling } from './InvokeWithJsonMarshalling';
|
||||||
import { attachComponentToElement, renderRenderTree } from '../Rendering/Renderer';
|
import { attachComponentToElement, renderBatch } from '../Rendering/Renderer';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The definitive list of internal functions invokable from .NET code.
|
* The definitive list of internal functions invokable from .NET code.
|
||||||
|
|
@ -8,5 +8,5 @@ import { attachComponentToElement, renderRenderTree } from '../Rendering/Rendere
|
||||||
export const internalRegisteredFunctions = {
|
export const internalRegisteredFunctions = {
|
||||||
attachComponentToElement,
|
attachComponentToElement,
|
||||||
invokeWithJsonMarshalling,
|
invokeWithJsonMarshalling,
|
||||||
renderRenderTree,
|
renderBatch,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -124,6 +124,10 @@ export const monoPlatform: Platform = {
|
||||||
const fieldValue = Module.getValue((baseAddress as any as number) + (fieldOffset || 0), 'i32');
|
const fieldValue = Module.getValue((baseAddress as any as number) + (fieldOffset || 0), 'i32');
|
||||||
return fieldValue === 0 ? null : monoPlatform.toJavaScriptString(fieldValue as any as System_String);
|
return fieldValue === 0 ? null : monoPlatform.toJavaScriptString(fieldValue as any as System_String);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
readStructField: function readStructField(baseAddress: Pointer, fieldOffset?: number): Pointer {
|
||||||
|
return ((baseAddress as any as number) + (fieldOffset || 0)) as any as Pointer;
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
// Bypass normal type checking to add this extra function. It's only intended to be called from
|
// Bypass normal type checking to add this extra function. It's only intended to be called from
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@
|
||||||
readInt32Field(baseAddress: Pointer, fieldOffset?: number): number;
|
readInt32Field(baseAddress: Pointer, fieldOffset?: number): number;
|
||||||
readObjectField(baseAddress: Pointer, fieldOffset?: number): System_Object;
|
readObjectField(baseAddress: Pointer, fieldOffset?: number): System_Object;
|
||||||
readStringField(baseAddress: Pointer, fieldOffset?: number): string | null;
|
readStringField(baseAddress: Pointer, fieldOffset?: number): string | null;
|
||||||
|
readStructField(baseAddress: Pointer, fieldOffset?: number): Pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We don't actually instantiate any of these at runtime. For perf it's preferable to
|
// We don't actually instantiate any of these at runtime. For perf it's preferable to
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
import { Pointer, System_Array } from '../Platform/Platform';
|
||||||
|
import { platform } from '../Environment';
|
||||||
|
|
||||||
|
// Keep in sync with the structs in .NET code
|
||||||
|
|
||||||
|
export const renderBatch = {
|
||||||
|
updatedComponents: (obj: RenderBatchPointer) => platform.readStructField(obj, 0) as ArrayRangePointer,
|
||||||
|
};
|
||||||
|
|
||||||
|
const arrayRangeStructLength = 8;
|
||||||
|
export const arrayRange = {
|
||||||
|
array: (obj: ArrayRangePointer) => platform.readObjectField(obj, 0) as System_Array,
|
||||||
|
count: (obj: ArrayRangePointer) => platform.readInt32Field(obj, 4),
|
||||||
|
};
|
||||||
|
|
||||||
|
export const renderTreeDiffStructLength = 4 + 2 * arrayRangeStructLength;
|
||||||
|
export const renderTreeDiff = {
|
||||||
|
componentId: (obj: RenderTreeDiffPointer) => platform.readInt32Field(obj, 0),
|
||||||
|
edits: (obj: RenderTreeDiffPointer) => platform.readStructField(obj, 4) as ArrayRangePointer,
|
||||||
|
currentState: (obj: RenderTreeDiffPointer) => platform.readStructField(obj, 4 + arrayRangeStructLength) as ArrayRangePointer,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Nominal types to ensure only valid pointers are passed to the functions above.
|
||||||
|
// At runtime the values are just numbers.
|
||||||
|
export interface RenderBatchPointer extends Pointer { RenderBatchPointer__DO_NOT_IMPLEMENT: any }
|
||||||
|
export interface ArrayRangePointer extends Pointer { ArrayRangePointer__DO_NOT_IMPLEMENT: any }
|
||||||
|
export interface RenderTreeDiffPointer extends Pointer { RenderTreeDiffPointer__DO_NOT_IMPLEMENT: any }
|
||||||
|
|
@ -1,15 +0,0 @@
|
||||||
import { Pointer, System_Array } from '../Platform/Platform';
|
|
||||||
import { platform } from '../Environment';
|
|
||||||
|
|
||||||
// Keep in sync with the RenderComponentArgs struct in .NET code
|
|
||||||
export const renderComponentArgs = {
|
|
||||||
browserRendererId: (obj: RenderComponentArgsPointer) => platform.readInt32Field(obj, 0),
|
|
||||||
componentId: (obj: RenderComponentArgsPointer) => platform.readInt32Field(obj, 4),
|
|
||||||
renderTreeEdits: (obj: RenderComponentArgsPointer) => platform.readObjectField(obj, 8) as System_Array,
|
|
||||||
renderTreeEditsLength: (obj: RenderComponentArgsPointer) => platform.readInt32Field(obj, 12),
|
|
||||||
renderTree: (obj: RenderComponentArgsPointer) => platform.readObjectField(obj, 16) as System_Array
|
|
||||||
}
|
|
||||||
|
|
||||||
// Nominal type to ensure only valid pointers are passed to the renderComponentArgs functions.
|
|
||||||
// At runtime the values are just numbers.
|
|
||||||
export interface RenderComponentArgsPointer extends Pointer { RenderComponentArgsPointer__DO_NOT_IMPLEMENT: any }
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
import { platform } from '../Environment';
|
import { platform } from '../Environment';
|
||||||
import { getTreeNodePtr, renderTreeNode, NodeType, RenderTreeNodePointer } from './RenderTreeNode';
|
import { getTreeNodePtr, renderTreeNode, NodeType, RenderTreeNodePointer } from './RenderTreeNode';
|
||||||
import { RenderTreeEditPointer } from './RenderTreeEdit';
|
import { RenderTreeEditPointer } from './RenderTreeEdit';
|
||||||
import { renderComponentArgs, RenderComponentArgsPointer } from './RenderComponentArgs';
|
import { renderBatch as renderBatchStruct, arrayRange, renderTreeDiffStructLength, renderTreeDiff, RenderBatchPointer, RenderTreeDiffPointer } from './RenderBatch';
|
||||||
import { BrowserRenderer } from './BrowserRenderer';
|
import { BrowserRenderer } from './BrowserRenderer';
|
||||||
|
|
||||||
type BrowserRendererRegistry = { [browserRendererId: number]: BrowserRenderer };
|
type BrowserRendererRegistry = { [browserRendererId: number]: BrowserRenderer };
|
||||||
|
|
@ -23,19 +23,27 @@ export function attachComponentToElement(browserRendererId: number, elementSelec
|
||||||
clearElement(element);
|
clearElement(element);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function renderRenderTree(args: RenderComponentArgsPointer) {
|
export function renderBatch(browserRendererId: number, batch: RenderBatchPointer) {
|
||||||
const browserRendererId = renderComponentArgs.browserRendererId(args);
|
|
||||||
const browserRenderer = browserRenderers[browserRendererId];
|
const browserRenderer = browserRenderers[browserRendererId];
|
||||||
if (!browserRenderer) {
|
if (!browserRenderer) {
|
||||||
throw new Error(`There is no browser renderer with ID ${browserRendererId}.`);
|
throw new Error(`There is no browser renderer with ID ${browserRendererId}.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const updatedComponents = renderBatchStruct.updatedComponents(batch);
|
||||||
|
const updatedComponentsLength = arrayRange.count(updatedComponents);
|
||||||
|
const updatedComponentsArray = arrayRange.array(updatedComponents);
|
||||||
|
for (var i = 0; i < updatedComponentsLength; i++) {
|
||||||
|
const updatedComponentDiff = platform.getArrayEntryPtr(updatedComponentsArray, i, renderTreeDiffStructLength) as RenderTreeDiffPointer;
|
||||||
|
const componentId = renderTreeDiff.componentId(updatedComponentDiff);
|
||||||
|
|
||||||
const componentId = renderComponentArgs.componentId(args);
|
const editsArrayRange = renderTreeDiff.edits(updatedComponentDiff);
|
||||||
const edits = renderComponentArgs.renderTreeEdits(args);
|
const currentStateArrayRange = renderTreeDiff.currentState(updatedComponentDiff);
|
||||||
const editsLength = renderComponentArgs.renderTreeEditsLength(args);
|
|
||||||
const tree = renderComponentArgs.renderTree(args);
|
|
||||||
|
|
||||||
browserRenderer.updateComponent(componentId, edits, editsLength, tree);
|
const edits = arrayRange.array(editsArrayRange);
|
||||||
|
const editsLength = arrayRange.count(editsArrayRange);
|
||||||
|
const tree = arrayRange.array(currentStateArrayRange);
|
||||||
|
browserRenderer.updateComponent(componentId, edits, editsLength, tree);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function clearElement(element: Element) {
|
function clearElement(element: Element) {
|
||||||
|
|
|
||||||
|
|
@ -68,33 +68,10 @@ namespace Microsoft.AspNetCore.Blazor.Browser.Rendering
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override void UpdateDisplay(RenderBatch batch)
|
protected override void UpdateDisplay(RenderBatch batch)
|
||||||
{
|
{
|
||||||
// TODO: Pass to JS in a single call
|
RegisteredFunction.InvokeUnmarshalled<int, RenderBatch, object>(
|
||||||
for (var i = 0; i < batch.UpdatedComponents.Count; i++)
|
"renderBatch",
|
||||||
{
|
_browserRendererId,
|
||||||
ref var diff = ref batch.UpdatedComponents.Array[i];
|
batch);
|
||||||
RegisteredFunction.InvokeUnmarshalled<RenderComponentArgs, object>(
|
|
||||||
"renderRenderTree",
|
|
||||||
new RenderComponentArgs
|
|
||||||
{
|
|
||||||
BrowserRendererId = _browserRendererId,
|
|
||||||
ComponentId = diff.ComponentId,
|
|
||||||
RenderTreeEdits = diff.Edits.Array,
|
|
||||||
RenderTreeEditsLength = diff.Edits.Count,
|
|
||||||
RenderTree = diff.CurrentState.Array
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Encapsulates the data we pass to the JS rendering function
|
|
||||||
private struct RenderComponentArgs
|
|
||||||
{
|
|
||||||
// Important: If you edit this struct, keep it in sync with RenderComponentArgs.ts
|
|
||||||
|
|
||||||
public int BrowserRendererId;
|
|
||||||
public int ComponentId;
|
|
||||||
public RenderTreeEdit[] RenderTreeEdits;
|
|
||||||
public int RenderTreeEditsLength;
|
|
||||||
public RenderTreeNode[] RenderTree;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue