khora_core/renderer/traits/
graphics_device.rs

1// Copyright 2025 eraflo
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use crate::math::dimension;
16use crate::renderer::api::*;
17use crate::renderer::error::ResourceError;
18use crate::renderer::traits::CommandEncoder;
19use std::fmt::Debug;
20use std::future::Future;
21
22/// Defines the abstract interface for a graphics device.
23///
24/// This trait is the central point of interaction with the underlying graphics API
25/// (like WGPU, Vulkan, etc.). It abstracts away the specifics of the backend and
26/// provides a unified API for creating, managing, and destroying GPU resources such
27/// as buffers, textures, and pipelines.
28///
29/// It is the cornerstone of the `khora-infra` crate's responsibility, where a
30/// concrete type will implement this trait to provide actual rendering capabilities.
31pub trait GraphicsDevice: Send + Sync + Debug + 'static {
32    // --- Shader Management ---
33
34    /// Creates a shader module from a descriptor.
35    ///
36    /// # Errors
37    /// Returns a [`ResourceError`] if the shader source is invalid or fails to compile.
38    fn create_shader_module(
39        &self,
40        descriptor: &ShaderModuleDescriptor,
41    ) -> Result<ShaderModuleId, ResourceError>;
42
43    /// Destroys a shader module, releasing its GPU resources.
44    fn destroy_shader_module(&self, id: ShaderModuleId) -> Result<(), ResourceError>;
45
46    // --- Pipeline Management ---
47
48    /// Creates a render pipeline from a descriptor.
49    ///
50    /// A render pipeline represents the entire configurable state of the GPU for a
51    /// draw call, including shaders, vertex layouts, and blend states.
52    ///
53    /// # Errors
54    /// Returns a [`ResourceError`] if the pipeline configuration is invalid or compilation fails.
55    fn create_render_pipeline(
56        &self,
57        descriptor: &RenderPipelineDescriptor,
58    ) -> Result<RenderPipelineId, ResourceError>;
59
60    /// Creates a pipeline layout from a descriptor.
61    ///
62    /// The pipeline layout defines the set of resource bindings (e.g., uniform buffers,
63    /// textures) that a pipeline can access.
64    ///
65    /// # Errors
66    /// Returns a [`ResourceError`] if the layout is invalid.
67    fn create_pipeline_layout(
68        &self,
69        descriptor: &PipelineLayoutDescriptor,
70    ) -> Result<PipelineLayoutId, ResourceError>;
71
72    /// Destroys a render pipeline, releasing its GPU resources.
73    fn destroy_render_pipeline(&self, id: RenderPipelineId) -> Result<(), ResourceError>;
74
75    // --- Buffer Management ---
76
77    /// Creates a new GPU buffer.
78    fn create_buffer(&self, descriptor: &BufferDescriptor) -> Result<BufferId, ResourceError>;
79
80    /// Creates a new GPU buffer and initializes it with the provided data.
81    /// This is often more efficient than `create_buffer` followed by `write_buffer` for static data.
82    fn create_buffer_with_data(
83        &self,
84        descriptor: &BufferDescriptor,
85        data: &[u8],
86    ) -> Result<BufferId, ResourceError>;
87
88    /// Destroys a GPU buffer, releasing its memory.
89    fn destroy_buffer(&self, id: BufferId) -> Result<(), ResourceError>;
90
91    /// Writes data to a specific region of a GPU buffer.
92    ///
93    /// # Arguments
94    /// * `id`: The identifier of the buffer to write to.
95    /// * `offset`: The offset in bytes from the beginning of the buffer to start writing.
96    /// * `data`: The slice of bytes to write into the buffer.
97    fn write_buffer(&self, id: BufferId, offset: u64, data: &[u8]) -> Result<(), ResourceError>;
98
99    /// Asynchronously writes data to a GPU buffer.
100    /// This can be more performant for large data uploads by avoiding stalls.
101    fn write_buffer_async<'a>(
102        &'a self,
103        id: BufferId,
104        offset: u64,
105        data: &'a [u8],
106    ) -> Box<dyn Future<Output = Result<(), ResourceError>> + Send + 'static>;
107
108    // --- Texture & Sampler Management ---
109
110    /// Creates a new GPU texture.
111    fn create_texture(&self, descriptor: &TextureDescriptor) -> Result<TextureId, ResourceError>;
112
113    /// Destroys a GPU texture, releasing its memory.
114    fn destroy_texture(&self, id: TextureId) -> Result<(), ResourceError>;
115
116    /// Writes data to a specific region of a GPU texture.
117    ///
118    /// # Arguments
119    /// * `texture_id`: The identifier of the texture to write to.
120    /// * `data`: The raw image data to write.
121    /// * `bytes_per_row`: The number of bytes for a single row of texels in `data`.
122    /// * `offset`: The 3D offset (x, y, z/layer) in the texture to start writing.
123    /// * `size`: The 3D extent (width, height, depth/layers) of the data to write.
124    fn write_texture(
125        &self,
126        texture_id: TextureId,
127        data: &[u8],
128        bytes_per_row: Option<u32>,
129        offset: dimension::Origin3D,
130        size: dimension::Extent3D,
131    ) -> Result<(), ResourceError>;
132
133    /// Creates a new texture view for a given texture.
134    /// A view describes how a shader will interpret a texture's data (e.g., its format, mip levels).
135    fn create_texture_view(
136        &self,
137        texture_id: TextureId,
138        descriptor: &TextureViewDescriptor,
139    ) -> Result<TextureViewId, ResourceError>;
140
141    /// Destroys a texture view.
142    fn destroy_texture_view(&self, id: TextureViewId) -> Result<(), ResourceError>;
143
144    /// Creates a new sampler.
145    /// A sampler defines how a shader will sample from a texture (e.g., filtering, wrapping).
146    fn create_sampler(&self, descriptor: &SamplerDescriptor) -> Result<SamplerId, ResourceError>;
147
148    /// Destroys a sampler.
149    fn destroy_sampler(&self, id: SamplerId) -> Result<(), ResourceError>;
150
151    // --- Command Management ---
152
153    /// Creates a new command encoder to record GPU commands.
154    ///
155    /// # Arguments
156    /// * `label`: An optional debug label for the command encoder.
157    fn create_command_encoder(&self, label: Option<&str>) -> Box<dyn CommandEncoder>;
158
159    /// Submits a previously recorded command buffer to the GPU's command queue for execution.
160    fn submit_command_buffer(&self, command_buffer: CommandBufferId);
161
162    // --- Device Introspection ---
163
164    /// Gets the texture format of the primary render surface.
165    fn get_surface_format(&self) -> Option<TextureFormat>;
166
167    /// Gets information about the active graphics adapter (GPU).
168    fn get_adapter_info(&self) -> RendererAdapterInfo;
169
170    /// Checks if a specific, optional rendering feature is supported by the backend.
171    fn supports_feature(&self, feature_name: &str) -> bool;
172}