refresh method

  1. @override
void refresh(
  1. ByteData bytes
)
override

Reparses bytes into this library in place.

bytes are a whole bundle, the same shape GraphicsDevice.loadShaders took, and the same refusals apply: bytes that are not a bundle, a section this backend has none of, an SDK it was not compiled on, a stage this backend cannot run. A refused reload throws ShaderBundleRefused and leaves the library as it was, so an editor that rebuilt a bundle wrongly keeps drawing with the one that worked.

A bundle that no longer names a stage already handed out is refused too, naming the stage. The handle is the renderer's for its lifetime — that is the identity promise above — so a library that answered a name once and then accepted a bundle without it would leave a live handle over a stage the bundle does not have: on one backend a pipeline that still draws the old code, on another a link error at the next frame, and in both cases a picture that disagrees with the file. Every backend refuses the same way, before anything is swapped, and the conformance suite holds them to it. A name that was asked for and answered null is not in use, and a bundle may drop or add it freely.

Implementation

@override
void refresh(ByteData bytes) {
  final bundle = ShaderBundle.decode(bytes);
  // The other half of the promise, kept the way the real backends keep it:
  // a bundle that dropped a stage somebody holds is refused, naming it.
  final dropped = _handles.keys
      .where((String n) => !bundle.names.contains(n))
      .toList();
  if (dropped.isNotEmpty) {
    throw ShaderBundleRefused(
      name: bundle.name,
      reason:
          'it no longer has the stage${dropped.length == 1 ? '' : 's'} '
          '${dropped.map((String n) => '"$n"').join(', ')}, which '
          '${dropped.length == 1 ? 'is' : 'are'} already in use',
    );
  }
  _bundle = bundle;
  refreshes++;
}