Chapter 1 - Let's get some Context - Ximr / DIGIC 7Note: This chapter may also apply to Digic 6. I had no chance to analyze any Digic 6 ROM, but i know XimrExe is referenced in those too.Future me: I dug into M10 (Digic 6, Powershot codebase) on CHDK forums. Ximr functions are very similar (in fact, nearly identical - earlier implementation) to the description below. RefreshVrmsSurface() and other non-Ximr named functions are specific to EOS codebase. For more details on PowerShots look into links from Chapter 6Even more future me: 750D and 5D4 confirmed to use just "earlier" implementation, our rendering code so far works well.RefreshVrmsSurface()Let's start with this function. It can be found by string referencing that name. It will be important in D8+ too.
Function belongs to GUI code, and is used to redraw screen to YUV buffers after RGBA buffers has changed.
It will also swap YUV buffers as last step.
Wait, what? Yup, I don't know where to start, so I let this just sink in

On the very beginning it has this code:
if (ximr_initialized == 0) {
Initialize_Ximr();
ximr_initialized = 1;
}
XimrXimr refers to family of "lower level" functions that utilize GPU (
ZICO core) to merge input buffers into output buffer.
From now on, I will refer to input buffers as
layers and output buffer as
Output Chunk.
Ximr ContextXimr family of functions uses structure known as Ximr Context.
Exact structure seems to be tied to DIGIC generation (size 0x300 on D7, 0x31C on D8, 0x7A0 on DX).
Structure contains a set of data that will be transferred to
ZICO core for the rendering to happen.
Initialize_Ximr()Helper function that will prepare empty `Ximr Context` structure and then set some details about:
- Output Chunk MARV, scaling, offsets, etc..
- Layers MARV, offsets, color parameters, enabled or not, etc...
This function is just a helper to call real Ximr functions, specific to camera. From this we know that 200d has only one Layer and Ximr Context is capable of having up to 8 of them:
XimrSetLayerVisibility(&XimrContext,0,1);
XimrSetInputLayerMARV(&XimrContext,0,bmp_vram_info.rgb_vram,0);
//...
XimrSetLayerVisibility(&XimrContext,1,0);
XimrSetLayerVisibility(&XimrContext,2,0);
//...
XimrSetLayerVisibility(&XimrContext,7,0);
XimrExe(XimrContext* pXC)Function that sends structure to
ZICO for rendering. Call is easy to notice inside of
RefreshVrmsSurface() as it is done just after obtaining
WINSYS semaphore.
Chapter 1.1 - Drawing in RGBYou may have noticed in Initialize_Ximr:
XimrSetInputLayerMARV(&XimrContext,0,bmp_vram_info.rgb_vram,0);
This leads us directly into Canon RGBA buffer (the one GUI is rendered into). Canon code would update this buffer, set
refresh_display_needed flag to 1 and call
RefreshVrmsSurface, which will tirgger re-render if flag is set.
Early tests by just stealing this buffer and calling
RefreshVrmsSurface were not exactly successful. Probably due to a race with Canon code - remember
WINSYS semaphore I mentioned earlier?
@names_are_hard and/or @turtius quickly noticed that we may go another way and just take a shortcut. This got implemented:
//draw on RGBA VRAM first
take_semaphore(winsys_sem, 0);
XimrExe((void *)XIMR_CONTEXT);
give_semaphore(winsys_sem);
...and it was successful. In fact, this is a part of how current builds render GUI on 200D. See @names_are_hard video:
Chapter 1.2 - Layers. Onions have layers. Ximr has layers.With
Initialize_Ximr function calls it was easy to spot what is used by Canon code to setup "Layer 0".
In fact, with just a few calls (except creating and allocating own MARV which I skipped there):
XimrSetInputLayerMARV (XimrContext, layerId, pNewLayer, 0);
XimrSetInputLayer_unk (XimrContext, layerId, 0, 3, 0xff);
XimrSetInputLayerColorParams (XimrContext, layerId, pNewLayer, 1, 1);
XimrSetInputLayerVisibility (XimrContext, layerId, 1);
XimrSetInputLayerDimensions (XimrContext, layerId, off_x, off_y, w, h, 0, 0);
I was able to setup own drawing surface, independent from Canon code as Layer 1.
In such a case, one could need to call redraw like Canon code does:
void surface_redraw()
{
display_refresh_needed = 1;
sync_caches();
RefreshVrmsSurface();
}
...but it also works with pure
XimrExe call mentioned earlier.
Those are excerpts from my Ximr integration PoC:
Github linkInteresting part is that on Digic 7 only, buffer itself must be aligned to 256 blocks - otherwise it will be rendered shifted (misaligned).
As you can see on the movie below, my layer is "above" Canon GUI. As RGBA layers support transparency and Canon GUI code doesn't know they exists, there's no interference with that.