auto PPU::serialize(serializer& s) -> void {
  Thread::serialize(s);

  s(vram);
  s(pram);
  s(oam);

  s(io.gameBoyColorMode);
  for(auto& flag : io.forceBlank) s(flag);
  s(io.greenSwap);

  s(Background::IO::mode);
  s(Background::IO::frame);
  s(Background::IO::mosaicWidth);
  s(Background::IO::mosaicHeight);
  s(bg0);
  s(bg1);
  s(bg2);
  s(bg3);
  s(objects);
  s(window0);
  s(window1);
  s(window2);
  s(window3);
  s(dac);

  s(pramAccessed);
  s(vramAccessedBG);
  s(oamAccessed);
}

auto PPU::Background::serialize(serializer& s) -> void {
  s(id);

  for(auto& flag : io.enable) s(flag);
  s(io.priority);
  s(io.characterBase);
  s(io.unused);
  s(io.mosaic);
  s(io.colorMode);
  s(io.screenBase);
  s(io.affineWrap);
  s(io.screenSize);
  s(io.hoffset);
  s(io.voffset);
  s(io.pa);
  s(io.pb);
  s(io.pc);
  s(io.pd);
  s(io.x);
  s(io.y);
  s(io.lx);
  s(io.ly);

  s(mosaicOffset);
  s(vmosaic);
  s(fx);
  s(fy);
}

auto PPU::Objects::serialize(serializer& s) -> void {
  for(auto& flag : io.enable) s(flag);
  s(io.hblank);
  s(io.mapping);
  s(io.mosaicWidth);
  s(io.mosaicHeight);

  s(renderY);
  s(mosaicY);
  s(hmosaicOffset);
  s(vmosaicOffset);
  s(objIndex);
  s(active);
  s(activeCycle);

  s(state);
}

auto PPU::Window::serialize(serializer& s) -> void {
  s(id);

  s(io.enable);
  s(io.active);
  s(io.x1);
  s(io.x2);
  s(io.y1);
  s(io.y2);

  for(auto& flag : output) s(flag);
  s(h);
  s(v);
}

auto PPU::DAC::serialize(serializer& s) -> void {
  s(io.blendMode);
  s(io.blendAbove);
  s(io.blendBelow);
  s(io.blendEVA);
  s(io.blendEVB);
  s(io.blendEVY);
}
