vidya/crates/renderer_resources/AGENTS.md
2026-10-24 21:17:06 +02:00

9.9 KiB

renderer_resources

Purpose

renderer_resources owns Vulkan buffer, image, view, descriptor, sampler, shader-module, and pipeline construction on the renderer_device layer. It handles resource memory and handle lifetimes, but contains no window, swapchain, or presentation orchestration; those remain in renderer. It must not depend on renderer.

Module map

  • lib.rs: re-exports Device, Error, Result, device, and make_extension from renderer_device; declares four public resource modules.
  • buffers.rs: BufferDesc and Buffer; Vulkan buffer creation, GPU allocation/binding, raw access, and host mapping.
  • images.rs: ImageDesc, Image, ImageViewDesc, ImageView, subresource ranges, extents, offsets, and queue ownership. ImageInner distinguishes allocated images from borrowed swapchain images.
  • pipeline.rs: shader-stage and graphics/compute pipeline descriptions; DescriptorPool, DescriptorSetLayout, PipelineLayout, Sampler, ShaderModule, and Pipeline.
  • util.rs: eq_f32, ord_f32, hash_f32, F32, and the crate-private weak_vec module / WeakVec used by image view tracking.

Key types and API

  • These modules are public from renderer_resources; the crate root re-exports the core device types and device module from renderer_device for resource construction.
  • BufferDesc configures Vulkan buffer flags, size, usage, queue families, memory location, allocation strategy, and optional debug name. Buffer::new allocates/binds memory; map and map_mut return mapped slices when available.
  • Buffer::raw returns the Vulkan handle and len returns the configured size. Mapping is bounded to the descriptor size, not the allocator block size.
  • ImageDesc configures image type, format, extent, layers/mips, samples, tiling, usage, initial layout, queue sharing, and allocation.
  • Image::new creates an allocated image. Image::new_with_allocation accepts an explicit renderer_device::device::Allocation and validates size and memory-type compatibility.
  • Image::from_swapchain_raw(image, device, format, extent, usage) builds an image wrapper for an image owned by a swapchain; renderer calls it from Swapchain::acquire_image.
  • ImageViewDesc describes a view's type, format, component mapping, aspect, mip range, and layer range. Image::create_view validates compatibility and returns ManuallyDrop<ImageView>.
  • Image::create_view resolves remaining mip/layer sentinels against the parent image, defaults an undefined view format to the image format, and checks image/view kind and format compatibility.
  • Extent, Offset, and MipRange represent image dimensions, offsets, and mip/layer ranges. QueueOwnership carries source and destination family indices.
  • Image exposes its raw handle, format, dimensions, and optional allocation; swapchain-backed images have no allocation.
  • Pipeline configuration records include ShaderStageDesc, GraphicsPipelineDesc, ComputePipelineDesc, PipelineLayoutDesc, DescriptorSetLayoutDesc, DescriptorSetLayoutBindingDesc, DescriptorPoolDesc, DescriptorSetAllocDesc, SamplerDesc, and fixed-function state descriptions.
  • Fixed-function state records are VertexInputState, TessellationState, InputAssemblyState, ViewportState, DepthBiasState, RasterizationState, MultisampleState, DepthBounds, DepthState, StencilState, DepthStencilState, ColorBlendState, RenderingState, and DynamicState.
  • Pipeline wraps graphics or compute Vulkan pipelines and retains its PipelineLayout in an Arc. Creation uses device.pools.pipeline_cache.raw.
  • DescriptorPool serializes allocation/reset with a mutex; descriptor set layouts and pipeline layouts own their Vulkan handles.
  • DescriptorPool::allocate returns raw descriptor-set handles from the provided DescriptorSetLayout values and optionally assigns names from DescriptorSetAllocDesc.
  • DescriptorSetLayout::new applies per-binding descriptor flags when the device supports Vulkan 1.2 or VK_EXT_descriptor_indexing.
  • PipelineLayoutDesc references descriptor-set layouts and push-constant ranges; PipelineLayout owns the created Vulkan layout.
  • SamplerDesc describes filtering, addressing, anisotropy, compare, LOD, and border settings; Sampler::new creates the Vulkan sampler.
  • ShaderModule::new_from_path reads a shader file relative to the process working directory; file-open failures map to Error::AssetMissing, while read/Vulkan failures use their corresponding Error conversions. new_from_memory accepts SPIR-V words.
  • GraphicsPipelineDesc supports render-pass/subpass inputs or dynamic RenderingState; optional fixed-function states are converted during pipeline creation.
  • SamplerDesc uses eq_f32 / hash_f32 for float-valued fields. F32 provides Eq/Ord/Hash semantics using the same helpers.
  • WeakVec<T> stores Weak<T> references and prunes entries whose strong count is zero when growing; it is crate-private, not public API.

