PrintfAny programming language has the equivalent of C/C++ printf. For instance, every "Hello World!" program uses a print function to output text to a console, file or web page... I thought about what it would take to have a similar API that works for images, the same way printf works for text. The API would have to be:
- Easy to use like printf.
- Immediate. You should see your images (somewhere) as soon as the print function is called.
- Unobtrusive. It should not alter a program's flow or dramatically affect its performance.
- It should rely on technology that is native to any system.
Designing Printf For ImagesWhat if you could tell a program to export raw image data at a moment of your choosing? This would be an improvement over the way C/C++ printf works. An image would be exported out of a program when the developer chooses to while the rest of the time the program would simply run unaffected. The solution I designed, has three parts.
- Just like C/C++ printf has a command line terminal as default output, I needed an outlet for images and I think Pico Pixel desktop application would be perfect for it. Pico Pixel is an image viewer we created. It is fast, simple, supports many pixel formats (DXT, BCn, ETC2...) and file formats such as OpenEXR, HDR, KTX and more.
- A C/C++ API. Developers call functions of the API to export images out of programs. The API is written in simple C/C++ that any compiler can handle.
- A communication system between a program and Pico Pixel. Network sockets are good for the job. Sockets libraries are everywhere. They work across hardware platforms and OSes. They are very well documented.
SDK IntegrationAs I said before, calling printf in C/C++ always outputs text in the console and this is not desirable for images. To prevent images from being sent everytime code execution goes over a call to PixelPrintf, we need something called a marker. Markers are objects used by PixelPrintf to decide whether to send image data to Pico Pixel or not. Every marker has an associated counter of integer values. While a marker's counter value is greater than 0, any call to PixelPrintf with the marker will be carried through. Each time a marker is used, its counter value is decremented by one. When a marker's counter value reaches zero, the marker can no longer be used to send image data to Pico Pixel. Its counter value has to be reloaded before it can be used again. Pico Pixel provides a user interface to reload counters. As a result, Pico Pixel acts as the trigger for image snapshot in a program. Here is what the code looks like.
PicoPixelClient pico_pixel_client("GlxGears"); pico_pixel_client.StartConnection(); // the last parameter '0' means the marker use_count is 0. int marker = pico_pixel_client.CreateMarker(std::string("Color Buffer"), 0); int marker = pico_pixel_client.CreateMarker(std::string("Depth Buffer"), 0); // Send the defined markers to PicoPixel desktop application pico_pixel_client.SendMarkersToPicoPixel(); // Image data is sent if and only if the marker's use_count is greated than 0. // A marker's use_count is decremented each time the marker is used. pico_pixel_client.PixelPrintf( marker, // data marker "color-framebuffer", // image name to appear in Pico Pixel desktop application PicoPixelClient::PIXEL_FORMAT_BGR8, // image pixel data format 400, // image width 300, // image height 1200, // image row pitch in bytes FALSE, // set to TRUE if the data is in srgb FALSE, // set to TRUE to rotate the image horizontally when displayed raw_data // char* pointer to the image raw data );By instrumenting a program with the code above, Pico Pixel interface mirrors the markers that have been defined. To take a snapshop of a texture buffer, set a value greater than 0 in the marker used to export the surface. When markers in Pico Pixel are synchronized with markers in the program, images are sent whenever code execution goes over the PixelPrintf call that use markers with positive counter's values.