Displaying Custom Textures
Display live GPU textures and native bitmaps inside web pages using custom image sources.
On this page
You can display native images (such as game textures, a minimap, or offscreen renders) directly on a page. HTML and CSS then position, size, and animate them like any standard web image.
To connect an image to the page, place an .imgsrc file in the web assets and register an ImageSource in native code under the same name.
Creating the .imgsrc File
An .imgsrc file is a plain-text asset containing the format header on the first line and an identifier on the second.
IMGSRC-V1
minimap
Place this file alongside the web assets and reference it anywhere the page accepts an image URL.
<img src="minimap.imgsrc" />
👍 Registration Order Does Not Matter
The page can load before you register the image source. The image appears on the page as soon as you add the matching source.
Displaying a Bitmap
Displaying an in-memory bitmap is the simplest way to show native images on a page— it works with both the CPU and GPU renderers without custom driver code.
To expose a bitmap to the page, wrap a Bitmap (see Working with Bitmaps) with ImageSource::CreateFromBitmap() and register it with ImageSourceProvider.
#include <Ultralight/Ultralight.h>
using namespace ultralight;
RefPtr<Bitmap> portrait;
RefPtr<ImageSource> portrait_source;
void RegisterPortrait() {
///
/// Draw the portrait into a 128 by 128 bitmap (a blank one will do for now).
///
portrait = Bitmap::Create(128, 128, BitmapFormat::BGRA8_UNORM_SRGB);
portrait->Erase();
///
/// Wrap it and register it under the identifier from portrait.imgsrc.
///
portrait_source = ImageSource::CreateFromBitmap(portrait);
ImageSourceProvider::instance().AddImageSource("portrait", portrait_source);
}
When the page renders an element using the image source, the library samples the bitmap's pixels directly.
To load block-compressed bitmaps and .dds files directly from markup instead, see Compressed Textures (requires Pro edition or higher).
Displaying a GPU Texture
You can composite a live GPU texture (such as a render target or a video stream) directly into a page without copying pixels back to CPU memory.
📘 GPU Renderer Required
Displaying a GPU texture requires a view configured with
ViewConfig::is_accelerated = trueand a custom GPU driver. The driver binds the native texture whenever the renderer draws the element (see GPU Renderer Overview).
Registering the Texture
To expose a GPU texture to the page, reserve an identifier from the GPU driver, wrap it with ImageSource::CreateFromTexture(), and register it with ImageSourceProvider.
RefPtr<ImageSource> minimap_source;
void RegisterMinimap() {
///
/// Reserve a texture id from our GPUDriver (0 is reserved for "no texture").
///
uint32_t texture_id = Platform::instance().gpu_driver()->NextTextureId();
// Pseudo-code, create your native texture here and have your driver bind it
// whenever texture_id shows up in a draw command.
///
/// Create a 512 by 512 image source that samples the whole texture.
///
Rect uv = { 0.0f, 0.0f, 1.0f, 1.0f };
minimap_source = ImageSource::CreateFromTexture(512, 512, texture_id, uv);
///
/// Register it under the identifier from minimap.imgsrc.
///
ImageSourceProvider::instance().AddImageSource("minimap", minimap_source);
}
Calling GPUDriver::NextTextureId() generates a non-zero identifier for the texture— ID 0 is reserved to indicate no texture. When creating the ImageSource, pass the image's dimensions in pixels for page layout, the reserved texture ID, and the texture UV coordinates to sample.
Binding the Texture in the GPU Driver
When the page renders an element using the image source, the library emits geometry with the specified texture ID and UV coordinates. The GPU driver must intercept this ID and bind the matching native texture (see Implementing a GPUDriver).
Providing a Backing Bitmap
You can pass an optional Bitmap as the final parameter of ImageSource::CreateFromTexture(). The library samples this bitmap when rendering on a CPU-backed view or when operations require raw pixel data on the host— without a backing bitmap, those views have nothing to draw.
When providing a backing bitmap, you must update its pixel buffer whenever the GPU texture changes to keep both in step.
Updating and Removing Images
Redrawing After Changes
Call ImageSource::Invalidate() whenever you modify an image's underlying pixels to schedule a redraw on the next frame.
void OnMinimapChanged() {
///
/// We drew a new frame into the texture; ask the page to redraw the image.
///
minimap_source->Invalidate();
}
The library does not track changes to native textures or bitmap memory automatically. Without calling Invalidate(), the page continues displaying the previous frame.
Removing an Image Source
When an image is no longer needed, unregister it by passing its identifier to ImageSourceProvider::RemoveImageSource().
void Shutdown() {
///
/// Unregister both identifiers when we are done with them.
///
ImageSourceProvider::instance().RemoveImageSource("minimap");
ImageSourceProvider::instance().RemoveImageSource("portrait");
}
🚧 Call from the Renderer's Thread
Register, invalidate, and remove image sources on the Renderer's thread only. These calls reach the page directly.