KestrelComputer / kestrel

The Kestrel is a family of home-made computers, built as much as possible on open-source technology, and supporting as much as possible the open-source philosophy.
http://kestrelcomputer.github.io/kestrel
Mozilla Public License 2.0
185 stars 10 forks source link

Problem: Kestrel-3 needs a BitBlit routine. #192

Closed sam-falvo closed 8 years ago

sam-falvo commented 8 years ago

After much design frustration, I've decided upon an interface that I'm more or less happy with.

The overall control flow of the blitter is as follows:

FOR each row DO
  IF vector A is sourced from a bitmap THEN
    Read next vector into workspace A.
  ELSE
    Fill workspace A with copies of static data A.
  END
  Apply left- and right-fringe masks.
  Shift workspace A as appropriate (left or right).

  IF vector B is sourced from a bitmap THEN
    Read next vector into workspace B.
  ELSE
    Fill workspace B with copies of static data B.
  END
  Shift workspace B as appropriate (left or right).

  FOR each byte in vector D DO
    Set byte to appropriate function of corresponding bytes in vectors A, B, and D.
  END

  Adjust A, B, and D pointers with their eponymous row skip parameters.
END

The interface to the blitter, from outside the library, should be expressed as simply as possible; so, given a bitmap A, we want to take bitmap data from (x1, y1)-(x1+W, y1+H), and merge it somehow with data from bitmap B at (x2, y2)-(x2+W, y2+H), and put the results in a destination bitmap at (x3, y3)-(x3+W, y3+H) using one of 256 possible functions. This requires bitmap address calculations, coordinate translations, etc. We definitely want to do this in the library, because if/when the blitter is put into hardware, the interface will likely change quite a bit. As long as client software deals with pixel subranges in a bitmap, software should continue to just work.

I'm thinking of using JIT to generate the minterm solver. Assuming we establish our registers ahead of time, I do not want to have to hand-write all 256 minterm solvers. Writing 16 (to handle two sources) is doable, yet tedious.

Between the need for temporary workspaces and generated code, I'm thinking we should make the blit context an abstract data type unto itself. E.g., to perform a blit, you first need to create a Blit object, adjust parameters as appropriate, then perform the blit. You can re-use this blit object as many times as needed by just adjusting the attributes. When you're done with the blit, you can dispose of it. (Interesting: this is how Smalltalk does it too.)

sam-falvo commented 8 years ago

I think a good simplification for the control flow above is to make each vector-get and vector-put operation a callback. That way, the software blitter is unaware of where the data came from, only that it now has it. Application of fringe masks and performing row shifting will be done by the soft-blitter, as that's entirely "inside" the blitter, as far as its concerned.

I still have not quite figured out how to handle the raster-op function yet; either JIT or not, it seems like supporting 256 ops is just too daunting a task. I may have to leave using D as a source out of the picture, and focus on 16 raster-ops between A and B only. Then, of this set of raster-ops functions, I invoke two of them. One will source bits for when the corresponding D bit is 0, and one will source bits for when the corresponding D bit is 1. Logically OR those two results, and that should give the expected results.

d1 = rasterop[opNotD](a, b)
d2 = rasterop[opD](a, b)
d = (!d & d1) | (d & d2)

It'd be interesting to benchmark this approach versus a soft-blitter that only provided one source and one destination, such as X11's BitBlt() call.

sam-falvo commented 8 years ago

This is still necessary, but is no longer a pressing issue. Closing this ticket for now.