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    // --- Compute Pipeline Management ---
76
77    /// Creates a compute pipeline from a descriptor.
78    ///
79    /// # Errors
80    /// Returns a [`ResourceError`] if the pipeline configuration is invalid or compilation fails.
81    fn create_compute_pipeline(
82        &self,
83        descriptor: &ComputePipelineDescriptor,
84    ) -> Result<ComputePipelineId, ResourceError>;
85
86    /// Destroys a compute pipeline, releasing its GPU resources.
87    fn destroy_compute_pipeline(&self, id: ComputePipelineId) -> Result<(), ResourceError>;
88
89    // --- Bind Group Management ---
90
91    /// Creates a bind group layout from a descriptor.
92    ///
93    /// A bind group layout describes the structure and types of resources that can be
94    /// bound to shaders at a specific bind group index.
95    ///
96    /// # Errors
97    /// Returns a [`ResourceError`] if the layout is invalid.
98    fn create_bind_group_layout(
99        &self,
100        descriptor: &BindGroupLayoutDescriptor,
101    ) -> Result<BindGroupLayoutId, ResourceError>;
102
103    /// Creates a bind group from a descriptor.
104    ///
105    /// A bind group represents the actual bound resources (buffers, textures, etc.)
106    /// that conform to a specific bind group layout.
107    ///
108    /// # Errors
109    /// Returns a [`ResourceError`] if the bind group configuration is invalid or
110    /// doesn't match its layout.
111    fn create_bind_group(
112        &self,
113        descriptor: &BindGroupDescriptor,
114    ) -> Result<BindGroupId, ResourceError>;
115
116    /// Destroys a bind group layout, releasing its resources.
117    fn destroy_bind_group_layout(&self, id: BindGroupLayoutId) -> Result<(), ResourceError>;
118
119    /// Destroys a bind group, releasing its resources.
120    fn destroy_bind_group(&self, id: BindGroupId) -> Result<(), ResourceError>;
121
122    // --- Buffer Management ---
123
124    /// Creates a new GPU buffer.
125    fn create_buffer(&self, descriptor: &BufferDescriptor) -> Result<BufferId, ResourceError>;
126
127    /// Creates a new GPU buffer and initializes it with the provided data.
128    /// This is often more efficient than `create_buffer` followed by `write_buffer` for static data.
129    fn create_buffer_with_data(
130        &self,
131        descriptor: &BufferDescriptor,
132        data: &[u8],
133    ) -> Result<BufferId, ResourceError>;
134
135    /// Destroys a GPU buffer, releasing its memory.
136    fn destroy_buffer(&self, id: BufferId) -> Result<(), ResourceError>;
137
138    /// Writes data to a specific region of a GPU buffer.
139    ///
140    /// # Arguments
141    /// * `id`: The identifier of the buffer to write to.
142    /// * `offset`: The offset in bytes from the beginning of the buffer to start writing.
143    /// * `data`: The slice of bytes to write into the buffer.
144    fn write_buffer(&self, id: BufferId, offset: u64, data: &[u8]) -> Result<(), ResourceError>;
145
146    /// Asynchronously writes data to a GPU buffer.
147    /// This can be more performant for large data uploads by avoiding stalls.
148    fn write_buffer_async<'a>(
149        &'a self,
150        id: BufferId,
151        offset: u64,
152        data: &'a [u8],
153    ) -> Box<dyn Future<Output = Result<(), ResourceError>> + Send + 'static>;
154
155    // --- Texture & Sampler Management ---
156
157    /// Creates a new GPU texture.
158    fn create_texture(&self, descriptor: &TextureDescriptor) -> Result<TextureId, ResourceError>;
159
160    /// Destroys a GPU texture, releasing its memory.
161    fn destroy_texture(&self, id: TextureId) -> Result<(), ResourceError>;
162
163    /// Writes data to a specific region of a GPU texture.
164    ///
165    /// # Arguments
166    /// * `texture_id`: The identifier of the texture to write to.
167    /// * `data`: The raw image data to write.
168    /// * `bytes_per_row`: The number of bytes for a single row of texels in `data`.
169    /// * `offset`: The 3D offset (x, y, z/layer) in the texture to start writing.
170    /// * `size`: The 3D extent (width, height, depth/layers) of the data to write.
171    fn write_texture(
172        &self,
173        texture_id: TextureId,
174        data: &[u8],
175        bytes_per_row: Option<u32>,
176        offset: dimension::Origin3D,
177        size: dimension::Extent3D,
178    ) -> Result<(), ResourceError>;
179
180    /// Creates a new texture view for a given texture.
181    /// A view describes how a shader will interpret a texture's data (e.g., its format, mip levels).
182    fn create_texture_view(
183        &self,
184        texture_id: TextureId,
185        descriptor: &TextureViewDescriptor,
186    ) -> Result<TextureViewId, ResourceError>;
187
188    /// Destroys a texture view.
189    fn destroy_texture_view(&self, id: TextureViewId) -> Result<(), ResourceError>;
190
191    /// Creates a new sampler.
192    /// A sampler defines how a shader will sample from a texture (e.g., filtering, wrapping).
193    fn create_sampler(&self, descriptor: &SamplerDescriptor) -> Result<SamplerId, ResourceError>;
194
195    /// Destroys a sampler.
196    fn destroy_sampler(&self, id: SamplerId) -> Result<(), ResourceError>;
197
198    // --- Command Management ---
199
200    /// Creates a new command encoder to record GPU commands.
201    ///
202    /// # Arguments
203    /// * `label`: An optional debug label for the command encoder.
204    fn create_command_encoder(&self, label: Option<&str>) -> Box<dyn CommandEncoder>;
205
206    /// Submits a previously recorded command buffer to the GPU's command queue for execution.
207    fn submit_command_buffer(&self, command_buffer: CommandBufferId);
208
209    // --- Device Introspection ---
210
211    /// Gets the texture format of the primary render surface.
212    fn get_surface_format(&self) -> Option<TextureFormat>;
213
214    /// Gets information about the active graphics adapter (GPU).
215    fn get_adapter_info(&self) -> RendererAdapterInfo;
216
217    /// Checks if a specific, optional rendering feature is supported by the backend.
218    fn supports_feature(&self, feature_name: &str) -> bool;
219}