Skip to main content

HalContext

Trait HalContext 

Source
pub trait HalContext {
    type Hal: Hal;

Show 13 methods // Required methods fn capabilities(&self) -> &Capabilities; fn create_texture( &mut self, desc: &TextureDescriptor, ) -> Result<<Self::Hal as Hal>::Texture>; fn destroy_texture(&mut self, texture: <Self::Hal as Hal>::Texture); fn register_program(&mut self, program: &RuntimeProgram) -> Result<u32>; fn submit_batch_textured( &mut self, target: &mut <Self::Hal as Hal>::Texture, batch: &Batch, pass: PassDescriptor, textures: &[&<Self::Hal as Hal>::Texture], ) -> Result<()>; fn read_texture( &mut self, texture: &mut <Self::Hal as Hal>::Texture, ) -> Result<Vec<u8>>; fn write_texture( &mut self, texture: &mut <Self::Hal as Hal>::Texture, pixels: &[u8], ) -> Result<()>; // Provided methods fn submit_batch( &mut self, target: &mut <Self::Hal as Hal>::Texture, batch: &Batch, pass: PassDescriptor, ) -> Result<()> { ... } fn create_exportable_texture( &mut self, _extent: Extent2D, _format: PixelFormat, _modifiers: &[Modifier], ) -> Result<<Self::Hal as Hal>::Texture> { ... } fn export_texture( &mut self, _texture: &<Self::Hal as Hal>::Texture, ) -> Result<ExternalImageDesc> { ... } fn submit_batch_deferred( &mut self, target: &mut <Self::Hal as Hal>::Texture, batch: &Batch, pass: PassDescriptor, ) -> Result<<Self::Hal as Hal>::Fence> { ... } fn submit_batch_deferred_textured( &mut self, _target: &mut <Self::Hal as Hal>::Texture, _batch: &Batch, _pass: PassDescriptor, _textures: &[&<Self::Hal as Hal>::Texture], ) -> Result<<Self::Hal as Hal>::Fence> { ... } fn retire_fence(&mut self, _fence: <Self::Hal as Hal>::Fence) { ... }
}
Expand description

A device, and the resources created from it.

§Why a batch rather than a command buffer

An earlier shape of this trait had callers record incrementally — begin a pass, bind a pipeline, draw, finish — mirroring how Vulkan itself works. Building a real backend showed that to be the wrong seam. What a backend actually wants is the whole Batch at once, because the useful decisions are all global to it: which draws can share a pipeline binding, how to lay out one shared vertex buffer, what to upload in a single copy. Handing over a stream of calls forces each backend to reconstruct that shape, and a record-and-replay backend would have to buffer the stream anyway just to see what it was given.

This stays explicit in the sense that matters — nothing is discovered at draw time and the caller states its whole intent up front — while leaving each backend free to realize it natively.

§Threading

These take &mut self, so a context is not yet usable for resource creation from several threads at once. The intended design is thread-safe creation behind &self, which needs interior mutability around the allocator. That is deferred rather than decided against: nothing creates resources off the recording thread yet, and adding the synchronization before there is a caller to shape it around would be guesswork.

Required Associated Types§

Required Methods§

Source

fn capabilities(&self) -> &Capabilities

What this device can do. The only thing callers branch on.

Source

fn create_texture( &mut self, desc: &TextureDescriptor, ) -> Result<<Self::Hal as Hal>::Texture>

Allocate a texture, or import an external image when the descriptor carries one.

Source

fn destroy_texture(&mut self, texture: <Self::Hal as Hal>::Texture)

Release a texture and its memory.

Source

fn register_program(&mut self, program: &RuntimeProgram) -> Result<u32>

Register a caller’s fragment program and return the name for it.

Registering the same payload twice gives the same name back rather than a second entry. That is not a convenience: a program leads to pipelines keyed by it, so registering one repeatedly would multiply the pipeline cache by the number of times a caller happened to ask – and a caller with no place to cache an index, which is every caller that renders a list of scenes, would do exactly that.

Source

fn submit_batch_textured( &mut self, target: &mut <Self::Hal as Hal>::Texture, batch: &Batch, pass: PassDescriptor, textures: &[&<Self::Hal as Hal>::Texture], ) -> Result<()>

Draw a batch whose materials sample textures.

textures is the table a Material::Image slot indexes. It is passed alongside the batch rather than held inside it because a batch is a description a recorder produces without touching the device, and a backend texture handle is not something it can name.

