use alloc::{boxed::Box, string::String, string::ToString as _, sync::Arc, vec::Vec}; use core::{
fmt,
ops::Range,
sync::atomic::{AtomicU32, AtomicU8},
}; use parking_lot::Mutex;
use arrayvec::ArrayVec; use glow::HasContext; use naga::FastHashMap;
usecrate::{CopyExtent, TextureDescriptor};
#[derive(Clone, Debug)] pubstruct Api;
//Note: we can support more samplers if not every one of them is used at a time, // but it probably doesn't worth it. const MAX_TEXTURE_SLOTS: usize = 16; const MAX_SAMPLERS: usize = 16; const MAX_VERTEX_ATTRIBUTES: usize = 16; const ZERO_BUFFER_SIZE: usize = 256 << 10; const MAX_IMMEDIATES: usize = 64; // We have to account for each immediate data may need to be set for every shader. const MAX_IMMEDIATES_COMMANDS: usize = MAX_IMMEDIATES * crate::MAX_CONCURRENT_SHADER_STAGES;
implcrate::Api for Api { const VARIANT: wgt::Backend = wgt::Backend::Gl;
type Instance = Instance; type Surface = Surface; type Adapter = Adapter; type Device = Device;
type Queue = Queue; type CommandEncoder = CommandEncoder; type CommandBuffer = CommandBuffer;
type Buffer = Buffer; type Texture = Texture; type SurfaceTexture = Texture; type TextureView = TextureView; type Sampler = Sampler; type QuerySet = QuerySet; type Fence = Fence; type AccelerationStructure = AccelerationStructure; type PipelineCache = PipelineCache;
type BindGroupLayout = BindGroupLayout; type BindGroup = BindGroup; type PipelineLayout = PipelineLayout; type ShaderModule = ShaderModule; type RenderPipeline = RenderPipeline; type ComputePipeline = ComputePipeline;
}
bitflags::bitflags! { /// Flags that affect internal code paths but do not /// change the exposed feature set. #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] struct PrivateCapabilities: u32 { /// Indicates support for `glBufferStorage` allocation. const BUFFER_ALLOCATION = 1 << 0; /// Support explicit layouts in shader. const SHADER_BINDING_LAYOUT = 1 << 1; /// Support extended shadow sampling instructions. const SHADER_TEXTURE_SHADOW_LOD = 1 << 2; /// Support memory barriers. const MEMORY_BARRIERS = 1 << 3; /// Vertex buffer layouts separate from the data. const VERTEX_BUFFER_LAYOUT = 1 << 4; /// Indicates that buffers used as `GL_ELEMENT_ARRAY_BUFFER` may be created / initialized / used /// as other targets, if not present they must not be mixed with other targets. const INDEX_BUFFER_ROLE_CHANGE = 1 << 5; /// Supports `glGetBufferSubData` const GET_BUFFER_SUB_DATA = 1 << 7; /// Supports `f16` color buffers const COLOR_BUFFER_HALF_FLOAT = 1 << 8; /// Supports `f11/f10` and `f32` color buffers const COLOR_BUFFER_FLOAT = 1 << 9; /// Supports query buffer objects. const QUERY_BUFFERS = 1 << 11; /// Supports 64 bit queries via `glGetQueryObjectui64v` const QUERY_64BIT = 1 << 12; /// Supports `glTexStorage2D`, etc. const TEXTURE_STORAGE = 1 << 13; /// Supports `push_debug_group`, `pop_debug_group` and `debug_message_insert`. const DEBUG_FNS = 1 << 14; /// Supports framebuffer invalidation. const INVALIDATE_FRAMEBUFFER = 1 << 15; /// Indicates support for `glDrawElementsInstancedBaseVertexBaseInstance` and `ARB_shader_draw_parameters` /// /// When this is true, instance offset emulation via vertex buffer rebinding and a shader uniform will be disabled. const FULLY_FEATURED_INSTANCING = 1 << 16; /// Supports direct multisampled rendering to a texture without needing a resolve texture. const MULTISAMPLED_RENDER_TO_TEXTURE = 1 << 17;
}
}
/// Result of `gl.get_parameter_i32(glow::MAX_SAMPLES)`. /// Cached here so it doesn't need to be queried every time texture format capabilities are requested. /// (this has been shown to be a significant enough overhead)
max_msaa_samples: i32,
}
pubstruct Queue {
shared: Arc<AdapterShared>,
features: wgt::Features,
draw_fbo: glow::Framebuffer,
copy_fbo: glow::Framebuffer, /// Shader program used to clear the screen for [`Workarounds::MESA_I915_SRGB_SHADER_CLEAR`] /// devices.
shader_clear_program: Option<ShaderClearProgram>, /// Keep a reasonably large buffer filled with zeroes, so that we can implement `ClearBuffer` of /// zeroes by copying from it.
zero_buffer: glow::Buffer,
temp_query_results: Mutex<Vec<u64>>,
draw_buffer_count: AtomicU8,
current_index_buffer: Mutex<Option<glow::Buffer>>,
}
impl Drop for Queue { fn drop(&mutself) { let gl = &self.shared.context.lock(); unsafe { gl.delete_framebuffer(self.draw_fbo) }; unsafe { gl.delete_framebuffer(self.copy_fbo) }; unsafe { gl.delete_buffer(self.zero_buffer) };
}
}
#[derive(Clone, Debug)] pubstruct Buffer {
raw: Option<glow::Buffer>,
target: BindTarget,
size: wgt::BufferAddress, /// Flags to use within calls to [`Device::map_buffer`](crate::Device::map_buffer).
map_flags: u32, /// Buffer mapping state. /// /// If locked concurrently with the GL context, the GL context should be locked first.
map_state: Arc<MaybeMutex<BufferMapState>>,
}
#[derive(Clone, Debug)] struct BufferMapState { /// True if the GL buffer is actually mapped, i.e. not "fake-mapped" with /// an empty slice
mapped: bool,
data: Option<Vec<u8>>,
offset_of_current_mapping: wgt::BufferAddress,
}
#[derive(Clone, Debug)] pubenum TextureInner {
Renderbuffer {
raw: glow::Renderbuffer,
},
DefaultRenderbuffer,
Texture {
raw: glow::Texture,
target: BindTarget,
}, #[cfg(webgl)] /// Render to a `WebGLFramebuffer` /// /// This is a web feature
ExternalFramebuffer {
inner: web_sys::WebGlFramebuffer,
}, #[cfg(native)] /// Render to a `glow::NativeFramebuffer` /// Useful when the framebuffer to draw to /// has a non-zero framebuffer ID /// /// This is a native feature
ExternalNativeFramebuffer {
inner: glow::NativeFramebuffer,
},
}
#[cfg(send_sync)] unsafeimpl Sync for TextureInner {} #[cfg(send_sync)] unsafeimpl Send for TextureInner {}
// The `drop_guard` field must be the last field of this struct so it is dropped last. // Do not add new fields after it. pub drop_guard: Option<crate::DropGuard>,
}
implcrate::DynTexture for Texture {} implcrate::DynSurfaceTexture for Texture {}
/// Returns the `target`, whether the image is 3d and whether the image is a cubemap. fn get_info_from_desc(desc: &TextureDescriptor) -> u32 { match desc.dimension { // WebGL (1 and 2) as well as some GLES versions do not have 1D textures, so we are // doing `TEXTURE_2D` instead
wgt::TextureDimension::D1 => glow::TEXTURE_2D,
wgt::TextureDimension::D2 => { // HACK: detect a cube map; forces cube compatible textures to be cube textures match (desc.is_cube_compatible(), desc.size.depth_or_array_layers) {
(false, 1) => glow::TEXTURE_2D,
(false, _) => glow::TEXTURE_2D_ARRAY,
(true, 6) => glow::TEXTURE_CUBE_MAP,
(true, _) => glow::TEXTURE_CUBE_MAP_ARRAY,
}
}
wgt::TextureDimension::D3 => glow::TEXTURE_3D,
}
}
/// More information can be found in issues #1614 and #1574 fn log_failing_target_heuristics(view_dimension: wgt::TextureViewDimension, target: u32) { let expected_target = match view_dimension {
wgt::TextureViewDimension::D1 => glow::TEXTURE_2D,
wgt::TextureViewDimension::D2 => glow::TEXTURE_2D,
wgt::TextureViewDimension::D2Array => glow::TEXTURE_2D_ARRAY,
wgt::TextureViewDimension::Cube => glow::TEXTURE_CUBE_MAP,
wgt::TextureViewDimension::CubeArray => glow::TEXTURE_CUBE_MAP_ARRAY,
wgt::TextureViewDimension::D3 => glow::TEXTURE_3D,
};
log::error!(
concat!( "wgpu-hal heuristics assumed that ", "the view dimension will be equal to `{}` rather than `{:?}`.\n", "`D2` textures with ", "`depth_or_array_layers == 1` ", "are assumed to have view dimension `D2`\n", "`D2` textures with ", "`depth_or_array_layers > 1` ", "are assumed to have view dimension `D2Array`\n", "`D2` textures with ", "`depth_or_array_layers == 6` ", "are assumed to have view dimension `Cube`\n", "`D2` textures with ", "`depth_or_array_layers > 6 && depth_or_array_layers % 6 == 0` ", "are assumed to have view dimension `CubeArray`\n",
),
got,
view_dimension,
);
}
}
implcrate::DynBindGroupLayout for BindGroupLayout {}
#[derive(Debug)] struct BindGroupLayoutInfo {
entries: Arc<[wgt::BindGroupLayoutEntry]>, /// Mapping of resources, indexed by `binding`, into the whole layout space. /// For texture resources, the value is the texture slot index. /// For sampler resources, the value is the index of the sampler in the whole layout. /// For buffers, the value is the uniform or storage slot index. /// For unused bindings, the value is `!0`
binding_to_slot: Box<[u8]>,
}
implcrate::DynPipelineLayout for PipelineLayout {}
impl PipelineLayout { /// # Panics /// If the pipeline layout does not contain a bind group layout used by /// the resource binding. fn get_slot(&self, br: &naga::ResourceBinding) -> u8 { let group_info = self.group_infos[br.group as usize].as_ref().unwrap();
group_info.binding_to_slot[br.binding as usize]
}
}
#[cfg(send_sync)] unsafeimpl Sync for ImmediateDesc {} #[cfg(send_sync)] unsafeimpl Send for ImmediateDesc {}
/// For each texture in the pipeline layout, store the index of the only /// sampler (in this layout) that the texture is used with. type SamplerBindMap = [Option<u8>; MAX_TEXTURE_SLOTS];
#[cfg(send_sync)] unsafeimpl Sync for CommandBuffer {} #[cfg(send_sync)] unsafeimpl Send for CommandBuffer {}
//TODO: we would have something like `Arc<typed_arena::Arena>` // here and in the command buffers. So that everything grows // inside the encoder and stays there until `reset_all`.
let _ = std::panic::catch_unwind(|| {
log::log!(
log_severity, "GLES: [{source_str}/{type_str}] ID {id} : {message}"
);
});
#[cfg(feature = "validation_canary")] if cfg!(debug_assertions) && log_severity == log::Level::Error { // Set canary and continue crate::VALIDATION_CANARY.add(message.to_string());
}
}
// If we are using `std`, then use `Mutex` to provide `Send` and `Sync`
cfg_if::cfg_if! { if#[cfg(gles_with_std)] { type MaybeMutex<T> = std::sync::Mutex<T>;
fn lock<T>(mutex: &MaybeMutex<T>) -> std::sync::MutexGuard<'_, T> {
mutex.lock().unwrap()
}
} else { // It should be impossible for any build configuration to trigger this error // It is intended only as a guard against changes elsewhere causing the use of // `RefCell` here to become unsound. #[cfg(all(send_sync, not(feature = "fragile-send-sync-non-atomic-wasm")))]
compile_error!("cannot provide non-fragile Send+Sync without std");
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.