Lazy Serialization
jsantell opened this issue · comments
Serialization is what blocks rendering on the content (often twice: once for the toJSON()
call and once for the postMessage()
, which seems roughly about three times the size of the toJSON()
). This can be observed in Chromium's violation warnings. For example, this example with geometry with position, size, and color attributes results in the warning, where 'refresh' is the serialization and 'message' is passing that to the extension:
[Violation] 'refresh' handler took 179ms
[Violation] 'message' handler took 574ms
This may be a prereq for #33, since we'll be able to more aggressively sync with content without incurring long jank times.
Strategies
With circumventing three's serialization in #31, a cache can be injected here for costly objects if the meta
object has some flag. That way, when serializing a scene for example, any 'expensive' objects will only return their basic structured data, minus expensive properties.
The objects can be fully serialized as needed when the corresponding object is being inspected.
Expensive items AFAIK:
- Texture's image
- Geometry's BufferAttributes
- Uniforms (which may be textures or buffers)
Pre-emptive Texture Serialization
Since textures aren't generally changing, especially when loaded from an image, we can also serialize these up front. Canvas, WebGLRenderTargets, data textures and video textures are a bit different, but for the most part, serializing once initially should be sufficient, and significantly decrease future serialization costs. For the special texture cases, they can be refreshed when that texture is being inspected. This gives the ability to render texture previews, for example, before a specific texture is inspected.
Completed in ad7a904, there are a handful of changes of how serialization is performed.
Changes:
- There is now a lighter form of serialization for resource lists/overviews (a traversal + dependency check) as well as a serialization option that skips children of Object3Ds.
- The "overview" data (scene graph, scenes, materials, textures, geometries) only need to know existence and name or type for the most part, rather than serializing an entire scene graph.
- The scene graph uses this light serialization as well, decoupling serialized object data from the scene structure.
- The devtools process doesn't attempt to have a full copy of the scene in memory. There's a downside of needing to request and load data before selecting an entity and a brief moment until it's loaded, but the advantage is lazily fetching potentially large images and geometries.
- Lighter serialization allows more refreshing, whenever a new scene is added, or a panel changed, the latest resources should be shown.
- On entity select, the entity is freshly serialized, with large resources only serialized once (images, buffer attributes). Additionally, they are only sent cross process once, another large source of jank. Texture images shouldn't change until we have dynamic textures for the most part, and attributes of geometry that aren't updating is also fine for now, which is not being used yet (will render geometry preview). In the future, checking texture or attribute versioning can be handled.