Decades ago, Will Wright suggested to me a nice optimization for cellular automata and convolution filters that lets you eliminate the bounds checks in the inner loop, which I implemented in my CAM6 cellular automata machine simulator:
Eliminate the edge conditions (and conditionals in the inner loop) by making a "gutter" of one extra pixel (or however many pixels your neighborhood extents out) around all the edges of the bitmap (i.e. increase the width and height by 2, then inset x and y by 1), then before processing each frame, copy the appropriate edges into the corresponding gutters (wrapping or clamping), then iterate over the pixels just inside the gutters, so you don't have to perform any bounds checks.
https://github.com/SimHacker/CAM6/blob/master/javascript/CAM...
// Optimization Techniques
//
// Extra copying is eliminated by swapping between two cell buffers,
// one for the past and the other for the future. After applying the
// rule, the past cell buffer becomes the future, and the future
// becomes the past. It's necessary to have two buffers, because
// you can't apply cellular automata in-place in one buffer, since
// you would stomp on your past neighbors whose future you just
// computed, since the neighbors above and to the right would be
// from the future instead of the past.
//
// Edge conditions eliminated from inner loop by making cell buffers
// two cells wider and taller, and wrapping edges around to the
// extra edge cells before applying rule, so the inner loop does not
// have to check for edge conditions to wrap the cells, and other
// edge treatments can be applied besides wrapping, like clamping or
// reflecting.
//
https://github.com/SimHacker/CAM6/blob/master/javascript/CAM... // wrapCells wraps the cell edges.
[...]
You can either wrap the cells into the gutter from the opposite edge like a torus, which makes nice seamlessly tileable patterns, or in the case of something like SimCity pollution diffusion, you can just clamp the pixels into the gutter along the same edge.Shaders have a way of wrapping and clamping and mirroring automatically (wrapping modes):
https://webglfundamentals.org/webgl/webgl-3d-textures-repeat...
But on old school consoles you have have to use software tricks like that instead of relying on the hardware.
And of course if you're using power of two sized bitmaps you can just mask the coordinates, which is practically free.
You could fix SimCity to use that trick, but it would make the code more complex, and it's probably not worth it on anything but really old hardware like the C64 or Sega Dreamcast.