Function at fc23d2b8 is responsible for redraw and for XimrContext structure population.
XimrContext is the structure passed as the first argument to most functions and then to XimrExe.
Disambiguation - we call VRAM structure "MARV" in Magic Lantern (little endian signature).
"Output Chunk" as well as "Ximr Context" are names directly taken from XCM on EOS R+. (XCMStatus EvShell command)
"Flags" field of MARV is a bit different to what I'm used to - possible values are 0x04000002, 0x05000004 and 0x07000002.
On the left "color type", on the right probably bytes per pixel.
Max 8 layers like on 200D. Layer definition inside Ximr Context has identical offsets to 200D.
Ximr functions are easy to find as they always take Ximr Context as first param.
All layer manipulation functions are easy distinguishable for that as 2nd param is checked to be below MAX_LAYER_COUNT (8 in case od Digic 6/7, 6 for Digic 8,X)
Bad news: The very first call is XimrInitializeContext, which means it is recreated on every redraw. This is different to 200D/M50 which does it once on init.
It is however a bit similar to R+ where this is handled by XCM on every redraw.
Now, some stubs. Declarations fit those from 200D.
Names of those stubs are made up by their function, no strings exists for those in EOS roms too.
I left numbered params where I'm not sure of their meaning, but they are saved into XimrContext structure.
fc3ed850 XimrInitializeContext(pXC)
fc3edac0 XimrSetLayerVisibility(*pXC, layer_id, state)
fc3edcae XimrSetLayerColorParams(*pXC, layer, *pMARV, color_id, p5)
fc3edae0 XimrSetLayerMARV(*pXC, layer_id, *pMARV, p4)
fc3edb26 XimrSetLayerDimensions(*pXC, layer, src_x, src_y, src_w, src_h, dst_x, dst_y)
fc3edc30 XimrSetLayer_related_fc3edc30(pXC, layer_id, p3, p4, p5)
fc3edc68 XimrSetLayer_related_fc3edc68(pXC, layer_id, p3, p4, p5)
fc3ed9ec XimrSetOutputChunkMARV(*pXC, *pMARV)
fc3edaa2 XimrSetOputChunkResolution(*pXC, w, h)
Decomp of those functions is weird to understand, as it has the same caveat as 200D, R and R6:
pLayer = (XimrLayerData_withOffset *)((int)pContext + layerId * 0x3c);
There's some compiler optimization going on there, you need to offset actual context inside structure definition.
Undefined fields were not referenced (at least on 200D). Fields with _<offset> name - referenced, but unknown meaning, may have wrong data size.
struct XimrLayerData_withOffset {
//add fake paddng
uint8_t _0x48;
uint8_t _0x49;
undefined field_0x4a;
uint8_t _0x4b;
uint8_t _0x4c;
uint8_t _0x4d;
undefined field_0x4e;
undefined field_0x4f;
undefined field_0x50;
undefined field_0x51;
uint8_t _0x52;
uint8_t _0x53;
uint8_t _0x54;
uint8_t color_type;
uint8_t visibility;
uint8_t _0x57;
undefined field_0x58;
undefined field_0x59;
uint16_t src_y;
uint16_t src_x;
uint16_t src_h;
uint16_t src_w;
uint16_t dst_y;
uint16_t dst_x;
uint16_t enabled;
struct MARV MARV;
First "true" field is at offset 0x48 while looking at decomp. Layer definition inside XimrContext start at the same offsets and seems to have the same structure.
Layers data is located at the same Ximr Context offsets as 200D/Digic 7.
Output Chunk is defined at different offset in Ximr Context (start at 0x28 on M10, 0xC on 200D).
Interesting part - there's a condition on which 3rd layer is referenced:
XimrSetLayerVisibility(XimrContext,2,1);
XimrSetLayer_related_fc3edc68(XimrContext,2,0,2,*param_5);
If you are able to patch this function and inject some instructions, you should be able to add own layer like this:
XimrSetLayer_related_fc3edc30(XimrContext,0,0,3,0);
XimrSetLayerVisibility(XimrContext,0,1);
XimrSetLayerColorParams(XimrContext,0,pNewLayerMARV,colorId,0); //colorId is probably just 1
XimrSetLayerMARV(XimrContext,0,pNewLayerMARV,p4);
XimrSetLayerDimensions(XimrContext,0,0,0,src_x, src_y, src_w, src_h, dst_x, dst_y);
Please remember than on 200D (Digic 7) I had to align display buffer to 0x100, otherwise it was shifted by offset/4. This wasn't the case on R/Digic 8.
Other potential candidates to hook: very end of XimrInitializeContext, very beginning of XimrExe (before mzrm_createmessage).
I would just copy all parameters from layer 0/1, except pNewLayerMARV which you need to create yourself. In my experiments I created the structure myself, but there's a CreateMARV function you may try to use at fc586110:
MARV * CreateMARV (void * p1, uint32_t flags, uint width, uint height, uint p5, uint p6)
I never dug into functions that are not responsible for layers, except naming some of those. Goal was to add own layers, and those XimrSetLayer_* were enough to achieve that on 200D.