How context objects work

This page documents the working bentween the RenderCanvas and the context object.

Introduction

The process of rendering to a canvas can be separated in two parts: rendering and presenting. The role of the context is to facilitate the rendering, and to then present the result to the screen. For this, the canvas provides one or more present-methods. Each canvas backend must provide at least the ‘screen’ or ‘bitmap’ present-method.

Rendering                 Presenting

            ┌─────────┐               ┌────────┐
            │         │  ──screen──►  │        │
──render──► | Context │      or       │ Canvas │
            │         │  ──bitmap──►  │        │
            └─────────┘               └────────┘

This means that for the context to be able to present to any canvas, it must support both the ‘bitmap’ and ‘screen’ present-methods. If the context prefers presenting to the screen, and the canvas supports that, all is well. Similarly, if the context has a bitmap to present, and the canvas supports the bitmap-method, there’s no problem.

It get’s a little trickier when there’s a mismatch, but we can deal with these cases too. When the context prefers presenting to screen, the rendered result is probably a texture on the GPU. This texture must then be downloaded to a bitmap on the CPU. All GPU API’s have ways to do this.

            ┌─────────┐                     ┌────────┐
            │         │  ──tex─┐            │        │
──render──► | Context │        |            │ Canvas │
            │         │        └─bitmap──►  │        |
            └─────────┘                     └────────┘
                     download from gpu to cpu

If the context has a bitmap to present, and the canvas only supports presenting to screen, you can use a small utility: the BitmapPresentAdapter takes a bitmap and presents it to the screen.

            ┌─────────┐                        ┌────────┐
            │         │           ┌─screen──►  │        │
──render──► | Context │           │            │ Canvas │
            │         │  ──bitmap─┘            │        |
            └─────────┘                        └────────┘
                      use BitmapPresentAdapter

This way, contexts can be made to work with all canvas backens.

Canvases may also provide additionally present-methods. If a context knows how to use that present-method, it can make use of it. Examples could be presenting diff images or video streams.

            ┌─────────┐                               ┌────────┐
            │         │                               │        │
──render──► | Context │  ──special-present-method──►  │ Canvas │
            │         │                               │        |
            └─────────┘                               └────────┘

Context detection

Anyone can make a context that works with rendercanvas. In order for rendercanvas to find, it needs a little hook.

rendercanvas._context.rendercanvas_context_hook(canvas, present_methods)

Hook function to allow rendercanvas to detect your context implementation.

If you make a function with this name available in the module your.module, rendercanvas will detect and call this function in order to obtain the canvas object. That way, anyone can use canvas.get_context("your.module") to use your context. The arguments are the same as for ContextInterface.

Context API

The class below describes the API and behavior that is expected of a context object. Also see https://github.com/pygfx/rendercanvas/blob/main/rendercanvas/_context.py.

class rendercanvas._context.ContextInterface(canvas, present_methods)

The interface that a context must implement, to be usable with a RenderCanvas.

Parameters:
  • canvas (BaseRenderCanvas) – the canvas to render to.

  • present_methods (dict) – The supported present methods of the canvas.

The present_methods dict has a field for each supported present-method. A canvas must support either “screen” or “bitmap”. It may support both, as well as additional (specialized) present methods. Below we list the common methods and what fields the subdicts have.

  • Render method “screen”:
    • “window”: the native window id.

    • “display”: the native display id (Linux only).

    • “platform”: to determine between “x11” and “wayland” (Linux only).

  • Render method “bitmap”:
    • “formats”: a list of supported formats. It should always include “rgba-u8”. Other options can be be “i-u8” (intensity/grayscale), “i-f32”, “bgra-u8”, “rgba-u16”, etc.

property canvas

The associated canvas object. Internally, this should preferably be stored using a weakref.

present()

Present the result to the canvas.

This is called by the canvas, and should not be called by user-code.

The implementation should always return a present-result dict, which should have at least a field ‘method’. The value of ‘method’ must be one of the methods that the canvas supports, i.e. it must be in present_methods.

  • If there is nothing to present, e.g. because nothing was rendered yet:
    • return {"method": "skip"} (special case).

  • If presentation could not be done for some reason:
    • return {"method": "fail", "message": "xx"} (special case).

  • If present_method is “screen”:
    • Render to screen using the info in present_methods['screen']).

    • Return {"method", "screen"} as confirmation.

  • If present_method is “bitmap”:
    • Return {"method": "bitmap", "data": data, "format": format}.

    • ‘data’ is a memoryview, or something that can be converted to a memoryview, like a numpy array.

    • ‘format’ is the format of the bitmap, must be in present_methods['bitmap']['formats'] (“rgba-u8” is always supported).

  • If present_method is something else:
    • Return {"method": "xx", ...}.

    • It’s the responsibility of the context to use a render method that is supported by the canvas, and that the appropriate arguments are supplied.

Adapter

class rendercanvas.utils.bitmappresentadapter.BitmapPresentAdapter(canvas, present_methods)

An adapter to present a bitmap to a canvas using wgpu.

This adapter can be used by context objects that want to present a bitmap, when the canvas only supports presenting to screen.

present_bitmap(bitmap)

Present the given bitmap to screen.

Supported formats are “rgba-u8” and “i-u8” (grayscale). Returns the present-result dict produced by GPUCanvasContext.present().