The target is borrowed mutably and the table immutably, so a batch cannot sample the target it draws into. That restriction is real rather than incidental — reading an attachment being written in the same pass needs machinery this does not have — and having the borrow checker state it is better than discovering it as a driver-dependent picture.

A slot with no entry is an error rather than a fallback: a paint silently drawn as something else is the failure nobody debugs from.

Source

fn read_texture( &mut self, texture: &mut <Self::Hal as Hal>::Texture, ) -> Result<Vec<u8>>

Copy a target back to host memory, tightly packed.

Part of the trait rather than a backend extra because the offscreen target is a first-class citizen: the entire golden and conformance apparatus is built on rendering to one and reading it back.

Source

fn write_texture( &mut self, texture: &mut <Self::Hal as Hal>::Texture, pixels: &[u8], ) -> Result<()>

Fill a texture from host memory, tightly packed and top row first.

The exact inverse of Self::read_texture, stated in the same layout, so a round trip through the pair is the identity on every backend. That is what lets it be checked without a decoder: write known bytes, read them back, compare.

Color must be premultiplied, matching what a render target holds and what a paint sampling this expects. A decoder usually produces straight alpha, so converting is the caller’s job. The distinction is invisible for an opaque image, which is what makes it worth stating here rather than leaving to be discovered.

Decoding images is out of scope for this project; getting already decoded pixels onto the device is not. Without this, an image shader could sample nothing but what the renderer itself had drawn.

Provided Methods§

Source

fn submit_batch( &mut self, target: &mut <Self::Hal as Hal>::Texture, batch: &Batch, pass: PassDescriptor, ) -> Result<()>

Draw a batch into a target.

A descriptor that preserves rather than clears composes several batches onto one target. A multisampled descriptor renders to a transient multisample buffer and resolves into the target, so the target stays single-sampled and readable either way.

Source

fn create_exportable_texture( &mut self, _extent: Extent2D, _format: PixelFormat, _modifiers: &[Modifier], ) -> Result<<Self::Hal as Hal>::Texture>

Allocate a target that can be shared with a display controller.

modifiers are the layouts the other side accepts, in preference order. The default reports the capability as absent, which is the honest answer for a backend that cannot do it: callers check DmaBufSupport::can_allocate_scanout and take the GBM-allocated path instead. This is capability gating rather than a stub — a backend that answered every method this way would be useless, but one that answers only the optional ones is correctly describing itself.

Source

fn export_texture( &mut self, _texture: &<Self::Hal as Hal>::Texture, ) -> Result<ExternalImageDesc>

Export a texture as a dma-buf for scanout or cross-device sharing.

Returns Error::Unsupported where DmaBufSupport::export is false; the DRM path then allocates through GBM and imports instead.

Source

fn submit_batch_deferred( &mut self, target: &mut <Self::Hal as Hal>::Texture, batch: &Batch, pass: PassDescriptor, ) -> Result<<Self::Hal as Hal>::Fence>

Submit a batch without waiting, returning something that signals when the GPU has finished.

A frame loop needs this rather than the waiting form: the returned fence is what gets handed to a display commit, and what decides when a frame slot may be reused.

Ordering between two of these is the caller’s, and nothing here checks it. Submitting twice into one target without waiting for the first is a write-after-write hazard: both calls are well formed, both succeed, and what lands is whichever the device finished last. A frame loop avoids it by construction, since a ring hands out a different slot each frame and will not reuse one until its fence has retired.

Source

fn submit_batch_deferred_textured( &mut self, _target: &mut <Self::Hal as Hal>::Texture, _batch: &Batch, _pass: PassDescriptor, _textures: &[&<Self::Hal as Hal>::Texture], ) -> Result<<Self::Hal as Hal>::Fence>

The same, for a batch whose materials sample textures.

What a frame with layers needs. The pass that lands in the image being presented is the one that composites the layers, so it samples the targets they were rendered into — and a deferred submission that could not sample anything meant such a frame could be rendered offscreen and never displayed.

The textures must outlive the submission, which the caller arranges: they cannot travel with the fence, because a fence is handed to a display commit and has to stay sendable while a texture tracks mutable state of its own.

Source

fn retire_fence(&mut self, _fence: <Self::Hal as Hal>::Fence)

Release a deferred submission once its work has completed.

Dyn Compatibility§

This trait is dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety".

Implementors§