Graphics Extensions for Solar2D

This here is an extension to Solar2D’s supported image formats. Adding support for SVG, WEBP and QOI, you simply could not go wrong.

Perform crazy feats like generating and rendering complex graphs, drawing anti-aliased shapes and coding your graphics on the go with all the power of SVG.

Is your screen the size of a billboard? Support it too with zero quality loss and zero asset bloat. Dynamically scale up or down as needed.

Ditch your bloated sprite animations for smaller, prettier WEBP animations.

Load your images 3-4 times faster (varies) than PNG with the all new, super sleek QOI image format.

And if you’re still in need of the old reliables, JPEG and PNG support is included free of charge.

So get ahead of the competition today with this enviable graphics plugin. As always, github stars are a valid form of payment.

Currently supports android and windows.

So now that I’ve hopefully sold you on this idea, here’s the link to the github with the code, a simple sample and docs:

Report any issues you might be having with the plugin and I’ll do my best to fix them ASAP.

I’m seeking someone willing to get all Rusty :laughing: to help me build this plugin for iOS and macOS. Please note that you will have to compile Rust code for the svg renderer into static libraries for these platforms. I’m not sure how simple or difficult this will be. If you’re trying and failing, please reach out. I’ve had to do it already, so I might be able to help. I will credit you on the repository’s readme.

If you’re still reading, have a great day … or night.


I’ve tested this extension with a png image and a qoi image.
The result is that loading the qoi is much slower than loading the png.

1x time

100x times

local gfxe = require('plugin.gfxe')
local asset_reader = require('plugin.AssetReader')

function valueDisplay(value, x, y, time)
    local txt = display.newText(value, x, y, native.systemFont, 32)
    txt:setFillColor(1, 0, 0, 0.75)

    timer.performWithDelay(time or 30000, function()

local group = display.newGroup()
local w = 800 * 0.35
local h = 600 * 0.35
local name = "dice"
local prevTime = system.getTimer()

for i=1, 100 do
    local b = gfxe.newStaticImage(
            filename = string.format("images/qoi_test_images/%s.qoi", name),
            width = w, height = h
    b:translate(display.contentWidth - w * 0.5, display.contentCenterY)

local currentTime = system.getTimer()
valueDisplay("qoi:" .. (currentTime - prevTime), display.contentWidth - w * 0.5, display.contentCenterY + h * 0.55, 200000)

prevTime = system.getTimer()

for i=1, 100 do
    local tex = graphics.newTexture({type="image", filename = string.format("images/qoi_test_images/%s.png", name)})
    local a = display.newImageRect(tex.filename, tex.baseDir, w, h)
    a:translate(w * 0.5, display.contentCenterY)

currentTime = system.getTimer()
valueDisplay("png:" .. (currentTime - prevTime), w * 0.5, display.contentCenterY + h * 0.55, 200000)
[|attachment](upload:// (1014.4 KB)

Solar2d does load png faster than the plugin loads qoi. Probably some internal optimizations in the engine. However, when testing loading speeds of the plugin itself, qoi loads about 2-3 times faster than png.

The plugin can now decode QOI faster than Solar2D can decode PNG. See Graphics Extensions for Solar2D - #7 by devex

What is the speed like without the premultiplyAlpha? (I assume your test doesn’t need to convert from RGB to RGBA, so that’s all that really suggests itself, besides the decode itself.)

Does it gain anything from something like FastPremult in this paper?

So I swapped the old premultiplyAlpha for the new FastPremult and it has made quite a difference (thanks for that). However, it seems like QOI is still a bit slower than Solar2D at decoding the image (around 2 times slower). I’m not sure what’s causing this.

Are there any special SIMD instructions related to png decoding in Solar2D’s codebase? Maybe it’s just my computer? Also, it seems like Solar2D loads external textures 2ms slower than internal textures. Another oddity.

There was a flaw in @pickerel’s benchmark that failed to account for how Solar2D handles loading images. Solar2D’s texture caching ensures only 1 I/O operation takes place which saves a great deal of time.

gfxe.newStaticImage as used in @pickerel’s example ends up performing 100 I/O operations, which are very costly. This results in wildly incorrect results. The following are the results I got loading the image 100 times after the FastPremult optimization and with the I/O operations reduced to 1:

I see you’re using the Lua file API to load the image contents, so that would be my first guess. In addition to opening the file it will allocate and populate that string. It looks like Lua will build this up piecewise, 512 bytes (or whatever) at a time.

On the Windows side, it uses the GDI+ APIs, cf. here and what follows.

Those APIs might also be doing some memory mapping, e.g. something like this.

1 Like

You were right actually, performing the I/O operation separately from decoding the data actually makes the plugin decode QOI faster than Solar2D can decode PNG (not by that much though). Pretty cool.


1 Like

Cool stuff!

After further testing, it’d be great to see these be added into Solar2D core.

1 Like

It’s great if Solar2d supports qoi, svg and webp.