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}