refresh method
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++;
}