Saturday, January 5, 2013

Frame buffer file format proposal

There are many still image formats, most offer some sort of compression or encoding because they are designed for image distribution. However, there seems to lack a format for storing intermediate images for transferring between some rendering or processing pipeline. Using existing image format, even without compression, requires complex encoding and decoding. For this reason, I'm proposing an intermediate image format that describes an uncompressed raw image, with the ability to use memory mapped file I/O to access pixel data.

The frame buffer file will have the general structure like this:
  • Plane 1
  • Plane 2 (optional)
  • Plane 3 (optional)
  • ...
  • Epilogue
A plane is a complete two dimensional array of pixels. An image may have only a single plane if the pixel is already a packed vector of color values. An image may also split color values for each pixel into their own planes. The color values may be specified in different colorspaces, such as RGB, YUV or even CMYK, specified in the epilogue. The beginning and end of each plane are page-aligned, with page size also specified in the epilogue. When an image is chroma-subsampled, the subsampled planes may have widths and heights independently scaled by a small integer denominator.

After the planes, the epilogue would store a descriptor about how to locate and interpret the planes. The epilogue need only be 32-bit word aligned but not necessarily page aligned, and can share parts of unused memory in the last plane. The epilogue consists of binary-serialized protocol buffer of the frame buffer descriptor, plus a small padding, and end with a 32-bit word-aligned crc32 checksum of the epilogue minus the footer, and a 32-bit footer. The footer's upper 16-bit is the signature 0xffbb, and the lower 16-bit is the size of the entire epilogue including padding and footer. The signature allows detecting the byte order. Since epilogue size is a multiple of 4, the last two bits of the size are zero, so it cannot be confused with the signature. Because epilogue size field is 16-bits, the epilogue is limited to 64KB.

A reader would verify that the frame buffer file size is a multiple of 4, read the last 4 bytes to check the signature and find the epilogue size. It would then read the whole epilogue into memory, check the crc32 of the frame buffer descriptor plus padding, and decode the descriptor.

I'll leave the actual frame buffer descriptor specification for another time. For now, it needs to be able to specify at least the page size, image width and height, colorspace, and the planes. Each plane will specify their own beginning and end file positions, subsample denominator, row (stride) size, and pixel format.

The frame buffer file format shall be used to store only one image, and not be used to specify more complex image compositions such as layering. A scene description language should be used for that purpose instead.

Wednesday, January 2, 2013

C++ named argument builder pattern

I was looking for a C++ builder pattern for passing named arguments to functions, but the example I found on Wikipedia is horrendous. Someone on Stack Overflow mentioned fluent interface which is much better, but the example given in Wikipedia is also horrendous because it involved two classes, one the actual object and the other one is the wrapper employing the fluent interface. Another answer on Stack Overflow is much better, but the example also involved two classes, one the real class and the other the builder. For the purpose of passing named arguments to functions, what I have in mind is more light weight.
#include <iostream>
#include <string>

struct RepeatArgs {
  RepeatArgs() throw()
    : n_(), c_(), prefix_() {}

  RepeatArgs& set_n(size_t n) throw() { n_ = n; return *this; }
  RepeatArgs& set_c(char c) throw() { c_ = c; return *this; }
  RepeatArgs& set_prefix(const std::string& prefix) {
    prefix_ = prefix; return *this;
  }

  size_t n_;
  char c_;
  std::string prefix_;
};

struct RepeatResult {
  std::string r_;
};

void Repeat(const RepeatArgs& args, RepeatResult& res) throw() {
  res.r_ = args.prefix_;
  for (size_t i = 0; i < args.n_; ++i)
    res.r_ += args.c_;
}

int main() {
  RepeatResult res;
  Repeat(RepeatArgs().set_prefix("hello world").set_c('!').set_n(5), res);
  std::cout << res.r_ << std::endl;
  return 0;
}
Some people would probably prefer the with_ prefix as opposed to set_ for the builder's setters.

Note that the args must be a const RepeatArgs& type so that the arguments of Repeat() can be built using a temporary object, like seen in the example above.

I chose to leave the fields public (as the default for struct) because the fields of the Args struct directly correspond to the arguments that a function would have taken directly, hence the additional getter abstraction is not needed. The purpose of the setters is to allow chaining by returning reference to *this. Contrary to a typical builder pattern, there is no need for a final build() call because the reference can be used directly.

Not having build() means that argument checking must be done in the function that takes the Args struct. Some may argue that it is better to do argument checking in build(), but build() is supposed to return a reference to the Args struct, so there is no good way to report invalid arguments, sort of raising an exception or aborting in the form of assertion failure.

The default constructor in this case simply initializes fields by the default constructor of the respective types, with the plain old types size_t and char to 0lu and '\0', and std::string to the empty string. The default constructor could always give them different default values suitable for the Repeat() function in the constructor's initializer list.

The Repeat() function can also use the following interface if return value optimization is desired.
RepeatResult Repeat(const RepeatArgs& args) throw();
However, the benefit of the former interface is that the return value can be used to indicate error status. For example,
enum RepeatStatus {
  ok = 0,
  out_of_memory = 1,
  ...
};

RepeatStatus Repeat(const RepeatArgs& args, RepeatResult& res) throw();
The argument builder pattern can also be used for methods that have complex arguments.
class Xyzzy {
 public:
  struct FooArgs {
    ...
  };

  struct FooResult {
    ...
  };

  enum FooStatus {
    ...
  };

  FooStatus Foo(const FooArgs& args, FooResult& res) throw();
};
The declaration of the Foo() method is now very similar to that generated for a protocol buffer service, but better because of the use of fluent builder interface. The idea is that if protocol buffer could generate classes using the named argument builder pattern, then that would make protocol buffer even simpler to use and still very lightweight.