From 240e42631d65a668ed4b0364edbac49fcb055cea Mon Sep 17 00:00:00 2001 From: Lucien Greathouse Date: Wed, 20 Nov 2024 17:10:56 -0500 Subject: [PATCH] Add 'PaintLimits' concept, filled in depending on limitations from the underlying graphics API --- crates/yakui-core/src/paint/paint_dom.rs | 24 ++++++++++ crates/yakui-core/src/state.rs | 7 ++- crates/yakui-vulkan/src/lib.rs | 57 ++++++++++++++--------- crates/yakui-vulkan/src/vulkan_context.rs | 4 ++ crates/yakui-wgpu/src/lib.rs | 11 ++++- 5 files changed, 79 insertions(+), 24 deletions(-) diff --git a/crates/yakui-core/src/paint/paint_dom.rs b/crates/yakui-core/src/paint/paint_dom.rs index 5a82b913..1ac09573 100644 --- a/crates/yakui-core/src/paint/paint_dom.rs +++ b/crates/yakui-core/src/paint/paint_dom.rs @@ -14,6 +14,17 @@ use super::layers::PaintLayers; use super::primitives::{PaintMesh, Vertex}; use super::texture::{Texture, TextureChange}; +#[derive(Debug, Clone, Copy, Default)] +/// Contains all information about the limits of the paint device. +pub struct PaintLimits { + /// Maximum texture size of a 1D texture. + pub max_texture_size_1d: u32, + /// Maximum texture size of a 2D texture. + pub max_texture_size_2d: u32, + /// Maximum texture size of a 3D texture. + pub max_texture_size_3d: u32, +} + /// Contains all information about how to paint the current set of widgets. #[derive(Debug)] pub struct PaintDom { @@ -22,6 +33,7 @@ pub struct PaintDom { surface_size: Vec2, unscaled_viewport: Rect, scale_factor: f32, + limits: Option, layers: PaintLayers, clip_stack: Vec, @@ -36,11 +48,23 @@ impl PaintDom { surface_size: Vec2::ONE, unscaled_viewport: Rect::ONE, scale_factor: 1.0, + limits: None, + layers: PaintLayers::new(), clip_stack: Vec::new(), } } + /// Gets the paint limits. + pub fn limits(&self) -> Option { + self.limits + } + + /// Sets the paint limits, should be called once by rendering backends. + pub fn set_limit(&mut self, limits: PaintLimits) { + self.limits = Some(limits); + } + /// Prepares the PaintDom to be updated for the frame. pub fn start(&mut self) { self.texture_edits.clear(); diff --git a/crates/yakui-core/src/state.rs b/crates/yakui-core/src/state.rs index 1540ec84..ce9cc4d1 100644 --- a/crates/yakui-core/src/state.rs +++ b/crates/yakui-core/src/state.rs @@ -5,7 +5,7 @@ use crate::geometry::{Rect, Vec2}; use crate::id::ManagedTextureId; use crate::input::InputState; use crate::layout::LayoutDom; -use crate::paint::{PaintDom, Texture}; +use crate::paint::{PaintDom, PaintLimits, Texture}; /// The entrypoint for yakui. #[derive(Debug)] @@ -120,4 +120,9 @@ impl Yakui { pub fn layout_dom(&self) -> &LayoutDom { &self.layout } + + /// Sets the paint limits, should be called once by rendering backends. + pub fn set_paint_limit(&mut self, limits: PaintLimits) { + self.paint.set_limit(limits) + } } diff --git a/crates/yakui-vulkan/src/lib.rs b/crates/yakui-vulkan/src/lib.rs index 72528521..7ad67984 100644 --- a/crates/yakui-vulkan/src/lib.rs +++ b/crates/yakui-vulkan/src/lib.rs @@ -16,9 +16,8 @@ use std::{collections::HashMap, ffi::CStr, io::Cursor}; pub use vulkan_context::VulkanContext; use vulkan_texture::{UploadQueue, NO_TEXTURE_ID}; pub use vulkan_texture::{VulkanTexture, VulkanTextureCreateInfo}; - -use yakui_core as yakui; use yakui_core::geometry::UVec2; +use yakui_core::paint::PaintLimits; use yakui_core::{paint::Vertex as YakuiVertex, ManagedTextureId}; /// A struct wrapping everything needed to render yakui on Vulkan. This will be your main entry point. @@ -67,7 +66,7 @@ pub struct Options { struct DrawCall { index_offset: u32, index_count: u32, - clip: Option, + clip: Option, texture_id: u32, workflow: Workflow, } @@ -103,11 +102,11 @@ enum Workflow { unsafe impl bytemuck::Zeroable for Workflow {} unsafe impl bytemuck::Pod for Workflow {} -impl From for Workflow { - fn from(p: yakui::paint::Pipeline) -> Self { +impl From for Workflow { + fn from(p: yakui_core::paint::Pipeline) -> Self { match p { - yakui::paint::Pipeline::Main => Workflow::Main, - yakui::paint::Pipeline::Text => Workflow::Text, + yakui_core::paint::Pipeline::Main => Workflow::Main, + yakui_core::paint::Pipeline::Text => Workflow::Text, _ => panic!("Unknown pipeline {p:?}"), } } @@ -116,9 +115,9 @@ impl From for Workflow { #[repr(C)] #[derive(Clone, Copy, Default, Debug)] struct Vertex { - position: yakui::geometry::Vec2, - texcoord: yakui::geometry::Vec2, - color: yakui::geometry::Vec4, + position: yakui_core::geometry::Vec2, + texcoord: yakui_core::geometry::Vec2, + color: yakui_core::geometry::Vec4, } impl From<&YakuiVertex> for Vertex { @@ -137,7 +136,17 @@ impl YakuiVulkan { /// ## Safety /// - `vulkan_context` must have valid members /// - the members of `render_surface` must have been created with the same [`ash::Device`] as `vulkan_context`. - pub fn new(vulkan_context: &VulkanContext, options: Options) -> Self { + pub fn new( + state: &mut yakui_core::Yakui, + vulkan_context: &VulkanContext, + options: Options, + ) -> Self { + state.set_paint_limit(PaintLimits { + max_texture_size_1d: vulkan_context.properties.limits.max_image_dimension1_d, + max_texture_size_2d: vulkan_context.properties.limits.max_image_dimension2_d, + max_texture_size_3d: vulkan_context.properties.limits.max_image_dimension3_d, + }); + let device = vulkan_context.device; let descriptors = Descriptors::new(vulkan_context); @@ -502,7 +511,7 @@ impl YakuiVulkan { } } - /// Create and add a "user managed" texture to this [`YakuiVulkan`] instance. Returns a [`yakui::TextureId`] that can be used + /// Create and add a "user managed" texture to this [`YakuiVulkan`] instance. Returns a [`yakui_core::TextureId`] that can be used /// to refer to the texture in your GUI code. /// /// ## Safety @@ -511,24 +520,24 @@ impl YakuiVulkan { &mut self, vulkan_context: &VulkanContext, texture_create_info: VulkanTextureCreateInfo>, - ) -> yakui::TextureId { + ) -> yakui_core::TextureId { let texture = VulkanTexture::new( vulkan_context, &mut self.descriptors, texture_create_info, &mut self.uploads, ); - yakui::TextureId::User(self.user_textures.insert(texture).to_bits()) + yakui_core::TextureId::User(self.user_textures.insert(texture).to_bits()) } /// Add a "user managed" texture to this [`YakuiVulkan`] instance from an existing [`ash::vk::Image`]. - /// Returns a [`yakui::TextureId`] that can be used to refer to the texture in your GUI code. + /// Returns a [`yakui_core::TextureId`] that can be used to refer to the texture in your GUI code. /// /// ## Safety /// - `vulkan_context` must be the same as the one used to create this instance /// - `image` must have been created from the same `vulkan_context` - pub fn add_user_texture(&mut self, texture: VulkanTexture) -> yakui::TextureId { - yakui::TextureId::User(self.user_textures.insert(texture).to_bits()) + pub fn add_user_texture(&mut self, texture: VulkanTexture) -> yakui_core::TextureId { + yakui_core::TextureId::User(self.user_textures.insert(texture).to_bits()) } /// Clean up all Vulkan related handles on this instance. You'll probably want to call this when the program ends, but @@ -560,8 +569,12 @@ impl YakuiVulkan { &mut self.descriptors } - fn update_textures(&mut self, vulkan_context: &VulkanContext, paint: &yakui::paint::PaintDom) { - use yakui::paint::TextureChange; + fn update_textures( + &mut self, + vulkan_context: &VulkanContext, + paint: &yakui_core::paint::PaintDom, + ) { + use yakui_core::paint::TextureChange; if !self.initial_textures_synced { self.initial_textures_synced = true; for (id, texture) in paint.textures() { @@ -620,7 +633,7 @@ impl YakuiVulkan { fn build_draw_calls( &mut self, vulkan_context: &VulkanContext, - paint: &yakui::paint::PaintDom, + paint: &yakui_core::paint::PaintDom, ) -> Vec { let mut vertices: Vec = Default::default(); let mut indices: Vec = Default::default(); @@ -643,11 +656,11 @@ impl YakuiVulkan { let texture_id = call .texture .and_then(|id| match id { - yakui::TextureId::Managed(managed) => { + yakui_core::TextureId::Managed(managed) => { let texture = self.yakui_managed_textures.get(&managed)?; Some(texture.id) } - yakui::TextureId::User(bits) => { + yakui_core::TextureId::User(bits) => { let texture = self .user_textures .get(thunderdome::Index::from_bits(bits)?)?; diff --git a/crates/yakui-vulkan/src/vulkan_context.rs b/crates/yakui-vulkan/src/vulkan_context.rs index 66c47520..d3d8120d 100644 --- a/crates/yakui-vulkan/src/vulkan_context.rs +++ b/crates/yakui-vulkan/src/vulkan_context.rs @@ -18,6 +18,8 @@ pub struct VulkanContext<'a> { pub queue: vk::Queue, /// Memory properties used for [`crate::YakuiVulkan`]'s allocation commands pub memory_properties: vk::PhysicalDeviceMemoryProperties, + /// Device properties used for setting paint limits + pub properties: vk::PhysicalDeviceProperties, } impl<'a> VulkanContext<'a> { @@ -26,11 +28,13 @@ impl<'a> VulkanContext<'a> { device: &'a ash::Device, queue: vk::Queue, memory_properties: vk::PhysicalDeviceMemoryProperties, + properties: vk::PhysicalDeviceProperties, ) -> Self { Self { device, queue, memory_properties, + properties, } } diff --git a/crates/yakui-wgpu/src/lib.rs b/crates/yakui-wgpu/src/lib.rs index 28991465..bc6a6ed0 100644 --- a/crates/yakui-wgpu/src/lib.rs +++ b/crates/yakui-wgpu/src/lib.rs @@ -17,7 +17,7 @@ use bytemuck::{Pod, Zeroable}; use glam::UVec2; use thunderdome::{Arena, Index}; use yakui_core::geometry::{Rect, Vec2, Vec4}; -use yakui_core::paint::{PaintDom, Pipeline, Texture, TextureChange, TextureFormat}; +use yakui_core::paint::{PaintDom, PaintLimits, Pipeline, Texture, TextureChange, TextureFormat}; use yakui_core::{ManagedTextureId, TextureId}; use self::bindgroup_cache::TextureBindgroupCache; @@ -27,6 +27,7 @@ use self::samplers::Samplers; use self::texture::{GpuManagedTexture, GpuTexture}; pub struct YakuiWgpu { + limits: PaintLimits, main_pipeline: PipelineCache, text_pipeline: PipelineCache, samplers: Samplers, @@ -69,6 +70,12 @@ impl Vertex { impl YakuiWgpu { pub fn new(device: &wgpu::Device, queue: &wgpu::Queue) -> Self { + let limits = PaintLimits { + max_texture_size_1d: device.limits().max_texture_dimension_1d, + max_texture_size_2d: device.limits().max_texture_dimension_2d, + max_texture_size_3d: device.limits().max_texture_dimension_3d, + }; + let layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { label: Some("yakui Bind Group Layout"), entries: &[ @@ -124,6 +131,7 @@ impl YakuiWgpu { ); Self { + limits, main_pipeline, text_pipeline, samplers, @@ -203,6 +211,7 @@ impl YakuiWgpu { ) { profiling::scope!("yakui-wgpu paint_with_encoder"); + state.set_paint_limit(self.limits); let paint = state.paint(); self.update_textures(device, paint, queue);