Invariants and gotchas

  • This crate consumes the renderer_device ownership types and re-exports; do not add a parallel device model or a dependency on renderer.
  • Image::from_swapchain_raw stores the raw image in the ImageInner::Swapchain variant with its device. The swapchain owns that Vulkan image; never destroy it as an independently allocated image.
  • from_swapchain_raw records a 2D, one-mip, one-layer, single-sample, optimal-tiled image with PRESENT queue sharing and UNDEFINED initial layout; the caller supplies format, extent, and usage.
  • from_swapchain_raw retains a Device for views and device queries, but not ownership of the image handle or swapchain lifetime; the renderer's frame/swapchain token must keep the swapchain alive.
  • Allocated images and buffers use DeviceObject for Vulkan handles and allocation ownership. Keep resource destruction ordered before freeing bound memory.
  • Buffer equality compares the raw buffer handle; Image equality compares the raw image handle. Descriptor equality is separate from resource object identity.
  • Allocation::Owned owns a device-managed allocation; Shared shares it through Arc and permits mutable access only when uniquely held; Unmanaged carries no allocation.
  • ImageView retains Arc<Image> so the source image outlives the view. Image::create_view returns ManuallyDrop<ImageView>; callers must transfer/drop it deliberately.
  • Image tracks views through WeakVec<ImageView> to avoid a strong-reference cycle. The weak list does not keep views alive.
  • ImageView's DeviceObject owns and destroys the Vulkan view; its parent Arc<Image> must remain alive through view destruction.
  • ImageDesc and BufferDesc omit alloc_scheme from both Hash and Eq; their Hash implementations omit name, and Eq also omits name. Do not treat these descriptors as complete resource identities without accounting for these fields.
  • Descriptor hashing/equality covers resource shape, usage, sharing, and memory location but not every construction input. Update both implementations together if adding descriptor-keyed resource deduplication.
  • Pipeline retains its layout with Arc; descriptor-pool operations are mutex-serialized. Keep these lifetime and synchronization guarantees when changing constructors or wrappers.
  • DescriptorPool::allocate returns raw vk::DescriptorSet handles; keep the owning pool alive while those sets are in use. Descriptor sets are not wrapped in owning resource objects here.
  • Descriptor-set layout binding flags are chained into layout creation when the device API version or descriptor-indexing extension supports them.
  • Pipeline cache lifetime and teardown belong to renderer_device; use the device's existing cache rather than adding a resource-crate cache.
  • Renderer shader assets remain under crates/renderer/shaders; this crate does not own those assets.
  • renderer accesses these modules through crate-private aliases. Making a resource type available in renderer's public API requires an explicit API/re-export decision there.

Conventions

  • renderer_resources has no crate-level nightly feature attributes; use APIs available under the workspace's pinned nightly toolchain and edition 2024.
  • Depend on renderer_device paths re-exported at this crate root (crate::Device, crate::device::..., and crate::make_extension) rather than introducing a dependency on renderer.
  • Do not commit changes. Verify with cargo check -p renderer_resources and cargo check --workspace from the workspace root.

Change guidance

  • Add buffer, image, view, descriptor, sampler, shader, and pipeline constructors in this crate, not in renderer's orchestration layer.
  • For each Vulkan handle, preserve the distinction between resource-owned handles and externally owned handles such as raw swapchain images.
  • Keep image-view range/format/kind validation close to image/view construction. Cover REMAINING_MIP_LEVELS and REMAINING_ARRAY_LAYERS normalization when changing range handling.
  • When modifying descriptor equality/hash behavior, update both together and account for name and alloc_scheme deliberately.
  • Preserve renderer_device::device::Allocation ownership semantics when accepting shared or unmanaged memory; ensure bound resources outlive their allocation use.
  • Keep SamplerDesc float equality and hashing consistent across every float field.
  • renderer_resources::util::weak_vec is internal support for images; do not expose or move it back into renderer without reviewing view ownership cycles.
  • Keep shader loading errors compatible with renderer_device::Error, and test path-based loading relative to the workspace runtime working directory.
  • Keep this crate independent of swapchain/window wrappers. Integrate swapchain images through the raw image plus explicit device, format, extent, and usage, not renderer types.
  • Keep pipeline descriptors, Vulkan state conversion, and handle ownership in this crate rather than moving resource ownership back into renderer orchestration.