openage icon indicating copy to clipboard operation
openage copied to clipboard

Use cython fused types (templated functions) to remove redundancy from smp.pyx and smx.pyx

Open TheJJ opened this issue 4 years ago • 2 comments

Required skills: Cython

Difficulty: Medium

SMX is the graphics storage format in AoE2:DE. We export these files to PNG in the converter.

Because of the different storage formats and layers, the process_drawing_cmds function exists 3 times in smp.pyx, and 5 times in smx.pyx, both in openage/convert/value_object/read/media/. We can use one generic function (one for smp, one for smx) that can handle all of the features at once.

We can do that using templates in Cython, called "fused functions".

Here's an example how it works in principle.

  • The rolf function is saved two times - once for variant_1 and once for variant_2. And it won't have any if in its body then.
  • Thus these if CompressionVariant is lines behave like if constexpr inside a templated entity.
cdef class variant_1:
    pass
cdef class variant_2:
    pass

cdef fused CompressionVariant:
    variant_1
    variant_2

cdef rolf(CompressionVariant a):
    print("common!")
    if CompressionVariant is variant_1:
        print("variant 1")          
    elif CompressionVariant is variant_2: 
        print("variant 2") 
    else:
        print('wtf?')   


cdef main():
    print("run")
    cdef variant_1 v1 = variant_1()
    cdef variant_2 v2 = variant_2()
    rolf(v1)    
    rolf(v2)      

main()

We defined multiple variants of process_drawing_cmds to avoid a lot of branches (ifs) in the codepath, since this function is called more than a million times during the conversion process.

You can test your changes with the singlefile media converter.

Further reading:

TheJJ avatar Jan 21 '21 22:01 TheJJ

cdef class variant_1: pass

cdef class variant_2: pass

cdef fused CompressionVariant: variant_1 variant_2

cdef void rolf(CompressionVariant a): print("common!") if type(a) is variant_1: print("variant 1") elif type(a) is variant_2: print("variant 2") else: print('wtf?')

def main(): print("run") cdef variant_1 v1 = variant_1() cdef variant_2 v2 = variant_2() rolf(v1) rolf(v2) cythonize -i example.pyx python -c "import example; example.main()"

Sujal-Rana-88 avatar May 31 '23 06:05 Sujal-Rana-88