vulkan: add support for blend buffers
This commit is contained in:
parent
1220539a41
commit
cb9da22ec2
20 changed files with 638 additions and 78 deletions
|
|
@ -13,6 +13,8 @@ pub fn main() -> anyhow::Result<()> {
|
||||||
compile_simple("fill.vert")?;
|
compile_simple("fill.vert")?;
|
||||||
compile_simple("tex.vert")?;
|
compile_simple("tex.vert")?;
|
||||||
compile_simple("tex.frag")?;
|
compile_simple("tex.frag")?;
|
||||||
|
compile_simple("out.vert")?;
|
||||||
|
compile_simple("out.frag")?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -408,7 +408,7 @@ static XBGR16161616: &Format = &Format {
|
||||||
..default(ConfigFormat::XBGR16161616)
|
..default(ConfigFormat::XBGR16161616)
|
||||||
};
|
};
|
||||||
|
|
||||||
static ABGR16161616F: &Format = &Format {
|
pub static ABGR16161616F: &Format = &Format {
|
||||||
name: "abgr16161616f",
|
name: "abgr16161616f",
|
||||||
vk_format: vk::Format::R16G16B16A16_SFLOAT,
|
vk_format: vk::Format::R16G16B16A16_SFLOAT,
|
||||||
drm: fourcc_code('A', 'B', '4', 'H'),
|
drm: fourcc_code('A', 'B', '4', 'H'),
|
||||||
|
|
|
||||||
|
|
@ -267,7 +267,9 @@ pub enum ResetStatus {
|
||||||
Other(u32),
|
Other(u32),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait GfxBlendBuffer: Debug {}
|
pub trait GfxBlendBuffer: Debug {
|
||||||
|
fn into_any(self: Rc<Self>) -> Rc<dyn Any>;
|
||||||
|
}
|
||||||
|
|
||||||
pub trait GfxFramebuffer: Debug {
|
pub trait GfxFramebuffer: Debug {
|
||||||
fn physical_size(&self) -> (i32, i32);
|
fn physical_size(&self) -> (i32, i32);
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
mod allocator;
|
mod allocator;
|
||||||
|
mod blend_buffer;
|
||||||
mod bo_allocator;
|
mod bo_allocator;
|
||||||
mod command;
|
mod command;
|
||||||
mod descriptor;
|
mod descriptor;
|
||||||
|
|
@ -204,8 +205,8 @@ pub enum VulkanError {
|
||||||
UndefinedContents,
|
UndefinedContents,
|
||||||
#[error("The framebuffer is being used by the transfer queue")]
|
#[error("The framebuffer is being used by the transfer queue")]
|
||||||
BusyInTransfer,
|
BusyInTransfer,
|
||||||
#[error("Vulkan does not support blend buffers")]
|
#[error("Driver does not support descriptor buffers")]
|
||||||
NoBlendBuffer,
|
NoDescriptorBuffer,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<VulkanError> for GfxError {
|
impl From<VulkanError> for GfxError {
|
||||||
|
|
@ -272,6 +273,7 @@ impl GfxContext for Context {
|
||||||
let old = old.into_texture().into_vk(&self.0.device.device);
|
let old = old.into_texture().into_vk(&self.0.device.device);
|
||||||
let shm = match &old.ty {
|
let shm = match &old.ty {
|
||||||
VulkanImageMemory::DmaBuf(_) => unreachable!(),
|
VulkanImageMemory::DmaBuf(_) => unreachable!(),
|
||||||
|
VulkanImageMemory::Blend(_) => unreachable!(),
|
||||||
VulkanImageMemory::Internal(shm) => shm,
|
VulkanImageMemory::Internal(shm) => shm,
|
||||||
};
|
};
|
||||||
if old.width as i32 == width
|
if old.width as i32 == width
|
||||||
|
|
@ -355,10 +357,11 @@ impl GfxContext for Context {
|
||||||
|
|
||||||
fn acquire_blend_buffer(
|
fn acquire_blend_buffer(
|
||||||
&self,
|
&self,
|
||||||
_width: i32,
|
width: i32,
|
||||||
_height: i32,
|
height: i32,
|
||||||
) -> Result<Rc<dyn GfxBlendBuffer>, GfxError> {
|
) -> Result<Rc<dyn GfxBlendBuffer>, GfxError> {
|
||||||
Err(GfxError(Box::new(VulkanError::NoBlendBuffer)))
|
let buffer = self.0.acquire_blend_buffer(width, height)?;
|
||||||
|
Ok(buffer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
139
src/gfx_apis/vulkan/blend_buffer.rs
Normal file
139
src/gfx_apis/vulkan/blend_buffer.rs
Normal file
|
|
@ -0,0 +1,139 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
gfx_api::GfxBlendBuffer,
|
||||||
|
gfx_apis::vulkan::{
|
||||||
|
VulkanError,
|
||||||
|
format::{BLEND_FORMAT, BLEND_USAGE},
|
||||||
|
image::{QueueFamily, QueueState, VulkanImage, VulkanImageMemory},
|
||||||
|
renderer::VulkanRenderer,
|
||||||
|
},
|
||||||
|
utils::on_drop::OnDrop,
|
||||||
|
},
|
||||||
|
ash::vk::{
|
||||||
|
DescriptorDataEXT, DescriptorGetInfoEXT, DescriptorImageInfo, DescriptorType, Extent3D,
|
||||||
|
ImageAspectFlags, ImageCreateInfo, ImageLayout, ImageSubresourceRange, ImageTiling,
|
||||||
|
ImageType, ImageViewCreateInfo, ImageViewType, SampleCountFlags, SharingMode,
|
||||||
|
},
|
||||||
|
gpu_alloc::UsageFlags,
|
||||||
|
std::{any::Any, cell::Cell, collections::hash_map::Entry, rc::Rc},
|
||||||
|
};
|
||||||
|
|
||||||
|
impl VulkanRenderer {
|
||||||
|
pub fn acquire_blend_buffer(
|
||||||
|
self: &Rc<Self>,
|
||||||
|
width: i32,
|
||||||
|
height: i32,
|
||||||
|
) -> Result<Rc<VulkanImage>, VulkanError> {
|
||||||
|
let Some(db) = &self.device.descriptor_buffer else {
|
||||||
|
return Err(VulkanError::NoDescriptorBuffer);
|
||||||
|
};
|
||||||
|
if width <= 0 || height <= 0 {
|
||||||
|
return Err(VulkanError::NonPositiveImageSize);
|
||||||
|
}
|
||||||
|
let width = width as u32;
|
||||||
|
let height = height as u32;
|
||||||
|
let cached = &mut *self.blend_buffers.borrow_mut();
|
||||||
|
let cached = cached.entry((width, height));
|
||||||
|
if let Entry::Occupied(entry) = &cached {
|
||||||
|
if let Some(buffer) = entry.get().upgrade() {
|
||||||
|
return Ok(buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let limits = self.device.blend_limits;
|
||||||
|
if width > limits.max_width || height > limits.max_height {
|
||||||
|
return Err(VulkanError::ImageTooLarge);
|
||||||
|
}
|
||||||
|
let create_info = ImageCreateInfo::default()
|
||||||
|
.image_type(ImageType::TYPE_2D)
|
||||||
|
.format(BLEND_FORMAT.vk_format)
|
||||||
|
.mip_levels(1)
|
||||||
|
.array_layers(1)
|
||||||
|
.tiling(ImageTiling::OPTIMAL)
|
||||||
|
.samples(SampleCountFlags::TYPE_1)
|
||||||
|
.sharing_mode(SharingMode::EXCLUSIVE)
|
||||||
|
.initial_layout(ImageLayout::UNDEFINED)
|
||||||
|
.extent(Extent3D {
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
depth: 1,
|
||||||
|
})
|
||||||
|
.usage(BLEND_USAGE);
|
||||||
|
let image = unsafe { self.device.device.create_image(&create_info, None) };
|
||||||
|
let image = image.map_err(VulkanError::CreateImage)?;
|
||||||
|
let destroy_image = OnDrop(|| unsafe { self.device.device.destroy_image(image, None) });
|
||||||
|
let memory_requirements =
|
||||||
|
unsafe { self.device.device.get_image_memory_requirements(image) };
|
||||||
|
let allocation =
|
||||||
|
self.allocator
|
||||||
|
.alloc(&memory_requirements, UsageFlags::FAST_DEVICE_ACCESS, false)?;
|
||||||
|
let res = unsafe {
|
||||||
|
self.device
|
||||||
|
.device
|
||||||
|
.bind_image_memory(image, allocation.memory, allocation.offset)
|
||||||
|
};
|
||||||
|
res.map_err(VulkanError::BindImageMemory)?;
|
||||||
|
let image_view_create_info = ImageViewCreateInfo::default()
|
||||||
|
.image(image)
|
||||||
|
.format(BLEND_FORMAT.vk_format)
|
||||||
|
.view_type(ImageViewType::TYPE_2D)
|
||||||
|
.subresource_range(ImageSubresourceRange {
|
||||||
|
aspect_mask: ImageAspectFlags::COLOR,
|
||||||
|
base_mip_level: 0,
|
||||||
|
level_count: 1,
|
||||||
|
base_array_layer: 0,
|
||||||
|
layer_count: 1,
|
||||||
|
});
|
||||||
|
let view = unsafe {
|
||||||
|
self.device
|
||||||
|
.device
|
||||||
|
.create_image_view(&image_view_create_info, None)
|
||||||
|
};
|
||||||
|
let view = view.map_err(VulkanError::CreateImageView)?;
|
||||||
|
destroy_image.forget();
|
||||||
|
let sampled_image_descriptor = {
|
||||||
|
let mut buf = vec![0; self.device.sampled_image_descriptor_size].into_boxed_slice();
|
||||||
|
let image_info = DescriptorImageInfo::default()
|
||||||
|
.image_view(view)
|
||||||
|
.image_layout(ImageLayout::SHADER_READ_ONLY_OPTIMAL);
|
||||||
|
let info = DescriptorGetInfoEXT::default()
|
||||||
|
.ty(DescriptorType::SAMPLED_IMAGE)
|
||||||
|
.data(DescriptorDataEXT {
|
||||||
|
p_sampled_image: &image_info,
|
||||||
|
});
|
||||||
|
unsafe {
|
||||||
|
db.get_descriptor(&info, &mut buf);
|
||||||
|
}
|
||||||
|
buf
|
||||||
|
};
|
||||||
|
let img = Rc::new(VulkanImage {
|
||||||
|
renderer: self.clone(),
|
||||||
|
format: BLEND_FORMAT,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
stride: 0,
|
||||||
|
texture_view: view,
|
||||||
|
render_view: None,
|
||||||
|
image,
|
||||||
|
is_undefined: Cell::new(true),
|
||||||
|
contents_are_undefined: Cell::new(true),
|
||||||
|
queue_state: Cell::new(QueueState::Acquired {
|
||||||
|
family: QueueFamily::Gfx,
|
||||||
|
}),
|
||||||
|
ty: VulkanImageMemory::Blend(allocation),
|
||||||
|
bridge: None,
|
||||||
|
shader_read_only_optimal_descriptor: Box::new([]),
|
||||||
|
sampled_image_descriptor,
|
||||||
|
descriptor_buffer_version: Default::default(),
|
||||||
|
descriptor_buffer_offset: Default::default(),
|
||||||
|
execution_version: Default::default(),
|
||||||
|
});
|
||||||
|
cached.insert_entry(Rc::downgrade(&img));
|
||||||
|
Ok(img)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GfxBlendBuffer for VulkanImage {
|
||||||
|
fn into_any(self: Rc<Self>) -> Rc<dyn Any> {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -68,6 +68,33 @@ impl VulkanDevice {
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(super) fn create_out_descriptor_set_layout(
|
||||||
|
self: &Rc<Self>,
|
||||||
|
db: &descriptor_buffer::Device,
|
||||||
|
) -> Result<Rc<VulkanDescriptorSetLayout>, VulkanError> {
|
||||||
|
let binding = DescriptorSetLayoutBinding::default()
|
||||||
|
.stage_flags(ShaderStageFlags::FRAGMENT)
|
||||||
|
.descriptor_count(1)
|
||||||
|
.descriptor_type(DescriptorType::SAMPLED_IMAGE);
|
||||||
|
let create_info = DescriptorSetLayoutCreateInfo::default()
|
||||||
|
.bindings(slice::from_ref(&binding))
|
||||||
|
.flags(DescriptorSetLayoutCreateFlags::DESCRIPTOR_BUFFER_EXT);
|
||||||
|
let layout = unsafe { self.device.create_descriptor_set_layout(&create_info, None) };
|
||||||
|
let layout = layout.map_err(VulkanError::CreateDescriptorSetLayout)?;
|
||||||
|
let size = self.get_descriptor_set_size(db, layout);
|
||||||
|
let mut offsets = ArrayVec::new();
|
||||||
|
unsafe {
|
||||||
|
offsets.push(db.get_descriptor_set_layout_binding_offset(layout, 0));
|
||||||
|
}
|
||||||
|
Ok(Rc::new(VulkanDescriptorSetLayout {
|
||||||
|
device: self.clone(),
|
||||||
|
layout,
|
||||||
|
size,
|
||||||
|
offsets,
|
||||||
|
_sampler: None,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
fn get_descriptor_set_size(
|
fn get_descriptor_set_size(
|
||||||
&self,
|
&self,
|
||||||
db: &descriptor_buffer::Device,
|
db: &descriptor_buffer::Device,
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ use {
|
||||||
format::XRGB8888,
|
format::XRGB8888,
|
||||||
gfx_apis::vulkan::{
|
gfx_apis::vulkan::{
|
||||||
VulkanError,
|
VulkanError,
|
||||||
format::VulkanFormat,
|
format::{VulkanBlendBufferLimits, VulkanFormat},
|
||||||
instance::{
|
instance::{
|
||||||
API_VERSION, ApiVersionDisplay, Extensions, VulkanInstance,
|
API_VERSION, ApiVersionDisplay, Extensions, VulkanInstance,
|
||||||
map_extension_properties,
|
map_extension_properties,
|
||||||
|
|
@ -63,6 +63,7 @@ pub struct VulkanDevice {
|
||||||
pub(super) image_drm_format_modifier: image_drm_format_modifier::Device,
|
pub(super) image_drm_format_modifier: image_drm_format_modifier::Device,
|
||||||
pub(super) descriptor_buffer: Option<descriptor_buffer::Device>,
|
pub(super) descriptor_buffer: Option<descriptor_buffer::Device>,
|
||||||
pub(super) formats: AHashMap<u32, VulkanFormat>,
|
pub(super) formats: AHashMap<u32, VulkanFormat>,
|
||||||
|
pub(super) blend_limits: VulkanBlendBufferLimits,
|
||||||
pub(super) memory_types: ArrayVec<MemoryType, MAX_MEMORY_TYPES>,
|
pub(super) memory_types: ArrayVec<MemoryType, MAX_MEMORY_TYPES>,
|
||||||
pub(super) graphics_queue: Queue,
|
pub(super) graphics_queue: Queue,
|
||||||
pub(super) graphics_queue_idx: u32,
|
pub(super) graphics_queue_idx: u32,
|
||||||
|
|
@ -71,6 +72,7 @@ pub struct VulkanDevice {
|
||||||
pub(super) transfer_granularity_mask: (u32, u32),
|
pub(super) transfer_granularity_mask: (u32, u32),
|
||||||
pub(super) descriptor_buffer_offset_mask: DeviceSize,
|
pub(super) descriptor_buffer_offset_mask: DeviceSize,
|
||||||
pub(super) combined_image_sampler_descriptor_size: usize,
|
pub(super) combined_image_sampler_descriptor_size: usize,
|
||||||
|
pub(super) sampled_image_descriptor_size: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for VulkanDevice {
|
impl Drop for VulkanDevice {
|
||||||
|
|
@ -337,6 +339,7 @@ impl VulkanInstance {
|
||||||
Err(e) => return Err(VulkanError::CreateDevice(e)),
|
Err(e) => return Err(VulkanError::CreateDevice(e)),
|
||||||
};
|
};
|
||||||
let destroy_device = OnDrop(|| unsafe { device.destroy_device(None) });
|
let destroy_device = OnDrop(|| unsafe { device.destroy_device(None) });
|
||||||
|
let blend_limits = self.load_blend_format_limits(phy_dev)?;
|
||||||
let formats = self.load_formats(phy_dev)?;
|
let formats = self.load_formats(phy_dev)?;
|
||||||
let supports_xrgb8888 = formats
|
let supports_xrgb8888 = formats
|
||||||
.get(&XRGB8888.drm)
|
.get(&XRGB8888.drm)
|
||||||
|
|
@ -364,6 +367,7 @@ impl VulkanInstance {
|
||||||
.then(|| descriptor_buffer::Device::new(&self.instance, &device));
|
.then(|| descriptor_buffer::Device::new(&self.instance, &device));
|
||||||
let mut descriptor_buffer_offset_mask = 0;
|
let mut descriptor_buffer_offset_mask = 0;
|
||||||
let mut combined_image_sampler_descriptor_size = 0;
|
let mut combined_image_sampler_descriptor_size = 0;
|
||||||
|
let mut sampled_image_descriptor_size = 0;
|
||||||
if supports_descriptor_buffer {
|
if supports_descriptor_buffer {
|
||||||
let mut descriptor_buffer_props =
|
let mut descriptor_buffer_props =
|
||||||
PhysicalDeviceDescriptorBufferPropertiesEXT::default();
|
PhysicalDeviceDescriptorBufferPropertiesEXT::default();
|
||||||
|
|
@ -380,6 +384,7 @@ impl VulkanInstance {
|
||||||
- 1;
|
- 1;
|
||||||
combined_image_sampler_descriptor_size =
|
combined_image_sampler_descriptor_size =
|
||||||
descriptor_buffer_props.combined_image_sampler_descriptor_size;
|
descriptor_buffer_props.combined_image_sampler_descriptor_size;
|
||||||
|
sampled_image_descriptor_size = descriptor_buffer_props.sampled_image_descriptor_size;
|
||||||
}
|
}
|
||||||
let memory_properties =
|
let memory_properties =
|
||||||
unsafe { self.instance.get_physical_device_memory_properties(phy_dev) };
|
unsafe { self.instance.get_physical_device_memory_properties(phy_dev) };
|
||||||
|
|
@ -418,6 +423,8 @@ impl VulkanInstance {
|
||||||
transfer_granularity_mask,
|
transfer_granularity_mask,
|
||||||
descriptor_buffer_offset_mask,
|
descriptor_buffer_offset_mask,
|
||||||
combined_image_sampler_descriptor_size,
|
combined_image_sampler_descriptor_size,
|
||||||
|
sampled_image_descriptor_size,
|
||||||
|
blend_limits,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
format::{FORMATS, Format},
|
format::{ABGR16161616F, FORMATS, Format},
|
||||||
gfx_apis::vulkan::{VulkanError, instance::VulkanInstance},
|
gfx_apis::vulkan::{VulkanError, instance::VulkanInstance},
|
||||||
video::{LINEAR_MODIFIER, Modifier},
|
video::{LINEAR_MODIFIER, Modifier},
|
||||||
},
|
},
|
||||||
|
|
@ -38,18 +38,24 @@ pub struct VulkanModifier {
|
||||||
pub render_needs_bridge: bool,
|
pub render_needs_bridge: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug, Default)]
|
||||||
pub struct VulkanModifierLimits {
|
pub struct VulkanModifierLimits {
|
||||||
pub max_width: u32,
|
pub max_width: u32,
|
||||||
pub max_height: u32,
|
pub max_height: u32,
|
||||||
pub exportable: bool,
|
pub exportable: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Default)]
|
||||||
pub struct VulkanInternalFormat {
|
pub struct VulkanInternalFormat {
|
||||||
pub limits: VulkanModifierLimits,
|
pub limits: VulkanModifierLimits,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
pub struct VulkanBlendBufferLimits {
|
||||||
|
pub max_width: u32,
|
||||||
|
pub max_height: u32,
|
||||||
|
}
|
||||||
|
|
||||||
const FRAMEBUFFER_FEATURES: FormatFeatureFlags = FormatFeatureFlags::from_raw(
|
const FRAMEBUFFER_FEATURES: FormatFeatureFlags = FormatFeatureFlags::from_raw(
|
||||||
0 | FormatFeatureFlags::COLOR_ATTACHMENT.as_raw()
|
0 | FormatFeatureFlags::COLOR_ATTACHMENT.as_raw()
|
||||||
| FormatFeatureFlags::COLOR_ATTACHMENT_BLEND.as_raw(),
|
| FormatFeatureFlags::COLOR_ATTACHMENT_BLEND.as_raw(),
|
||||||
|
|
@ -79,6 +85,16 @@ const TRANSFER_USAGE: ImageUsageFlags = ImageUsageFlags::from_raw(
|
||||||
const SHM_USAGE: ImageUsageFlags =
|
const SHM_USAGE: ImageUsageFlags =
|
||||||
ImageUsageFlags::from_raw(TRANSFER_USAGE.as_raw() | TEX_USAGE.as_raw());
|
ImageUsageFlags::from_raw(TRANSFER_USAGE.as_raw() | TEX_USAGE.as_raw());
|
||||||
|
|
||||||
|
pub const BLEND_FORMAT: &Format = ABGR16161616F;
|
||||||
|
const BLEND_FEATURES: FormatFeatureFlags = FormatFeatureFlags::from_raw(
|
||||||
|
0 | FormatFeatureFlags::COLOR_ATTACHMENT.as_raw()
|
||||||
|
| FormatFeatureFlags::COLOR_ATTACHMENT_BLEND.as_raw()
|
||||||
|
| FormatFeatureFlags::SAMPLED_IMAGE.as_raw(),
|
||||||
|
);
|
||||||
|
pub const BLEND_USAGE: ImageUsageFlags = ImageUsageFlags::from_raw(
|
||||||
|
ImageUsageFlags::COLOR_ATTACHMENT.as_raw() | ImageUsageFlags::SAMPLED.as_raw(),
|
||||||
|
);
|
||||||
|
|
||||||
impl VulkanInstance {
|
impl VulkanInstance {
|
||||||
pub(super) fn load_formats(
|
pub(super) fn load_formats(
|
||||||
&self,
|
&self,
|
||||||
|
|
@ -126,6 +142,29 @@ impl VulkanInstance {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn load_blend_format_limits(
|
||||||
|
&self,
|
||||||
|
phy_dev: PhysicalDevice,
|
||||||
|
) -> Result<VulkanBlendBufferLimits, VulkanError> {
|
||||||
|
let format_properties = unsafe {
|
||||||
|
self.instance
|
||||||
|
.get_physical_device_format_properties(phy_dev, BLEND_FORMAT.vk_format)
|
||||||
|
};
|
||||||
|
let l = self
|
||||||
|
.load_internal_format(
|
||||||
|
phy_dev,
|
||||||
|
BLEND_FORMAT,
|
||||||
|
&format_properties,
|
||||||
|
BLEND_FEATURES,
|
||||||
|
BLEND_USAGE,
|
||||||
|
)?
|
||||||
|
.unwrap_or_default();
|
||||||
|
Ok(VulkanBlendBufferLimits {
|
||||||
|
max_width: l.limits.max_width,
|
||||||
|
max_height: l.limits.max_height,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
fn load_shm_format(
|
fn load_shm_format(
|
||||||
&self,
|
&self,
|
||||||
phy_dev: PhysicalDevice,
|
phy_dev: PhysicalDevice,
|
||||||
|
|
|
||||||
|
|
@ -64,6 +64,7 @@ pub struct VulkanImage {
|
||||||
pub(super) ty: VulkanImageMemory,
|
pub(super) ty: VulkanImageMemory,
|
||||||
pub(super) bridge: Option<VulkanFramebufferBridge>,
|
pub(super) bridge: Option<VulkanFramebufferBridge>,
|
||||||
pub(super) shader_read_only_optimal_descriptor: Box<[u8]>,
|
pub(super) shader_read_only_optimal_descriptor: Box<[u8]>,
|
||||||
|
pub(super) sampled_image_descriptor: Box<[u8]>,
|
||||||
pub(super) descriptor_buffer_version: Cell<u64>,
|
pub(super) descriptor_buffer_version: Cell<u64>,
|
||||||
pub(super) descriptor_buffer_offset: Cell<DeviceSize>,
|
pub(super) descriptor_buffer_offset: Cell<DeviceSize>,
|
||||||
pub(super) execution_version: Cell<u64>,
|
pub(super) execution_version: Cell<u64>,
|
||||||
|
|
@ -102,6 +103,7 @@ pub enum QueueTransfer {
|
||||||
pub enum VulkanImageMemory {
|
pub enum VulkanImageMemory {
|
||||||
DmaBuf(VulkanDmaBufImage),
|
DmaBuf(VulkanDmaBufImage),
|
||||||
Internal(VulkanShmImage),
|
Internal(VulkanShmImage),
|
||||||
|
Blend(#[expect(dead_code)] VulkanAllocation),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct VulkanDmaBufImage {
|
pub struct VulkanDmaBufImage {
|
||||||
|
|
@ -451,6 +453,7 @@ impl VulkanDmaBufImageTemplate {
|
||||||
shader_read_only_optimal_descriptor: self
|
shader_read_only_optimal_descriptor: self
|
||||||
.renderer
|
.renderer
|
||||||
.sampler_read_only_descriptor(texture_view),
|
.sampler_read_only_descriptor(texture_view),
|
||||||
|
sampled_image_descriptor: Box::new([]),
|
||||||
descriptor_buffer_version: Cell::new(0),
|
descriptor_buffer_version: Cell::new(0),
|
||||||
descriptor_buffer_offset: Cell::new(0),
|
descriptor_buffer_offset: Cell::new(0),
|
||||||
execution_version: Cell::new(0),
|
execution_version: Cell::new(0),
|
||||||
|
|
@ -539,10 +542,30 @@ impl GfxFramebuffer for VulkanImage {
|
||||||
ops: &[GfxApiOpt],
|
ops: &[GfxApiOpt],
|
||||||
clear: Option<&Color>,
|
clear: Option<&Color>,
|
||||||
region: &Region,
|
region: &Region,
|
||||||
_blend_buffer: Option<&Rc<dyn GfxBlendBuffer>>,
|
blend_buffer: Option<&Rc<dyn GfxBlendBuffer>>,
|
||||||
) -> Result<Option<SyncFile>, GfxError> {
|
) -> Result<Option<SyncFile>, GfxError> {
|
||||||
|
let mut blend_buffer =
|
||||||
|
blend_buffer.map(|b| b.clone().into_vk(&self.renderer.device.device));
|
||||||
|
if let Some(bb) = &blend_buffer {
|
||||||
|
if bb.size() != self.size() {
|
||||||
|
log::error!(
|
||||||
|
"Blend buffer has invalid size: {:?} != {:?}",
|
||||||
|
bb.size(),
|
||||||
|
self.size()
|
||||||
|
);
|
||||||
|
blend_buffer = None;
|
||||||
|
}
|
||||||
|
}
|
||||||
self.renderer
|
self.renderer
|
||||||
.execute(&self, acquire_sync, release_sync, ops, clear, region)
|
.execute(
|
||||||
|
&self,
|
||||||
|
acquire_sync,
|
||||||
|
release_sync,
|
||||||
|
ops,
|
||||||
|
clear,
|
||||||
|
region,
|
||||||
|
blend_buffer,
|
||||||
|
)
|
||||||
.map_err(|e| e.into())
|
.map_err(|e| e.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -610,6 +633,7 @@ impl GfxTexture for VulkanImage {
|
||||||
match &self.ty {
|
match &self.ty {
|
||||||
VulkanImageMemory::DmaBuf(b) => Some(&b.template.dmabuf),
|
VulkanImageMemory::DmaBuf(b) => Some(&b.template.dmabuf),
|
||||||
VulkanImageMemory::Internal(_) => None,
|
VulkanImageMemory::Internal(_) => None,
|
||||||
|
VulkanImageMemory::Blend(_) => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,7 @@ pub(super) struct PipelineCreateInfo {
|
||||||
pub(super) blend: bool,
|
pub(super) blend: bool,
|
||||||
pub(super) src_has_alpha: bool,
|
pub(super) src_has_alpha: bool,
|
||||||
pub(super) has_alpha_mult: bool,
|
pub(super) has_alpha_mult: bool,
|
||||||
|
pub(super) with_linear_output: bool,
|
||||||
pub(super) frag_descriptor_set_layout: Option<Rc<VulkanDescriptorSetLayout>>,
|
pub(super) frag_descriptor_set_layout: Option<Rc<VulkanDescriptorSetLayout>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -76,8 +77,8 @@ impl VulkanDevice {
|
||||||
};
|
};
|
||||||
let destroy_layout =
|
let destroy_layout =
|
||||||
OnDrop(|| unsafe { self.device.destroy_pipeline_layout(pipeline_layout, None) });
|
OnDrop(|| unsafe { self.device.destroy_pipeline_layout(pipeline_layout, None) });
|
||||||
let mut frag_spec_data = ArrayVec::<_, 8>::new();
|
let mut frag_spec_data = ArrayVec::<_, { 3 * 4 }>::new();
|
||||||
let mut frag_spec_entries = ArrayVec::<_, 2>::new();
|
let mut frag_spec_entries = ArrayVec::<_, 3>::new();
|
||||||
let mut frag_spec_entry = |data: &[u8]| {
|
let mut frag_spec_entry = |data: &[u8]| {
|
||||||
let entry = SpecializationMapEntry::default()
|
let entry = SpecializationMapEntry::default()
|
||||||
.constant_id(frag_spec_entries.len() as _)
|
.constant_id(frag_spec_entries.len() as _)
|
||||||
|
|
@ -88,6 +89,7 @@ impl VulkanDevice {
|
||||||
};
|
};
|
||||||
frag_spec_entry(&(info.src_has_alpha as u32).to_ne_bytes());
|
frag_spec_entry(&(info.src_has_alpha as u32).to_ne_bytes());
|
||||||
frag_spec_entry(&(info.has_alpha_mult as u32).to_ne_bytes());
|
frag_spec_entry(&(info.has_alpha_mult as u32).to_ne_bytes());
|
||||||
|
frag_spec_entry(&(info.with_linear_output as u32).to_ne_bytes());
|
||||||
let frag_spec = SpecializationInfo::default()
|
let frag_spec = SpecializationInfo::default()
|
||||||
.map_entries(&frag_spec_entries)
|
.map_entries(&frag_spec_entries)
|
||||||
.data(&frag_spec_data);
|
.data(&frag_spec_data);
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,8 @@ use {
|
||||||
cpu_worker::PendingJob,
|
cpu_worker::PendingJob,
|
||||||
format::XRGB8888,
|
format::XRGB8888,
|
||||||
gfx_api::{
|
gfx_api::{
|
||||||
AcquireSync, BufferResv, BufferResvUser, GfxApiOpt, GfxFormat, GfxFramebuffer,
|
AcquireSync, BufferResv, BufferResvUser, GfxApiOpt, GfxBlendBuffer, GfxFormat,
|
||||||
GfxTexture, GfxWriteModifier, ReleaseSync, SyncFile,
|
GfxFramebuffer, GfxTexture, GfxWriteModifier, ReleaseSync, SyncFile,
|
||||||
},
|
},
|
||||||
gfx_apis::vulkan::{
|
gfx_apis::vulkan::{
|
||||||
VulkanError,
|
VulkanError,
|
||||||
|
|
@ -17,13 +17,14 @@ use {
|
||||||
},
|
},
|
||||||
device::VulkanDevice,
|
device::VulkanDevice,
|
||||||
fence::VulkanFence,
|
fence::VulkanFence,
|
||||||
|
format::BLEND_FORMAT,
|
||||||
image::{QueueFamily, QueueState, QueueTransfer, VulkanImage, VulkanImageMemory},
|
image::{QueueFamily, QueueState, QueueTransfer, VulkanImage, VulkanImageMemory},
|
||||||
pipeline::{PipelineCreateInfo, VulkanPipeline},
|
pipeline::{PipelineCreateInfo, VulkanPipeline},
|
||||||
sampler::VulkanSampler,
|
sampler::VulkanSampler,
|
||||||
semaphore::VulkanSemaphore,
|
semaphore::VulkanSemaphore,
|
||||||
shaders::{
|
shaders::{
|
||||||
FILL_FRAG, FILL_VERT, FillPushConstants, TEX_FRAG, TEX_VERT, TexPushConstants,
|
FILL_FRAG, FILL_VERT, FillPushConstants, OUT_FRAG, OUT_VERT, OutPushConstants,
|
||||||
VulkanShader,
|
TEX_FRAG, TEX_VERT, TexPushConstants, VulkanShader,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
io_uring::IoUring,
|
io_uring::IoUring,
|
||||||
|
|
@ -55,9 +56,10 @@ use {
|
||||||
linearize::{Linearize, StaticMap, static_map},
|
linearize::{Linearize, StaticMap, static_map},
|
||||||
std::{
|
std::{
|
||||||
cell::{Cell, RefCell},
|
cell::{Cell, RefCell},
|
||||||
|
collections::hash_map::Entry,
|
||||||
fmt::{Debug, Formatter},
|
fmt::{Debug, Formatter},
|
||||||
mem, ptr,
|
mem, ptr,
|
||||||
rc::Rc,
|
rc::{Rc, Weak},
|
||||||
slice,
|
slice,
|
||||||
},
|
},
|
||||||
uapi::OwnedFd,
|
uapi::OwnedFd,
|
||||||
|
|
@ -67,6 +69,8 @@ pub struct VulkanRenderer {
|
||||||
pub(super) formats: Rc<AHashMap<u32, GfxFormat>>,
|
pub(super) formats: Rc<AHashMap<u32, GfxFormat>>,
|
||||||
pub(super) device: Rc<VulkanDevice>,
|
pub(super) device: Rc<VulkanDevice>,
|
||||||
pub(super) pipelines: CopyHashMap<vk::Format, Rc<VulkanFormatPipelines>>,
|
pub(super) pipelines: CopyHashMap<vk::Format, Rc<VulkanFormatPipelines>>,
|
||||||
|
pub(super) pipelines_with_blend_buffer: CopyHashMap<vk::Format, Rc<VulkanFormatPipelines>>,
|
||||||
|
pub(super) out_pipelines: RefCell<AHashMap<vk::Format, Rc<VulkanPipeline>>>,
|
||||||
pub(super) gfx_command_buffers: CachedCommandBuffers,
|
pub(super) gfx_command_buffers: CachedCommandBuffers,
|
||||||
pub(super) transfer_command_buffers: Option<CachedCommandBuffers>,
|
pub(super) transfer_command_buffers: Option<CachedCommandBuffers>,
|
||||||
pub(super) wait_semaphores: Stack<Rc<VulkanSemaphore>>,
|
pub(super) wait_semaphores: Stack<Rc<VulkanSemaphore>>,
|
||||||
|
|
@ -82,12 +86,17 @@ pub struct VulkanRenderer {
|
||||||
pub(super) fill_frag_shader: Rc<VulkanShader>,
|
pub(super) fill_frag_shader: Rc<VulkanShader>,
|
||||||
pub(super) tex_vert_shader: Rc<VulkanShader>,
|
pub(super) tex_vert_shader: Rc<VulkanShader>,
|
||||||
pub(super) tex_frag_shader: Rc<VulkanShader>,
|
pub(super) tex_frag_shader: Rc<VulkanShader>,
|
||||||
|
pub(super) out_vert_shader: Rc<VulkanShader>,
|
||||||
|
pub(super) out_frag_shader: Rc<VulkanShader>,
|
||||||
pub(super) tex_descriptor_set_layout: Rc<VulkanDescriptorSetLayout>,
|
pub(super) tex_descriptor_set_layout: Rc<VulkanDescriptorSetLayout>,
|
||||||
|
pub(super) out_descriptor_set_layout: Option<Rc<VulkanDescriptorSetLayout>>,
|
||||||
pub(super) defunct: Cell<bool>,
|
pub(super) defunct: Cell<bool>,
|
||||||
pub(super) pending_cpu_jobs: CopyHashMap<u64, PendingJob>,
|
pub(super) pending_cpu_jobs: CopyHashMap<u64, PendingJob>,
|
||||||
pub(super) shm_allocator: Rc<VulkanThreadedAllocator>,
|
pub(super) shm_allocator: Rc<VulkanThreadedAllocator>,
|
||||||
pub(super) sampler: Rc<VulkanSampler>,
|
pub(super) sampler: Rc<VulkanSampler>,
|
||||||
pub(super) sampler_descriptor_buffer_cache: Rc<VulkanDescriptorBufferCache>,
|
pub(super) sampler_descriptor_buffer_cache: Rc<VulkanDescriptorBufferCache>,
|
||||||
|
pub(super) resource_descriptor_buffer_cache: Rc<VulkanDescriptorBufferCache>,
|
||||||
|
pub(super) blend_buffers: RefCell<AHashMap<(u32, u32), Weak<VulkanImage>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) struct CachedCommandBuffers {
|
pub(super) struct CachedCommandBuffers {
|
||||||
|
|
@ -139,11 +148,13 @@ pub(super) struct Memory {
|
||||||
wait_semaphore_infos: Vec<SemaphoreSubmitInfo<'static>>,
|
wait_semaphore_infos: Vec<SemaphoreSubmitInfo<'static>>,
|
||||||
release_fence: Option<Rc<VulkanFence>>,
|
release_fence: Option<Rc<VulkanFence>>,
|
||||||
release_sync_file: Option<SyncFile>,
|
release_sync_file: Option<SyncFile>,
|
||||||
descriptor_buffers: ArrayVec<VulkanDescriptorBuffer, 1>,
|
descriptor_buffers: ArrayVec<VulkanDescriptorBuffer, 2>,
|
||||||
paint_regions: Vec<PaintRegion>,
|
paint_regions: Vec<PaintRegion>,
|
||||||
clear_rects: Vec<ClearRect>,
|
clear_rects: Vec<ClearRect>,
|
||||||
image_copy_regions: Vec<ImageCopy2<'static>>,
|
image_copy_regions: Vec<ImageCopy2<'static>>,
|
||||||
|
is_full_clear: bool,
|
||||||
sampler_descriptor_buffer_writer: VulkanDescriptorBufferWriter,
|
sampler_descriptor_buffer_writer: VulkanDescriptorBufferWriter,
|
||||||
|
resource_descriptor_buffer_writer: VulkanDescriptorBufferWriter,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct PaintRegion {
|
struct PaintRegion {
|
||||||
|
|
@ -159,11 +170,12 @@ pub(super) struct PendingFrame {
|
||||||
renderer: Rc<VulkanRenderer>,
|
renderer: Rc<VulkanRenderer>,
|
||||||
cmd: Cell<Option<Rc<VulkanCommandBuffer>>>,
|
cmd: Cell<Option<Rc<VulkanCommandBuffer>>>,
|
||||||
_fb: Rc<VulkanImage>,
|
_fb: Rc<VulkanImage>,
|
||||||
|
_bb: Option<Rc<VulkanImage>>,
|
||||||
_textures: Vec<UsedTexture>,
|
_textures: Vec<UsedTexture>,
|
||||||
wait_semaphores: Cell<Vec<Rc<VulkanSemaphore>>>,
|
wait_semaphores: Cell<Vec<Rc<VulkanSemaphore>>>,
|
||||||
waiter: Cell<Option<SpawnedFuture<()>>>,
|
waiter: Cell<Option<SpawnedFuture<()>>>,
|
||||||
_release_fence: Option<Rc<VulkanFence>>,
|
_release_fence: Option<Rc<VulkanFence>>,
|
||||||
_descriptor_buffers: ArrayVec<VulkanDescriptorBuffer, 1>,
|
_descriptor_buffers: ArrayVec<VulkanDescriptorBuffer, 2>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) struct VulkanFormatPipelines {
|
pub(super) struct VulkanFormatPipelines {
|
||||||
|
|
@ -181,6 +193,13 @@ impl VulkanDevice {
|
||||||
let fill_frag_shader = self.create_shader(FILL_FRAG)?;
|
let fill_frag_shader = self.create_shader(FILL_FRAG)?;
|
||||||
let sampler = self.create_sampler()?;
|
let sampler = self.create_sampler()?;
|
||||||
let tex_descriptor_set_layout = self.create_tex_descriptor_set_layout(&sampler)?;
|
let tex_descriptor_set_layout = self.create_tex_descriptor_set_layout(&sampler)?;
|
||||||
|
let out_descriptor_set_layout = self
|
||||||
|
.descriptor_buffer
|
||||||
|
.as_ref()
|
||||||
|
.map(|db| self.create_out_descriptor_set_layout(db))
|
||||||
|
.transpose()?;
|
||||||
|
let out_vert_shader = self.create_shader(OUT_VERT)?;
|
||||||
|
let out_frag_shader = self.create_shader(OUT_FRAG)?;
|
||||||
let tex_vert_shader = self.create_shader(TEX_VERT)?;
|
let tex_vert_shader = self.create_shader(TEX_VERT)?;
|
||||||
let tex_frag_shader = self.create_shader(TEX_FRAG)?;
|
let tex_frag_shader = self.create_shader(TEX_FRAG)?;
|
||||||
let gfx_command_buffers = self.create_command_pool(self.graphics_queue_idx)?;
|
let gfx_command_buffers = self.create_command_pool(self.graphics_queue_idx)?;
|
||||||
|
|
@ -223,10 +242,14 @@ impl VulkanDevice {
|
||||||
let shm_allocator = self.create_threaded_allocator()?;
|
let shm_allocator = self.create_threaded_allocator()?;
|
||||||
let sampler_descriptor_buffer_cache =
|
let sampler_descriptor_buffer_cache =
|
||||||
Rc::new(VulkanDescriptorBufferCache::new(self, &allocator, true));
|
Rc::new(VulkanDescriptorBufferCache::new(self, &allocator, true));
|
||||||
|
let resource_descriptor_buffer_cache =
|
||||||
|
Rc::new(VulkanDescriptorBufferCache::new(self, &allocator, false));
|
||||||
let render = Rc::new(VulkanRenderer {
|
let render = Rc::new(VulkanRenderer {
|
||||||
formats: Rc::new(formats),
|
formats: Rc::new(formats),
|
||||||
device: self.clone(),
|
device: self.clone(),
|
||||||
pipelines: Default::default(),
|
pipelines: Default::default(),
|
||||||
|
pipelines_with_blend_buffer: Default::default(),
|
||||||
|
out_pipelines: Default::default(),
|
||||||
gfx_command_buffers,
|
gfx_command_buffers,
|
||||||
transfer_command_buffers,
|
transfer_command_buffers,
|
||||||
wait_semaphores: Default::default(),
|
wait_semaphores: Default::default(),
|
||||||
|
|
@ -242,14 +265,19 @@ impl VulkanDevice {
|
||||||
fill_frag_shader,
|
fill_frag_shader,
|
||||||
tex_vert_shader,
|
tex_vert_shader,
|
||||||
tex_frag_shader,
|
tex_frag_shader,
|
||||||
|
out_vert_shader,
|
||||||
|
out_frag_shader,
|
||||||
tex_descriptor_set_layout,
|
tex_descriptor_set_layout,
|
||||||
|
out_descriptor_set_layout,
|
||||||
defunct: Cell::new(false),
|
defunct: Cell::new(false),
|
||||||
pending_cpu_jobs: Default::default(),
|
pending_cpu_jobs: Default::default(),
|
||||||
shm_allocator,
|
shm_allocator,
|
||||||
sampler,
|
sampler,
|
||||||
sampler_descriptor_buffer_cache,
|
sampler_descriptor_buffer_cache,
|
||||||
|
resource_descriptor_buffer_cache,
|
||||||
|
blend_buffers: Default::default(),
|
||||||
});
|
});
|
||||||
render.get_or_create_pipelines(XRGB8888.vk_format)?;
|
render.get_or_create_pipelines(XRGB8888.vk_format, None)?;
|
||||||
Ok(render)
|
Ok(render)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -258,8 +286,14 @@ impl VulkanRenderer {
|
||||||
fn get_or_create_pipelines(
|
fn get_or_create_pipelines(
|
||||||
&self,
|
&self,
|
||||||
format: vk::Format,
|
format: vk::Format,
|
||||||
|
bb: Option<&VulkanImage>,
|
||||||
) -> Result<Rc<VulkanFormatPipelines>, VulkanError> {
|
) -> Result<Rc<VulkanFormatPipelines>, VulkanError> {
|
||||||
if let Some(pl) = self.pipelines.get(&format) {
|
let with_linear_output = bb.is_some();
|
||||||
|
let pipelines = match with_linear_output {
|
||||||
|
false => &self.pipelines,
|
||||||
|
true => &self.pipelines_with_blend_buffer,
|
||||||
|
};
|
||||||
|
if let Some(pl) = pipelines.get(&format) {
|
||||||
return Ok(pl);
|
return Ok(pl);
|
||||||
}
|
}
|
||||||
let fill = self
|
let fill = self
|
||||||
|
|
@ -271,6 +305,7 @@ impl VulkanRenderer {
|
||||||
blend: true,
|
blend: true,
|
||||||
src_has_alpha: true,
|
src_has_alpha: true,
|
||||||
has_alpha_mult: false,
|
has_alpha_mult: false,
|
||||||
|
with_linear_output,
|
||||||
frag_descriptor_set_layout: None,
|
frag_descriptor_set_layout: None,
|
||||||
})?;
|
})?;
|
||||||
let create_tex_pipeline = |src_has_alpha, has_alpha_mult| {
|
let create_tex_pipeline = |src_has_alpha, has_alpha_mult| {
|
||||||
|
|
@ -282,6 +317,7 @@ impl VulkanRenderer {
|
||||||
blend: src_has_alpha || has_alpha_mult,
|
blend: src_has_alpha || has_alpha_mult,
|
||||||
src_has_alpha,
|
src_has_alpha,
|
||||||
has_alpha_mult,
|
has_alpha_mult,
|
||||||
|
with_linear_output,
|
||||||
frag_descriptor_set_layout: Some(self.tex_descriptor_set_layout.clone()),
|
frag_descriptor_set_layout: Some(self.tex_descriptor_set_layout.clone()),
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
@ -289,7 +325,7 @@ impl VulkanRenderer {
|
||||||
let tex_alpha = create_tex_pipeline(true, false)?;
|
let tex_alpha = create_tex_pipeline(true, false)?;
|
||||||
let tex_mult_opaque = create_tex_pipeline(false, true)?;
|
let tex_mult_opaque = create_tex_pipeline(false, true)?;
|
||||||
let tex_mult_alpha = create_tex_pipeline(true, true)?;
|
let tex_mult_alpha = create_tex_pipeline(true, true)?;
|
||||||
let pipelines = Rc::new(VulkanFormatPipelines {
|
let format_pipelines = Rc::new(VulkanFormatPipelines {
|
||||||
fill,
|
fill,
|
||||||
tex: static_map! {
|
tex: static_map! {
|
||||||
TexCopyType::Identity => static_map! {
|
TexCopyType::Identity => static_map! {
|
||||||
|
|
@ -302,8 +338,8 @@ impl VulkanRenderer {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
self.pipelines.set(format, pipelines.clone());
|
pipelines.set(format, format_pipelines.clone());
|
||||||
Ok(pipelines)
|
Ok(format_pipelines)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn allocate_point(&self) -> u64 {
|
pub(super) fn allocate_point(&self) -> u64 {
|
||||||
|
|
@ -314,6 +350,7 @@ impl VulkanRenderer {
|
||||||
&self,
|
&self,
|
||||||
buf: CommandBuffer,
|
buf: CommandBuffer,
|
||||||
opts: &[GfxApiOpt],
|
opts: &[GfxApiOpt],
|
||||||
|
bb: Option<&VulkanImage>,
|
||||||
) -> Result<(), VulkanError> {
|
) -> Result<(), VulkanError> {
|
||||||
let Some(db) = &self.device.descriptor_buffer else {
|
let Some(db) = &self.device.descriptor_buffer else {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
|
|
@ -324,6 +361,15 @@ impl VulkanRenderer {
|
||||||
memory.descriptor_buffers.clear();
|
memory.descriptor_buffers.clear();
|
||||||
let sampler_writer = &mut memory.sampler_descriptor_buffer_writer;
|
let sampler_writer = &mut memory.sampler_descriptor_buffer_writer;
|
||||||
sampler_writer.clear();
|
sampler_writer.clear();
|
||||||
|
let resource_writer = &mut memory.resource_descriptor_buffer_writer;
|
||||||
|
resource_writer.clear();
|
||||||
|
if let Some(bb) = bb {
|
||||||
|
let layout = self.out_descriptor_set_layout.as_ref().unwrap();
|
||||||
|
let offset = resource_writer.next_offset();
|
||||||
|
bb.descriptor_buffer_offset.set(offset);
|
||||||
|
let mut writer = resource_writer.add_set(layout);
|
||||||
|
writer.write(layout.offsets[0], &bb.sampled_image_descriptor);
|
||||||
|
}
|
||||||
for cmd in opts {
|
for cmd in opts {
|
||||||
let GfxApiOpt::CopyTexture(c) = cmd else {
|
let GfxApiOpt::CopyTexture(c) = cmd else {
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -341,8 +387,10 @@ impl VulkanRenderer {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
let mut infos = ArrayVec::<_, 2>::new();
|
let mut infos = ArrayVec::<_, 2>::new();
|
||||||
#[expect(clippy::single_element_loop)]
|
for (writer, cache) in [
|
||||||
for (writer, cache) in [(&sampler_writer, &self.sampler_descriptor_buffer_cache)] {
|
(&sampler_writer, &self.sampler_descriptor_buffer_cache),
|
||||||
|
(&resource_writer, &self.resource_descriptor_buffer_cache),
|
||||||
|
] {
|
||||||
let buffer = cache.allocate(writer.len() as DeviceSize)?;
|
let buffer = cache.allocate(writer.len() as DeviceSize)?;
|
||||||
buffer.buffer.allocation.upload(|ptr, _| unsafe {
|
buffer.buffer.allocation.upload(|ptr, _| unsafe {
|
||||||
ptr::copy_nonoverlapping(writer.as_ptr(), ptr, writer.len())
|
ptr::copy_nonoverlapping(writer.as_ptr(), ptr, writer.len())
|
||||||
|
|
@ -404,11 +452,31 @@ impl VulkanRenderer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn initial_barriers(&self, buf: CommandBuffer, fb: &VulkanImage) -> Result<(), VulkanError> {
|
fn initial_barriers(
|
||||||
|
&self,
|
||||||
|
buf: CommandBuffer,
|
||||||
|
fb: &VulkanImage,
|
||||||
|
bb: Option<&VulkanImage>,
|
||||||
|
) -> Result<(), VulkanError> {
|
||||||
zone!("initial_barriers");
|
zone!("initial_barriers");
|
||||||
let mut memory = self.memory.borrow_mut();
|
let mut memory = self.memory.borrow_mut();
|
||||||
let memory = &mut *memory;
|
let memory = &mut *memory;
|
||||||
memory.image_barriers.clear();
|
memory.image_barriers.clear();
|
||||||
|
if let Some(bb) = bb {
|
||||||
|
let barrier = image_barrier()
|
||||||
|
.image(bb.image)
|
||||||
|
.old_layout(if bb.is_undefined.get() {
|
||||||
|
ImageLayout::UNDEFINED
|
||||||
|
} else {
|
||||||
|
ImageLayout::SHADER_READ_ONLY_OPTIMAL
|
||||||
|
})
|
||||||
|
.new_layout(ImageLayout::COLOR_ATTACHMENT_OPTIMAL)
|
||||||
|
.src_stage_mask(PipelineStageFlags2::FRAGMENT_SHADER)
|
||||||
|
.dst_stage_mask(PipelineStageFlags2::COLOR_ATTACHMENT_OUTPUT)
|
||||||
|
.src_access_mask(AccessFlags2::SHADER_READ)
|
||||||
|
.dst_access_mask(AccessFlags2::COLOR_ATTACHMENT_WRITE);
|
||||||
|
memory.image_barriers.push(barrier);
|
||||||
|
}
|
||||||
let mut need_fb_barrier = true;
|
let mut need_fb_barrier = true;
|
||||||
if let VulkanImageMemory::Internal(..) = &fb.ty {
|
if let VulkanImageMemory::Internal(..) = &fb.ty {
|
||||||
need_fb_barrier = fb.is_undefined.get()
|
need_fb_barrier = fb.is_undefined.get()
|
||||||
|
|
@ -498,36 +566,59 @@ impl VulkanRenderer {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn begin_rendering(&self, buf: CommandBuffer, fb: &VulkanImage, clear: Option<&Color>) {
|
fn begin_rendering(
|
||||||
|
&self,
|
||||||
|
buf: CommandBuffer,
|
||||||
|
fb: &VulkanImage,
|
||||||
|
clear: Option<&Color>,
|
||||||
|
bb: Option<&VulkanImage>,
|
||||||
|
) {
|
||||||
zone!("begin_rendering");
|
zone!("begin_rendering");
|
||||||
let memory = &mut *self.memory.borrow_mut();
|
let memory = &mut *self.memory.borrow_mut();
|
||||||
let clear_value = clear.map(|clear| ClearValue {
|
let mut load_clear = None;
|
||||||
color: ClearColorValue {
|
let mut manual_clear = None;
|
||||||
float32: clear.to_array_srgb(None),
|
memory.is_full_clear = false;
|
||||||
},
|
if let Some(clear) = clear {
|
||||||
});
|
let clear_value = ClearValue {
|
||||||
let load_clear = memory.paint_regions.len() == 1 && {
|
color: ClearColorValue {
|
||||||
let rect = &memory.paint_regions[0].rect;
|
float32: if bb.is_some() {
|
||||||
rect.offset.x == 0
|
clear.to_array_linear(None)
|
||||||
&& rect.offset.y == 0
|
} else {
|
||||||
&& rect.extent.width == fb.width
|
clear.to_array_srgb(None)
|
||||||
&& rect.extent.height == fb.height
|
},
|
||||||
};
|
},
|
||||||
let (load_clear, manual_clear) = match load_clear {
|
};
|
||||||
false => (None, clear_value),
|
let use_load_clear = memory.paint_regions.len() == 1 && {
|
||||||
true => (clear_value, None),
|
let rect = &memory.paint_regions[0].rect;
|
||||||
};
|
rect.offset.x == 0
|
||||||
let rendering_attachment_info = {
|
&& rect.offset.y == 0
|
||||||
let mut rai = RenderingAttachmentInfo::default()
|
&& rect.extent.width == fb.width
|
||||||
.image_view(fb.render_view.unwrap_or(fb.texture_view))
|
&& rect.extent.height == fb.height
|
||||||
.image_layout(ImageLayout::COLOR_ATTACHMENT_OPTIMAL)
|
};
|
||||||
.load_op(AttachmentLoadOp::LOAD)
|
if use_load_clear {
|
||||||
.store_op(AttachmentStoreOp::STORE);
|
load_clear = Some(clear_value);
|
||||||
if let Some(clear) = load_clear {
|
} else {
|
||||||
rai = rai.clear_value(clear).load_op(AttachmentLoadOp::CLEAR);
|
manual_clear = Some(clear_value);
|
||||||
}
|
}
|
||||||
rai
|
memory.is_full_clear = use_load_clear;
|
||||||
|
}
|
||||||
|
let mut rendering_attachment_info = RenderingAttachmentInfo::default()
|
||||||
|
.image_layout(ImageLayout::COLOR_ATTACHMENT_OPTIMAL)
|
||||||
|
.store_op(AttachmentStoreOp::STORE);
|
||||||
|
rendering_attachment_info = if let Some(bb) = bb {
|
||||||
|
rendering_attachment_info
|
||||||
|
.image_view(bb.render_view.unwrap_or(bb.texture_view))
|
||||||
|
.load_op(AttachmentLoadOp::DONT_CARE)
|
||||||
|
} else {
|
||||||
|
rendering_attachment_info
|
||||||
|
.image_view(fb.render_view.unwrap_or(fb.texture_view))
|
||||||
|
.load_op(AttachmentLoadOp::LOAD)
|
||||||
};
|
};
|
||||||
|
if let Some(clear) = load_clear {
|
||||||
|
rendering_attachment_info = rendering_attachment_info
|
||||||
|
.clear_value(clear)
|
||||||
|
.load_op(AttachmentLoadOp::CLEAR);
|
||||||
|
}
|
||||||
let rendering_info = RenderingInfo::default()
|
let rendering_info = RenderingInfo::default()
|
||||||
.render_area(Rect2D {
|
.render_area(Rect2D {
|
||||||
offset: Default::default(),
|
offset: Default::default(),
|
||||||
|
|
@ -598,10 +689,15 @@ impl VulkanRenderer {
|
||||||
buf: CommandBuffer,
|
buf: CommandBuffer,
|
||||||
fb: &VulkanImage,
|
fb: &VulkanImage,
|
||||||
opts: &[GfxApiOpt],
|
opts: &[GfxApiOpt],
|
||||||
|
bb: Option<&VulkanImage>,
|
||||||
) -> Result<(), VulkanError> {
|
) -> Result<(), VulkanError> {
|
||||||
zone!("record_draws");
|
zone!("record_draws");
|
||||||
let memory = &*self.memory.borrow();
|
let memory = &*self.memory.borrow();
|
||||||
let pipelines = self.get_or_create_pipelines(fb.format.vk_format)?;
|
let format = match bb.is_some() {
|
||||||
|
false => fb.format.vk_format,
|
||||||
|
true => BLEND_FORMAT.vk_format,
|
||||||
|
};
|
||||||
|
let pipelines = self.get_or_create_pipelines(format, bb)?;
|
||||||
let dev = &self.device.device;
|
let dev = &self.device.device;
|
||||||
let mut current_pipeline = None;
|
let mut current_pipeline = None;
|
||||||
let mut bind = |pipeline: &VulkanPipeline| {
|
let mut bind = |pipeline: &VulkanPipeline| {
|
||||||
|
|
@ -618,7 +714,11 @@ impl VulkanRenderer {
|
||||||
GfxApiOpt::FillRect(r) => {
|
GfxApiOpt::FillRect(r) => {
|
||||||
let push = FillPushConstants {
|
let push = FillPushConstants {
|
||||||
pos: r.rect.to_points(),
|
pos: r.rect.to_points(),
|
||||||
color: r.color.to_array_srgb(r.alpha),
|
color: if bb.is_some() {
|
||||||
|
r.color.to_array_linear(r.alpha)
|
||||||
|
} else {
|
||||||
|
r.color.to_array_srgb(r.alpha)
|
||||||
|
},
|
||||||
};
|
};
|
||||||
for region in &memory.paint_regions {
|
for region in &memory.paint_regions {
|
||||||
let mut push = push;
|
let mut push = push;
|
||||||
|
|
@ -715,6 +815,103 @@ impl VulkanRenderer {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn copy_blend_buffer(
|
||||||
|
&self,
|
||||||
|
buf: CommandBuffer,
|
||||||
|
fb: &VulkanImage,
|
||||||
|
bb: Option<&VulkanImage>,
|
||||||
|
) -> Result<(), VulkanError> {
|
||||||
|
let Some(bb) = bb else {
|
||||||
|
return Ok(());
|
||||||
|
};
|
||||||
|
zone!("copy_blend_buffer");
|
||||||
|
let memory = &*self.memory.borrow();
|
||||||
|
let dev = &self.device.device;
|
||||||
|
let db = self.device.descriptor_buffer.as_ref().unwrap();
|
||||||
|
let pipeline = match self.out_pipelines.borrow_mut().entry(fb.format.vk_format) {
|
||||||
|
Entry::Occupied(pipeline) => pipeline.get().clone(),
|
||||||
|
Entry::Vacant(e) => {
|
||||||
|
let layout = self.out_descriptor_set_layout.as_ref().unwrap();
|
||||||
|
let out = self
|
||||||
|
.device
|
||||||
|
.create_pipeline::<OutPushConstants>(PipelineCreateInfo {
|
||||||
|
format: fb.format.vk_format,
|
||||||
|
vert: self.out_vert_shader.clone(),
|
||||||
|
frag: self.out_frag_shader.clone(),
|
||||||
|
blend: false,
|
||||||
|
src_has_alpha: true,
|
||||||
|
has_alpha_mult: false,
|
||||||
|
with_linear_output: true,
|
||||||
|
frag_descriptor_set_layout: Some(layout.clone()),
|
||||||
|
})?;
|
||||||
|
e.insert(out.clone());
|
||||||
|
out
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let image_barrier = image_barrier()
|
||||||
|
.image(bb.image)
|
||||||
|
.old_layout(ImageLayout::COLOR_ATTACHMENT_OPTIMAL)
|
||||||
|
.new_layout(ImageLayout::SHADER_READ_ONLY_OPTIMAL)
|
||||||
|
.src_access_mask(AccessFlags2::COLOR_ATTACHMENT_WRITE)
|
||||||
|
.dst_access_mask(AccessFlags2::SHADER_SAMPLED_READ)
|
||||||
|
.src_stage_mask(PipelineStageFlags2::COLOR_ATTACHMENT_OUTPUT)
|
||||||
|
.dst_stage_mask(PipelineStageFlags2::FRAGMENT_SHADER);
|
||||||
|
let dependency_info =
|
||||||
|
DependencyInfoKHR::default().image_memory_barriers(slice::from_ref(&image_barrier));
|
||||||
|
let rendering_attachment_info = RenderingAttachmentInfo::default()
|
||||||
|
.image_view(fb.render_view.unwrap_or(fb.texture_view))
|
||||||
|
.image_layout(ImageLayout::COLOR_ATTACHMENT_OPTIMAL)
|
||||||
|
.load_op(if memory.is_full_clear {
|
||||||
|
AttachmentLoadOp::DONT_CARE
|
||||||
|
} else {
|
||||||
|
AttachmentLoadOp::LOAD
|
||||||
|
})
|
||||||
|
.store_op(AttachmentStoreOp::STORE);
|
||||||
|
let rendering_info = RenderingInfo::default()
|
||||||
|
.render_area(Rect2D {
|
||||||
|
offset: Default::default(),
|
||||||
|
extent: Extent2D {
|
||||||
|
width: fb.width,
|
||||||
|
height: fb.height,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.layer_count(1)
|
||||||
|
.color_attachments(slice::from_ref(&rendering_attachment_info));
|
||||||
|
unsafe {
|
||||||
|
dev.cmd_pipeline_barrier2(buf, &dependency_info);
|
||||||
|
dev.cmd_begin_rendering(buf, &rendering_info);
|
||||||
|
dev.cmd_bind_pipeline(buf, PipelineBindPoint::GRAPHICS, pipeline.pipeline);
|
||||||
|
db.cmd_set_descriptor_buffer_offsets(
|
||||||
|
buf,
|
||||||
|
PipelineBindPoint::GRAPHICS,
|
||||||
|
pipeline.pipeline_layout,
|
||||||
|
0,
|
||||||
|
&[1],
|
||||||
|
&[bb.descriptor_buffer_offset.get()],
|
||||||
|
);
|
||||||
|
for region in &memory.paint_regions {
|
||||||
|
let push = OutPushConstants {
|
||||||
|
pos: [
|
||||||
|
[region.x2, region.y1],
|
||||||
|
[region.x1, region.y1],
|
||||||
|
[region.x2, region.y2],
|
||||||
|
[region.x1, region.y2],
|
||||||
|
],
|
||||||
|
};
|
||||||
|
dev.cmd_push_constants(
|
||||||
|
buf,
|
||||||
|
pipeline.pipeline_layout,
|
||||||
|
ShaderStageFlags::VERTEX | ShaderStageFlags::FRAGMENT,
|
||||||
|
0,
|
||||||
|
uapi::as_bytes(&push),
|
||||||
|
);
|
||||||
|
dev.cmd_draw(buf, 4, 1, 0, 0);
|
||||||
|
}
|
||||||
|
dev.cmd_end_rendering(buf);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn end_rendering(&self, buf: CommandBuffer) {
|
fn end_rendering(&self, buf: CommandBuffer) {
|
||||||
zone!("end_rendering");
|
zone!("end_rendering");
|
||||||
unsafe {
|
unsafe {
|
||||||
|
|
@ -997,7 +1194,10 @@ impl VulkanRenderer {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn store_layouts(&self, fb: &VulkanImage) {
|
fn store_layouts(&self, fb: &VulkanImage, bb: Option<&VulkanImage>) {
|
||||||
|
if let Some(bb) = bb {
|
||||||
|
bb.is_undefined.set(false);
|
||||||
|
}
|
||||||
fb.is_undefined.set(false);
|
fb.is_undefined.set(false);
|
||||||
fb.contents_are_undefined.set(false);
|
fb.contents_are_undefined.set(false);
|
||||||
fb.queue_state.set(QueueState::Acquired {
|
fb.queue_state.set(QueueState::Acquired {
|
||||||
|
|
@ -1011,7 +1211,12 @@ impl VulkanRenderer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_pending_frame(self: &Rc<Self>, buf: Rc<VulkanCommandBuffer>, fb: &Rc<VulkanImage>) {
|
fn create_pending_frame(
|
||||||
|
self: &Rc<Self>,
|
||||||
|
buf: Rc<VulkanCommandBuffer>,
|
||||||
|
fb: &Rc<VulkanImage>,
|
||||||
|
bb: Option<Rc<VulkanImage>>,
|
||||||
|
) {
|
||||||
zone!("create_pending_frame");
|
zone!("create_pending_frame");
|
||||||
let point = self.allocate_point();
|
let point = self.allocate_point();
|
||||||
let mut memory = self.memory.borrow_mut();
|
let mut memory = self.memory.borrow_mut();
|
||||||
|
|
@ -1020,6 +1225,7 @@ impl VulkanRenderer {
|
||||||
renderer: self.clone(),
|
renderer: self.clone(),
|
||||||
cmd: Cell::new(Some(buf)),
|
cmd: Cell::new(Some(buf)),
|
||||||
_fb: fb.clone(),
|
_fb: fb.clone(),
|
||||||
|
_bb: bb,
|
||||||
_textures: mem::take(&mut memory.textures),
|
_textures: mem::take(&mut memory.textures),
|
||||||
wait_semaphores: Cell::new(mem::take(&mut memory.wait_semaphores)),
|
wait_semaphores: Cell::new(mem::take(&mut memory.wait_semaphores)),
|
||||||
waiter: Cell::new(None),
|
waiter: Cell::new(None),
|
||||||
|
|
@ -1047,9 +1253,18 @@ impl VulkanRenderer {
|
||||||
opts: &[GfxApiOpt],
|
opts: &[GfxApiOpt],
|
||||||
clear: Option<&Color>,
|
clear: Option<&Color>,
|
||||||
region: &Region,
|
region: &Region,
|
||||||
|
blend_buffer: Option<Rc<VulkanImage>>,
|
||||||
) -> Result<Option<SyncFile>, VulkanError> {
|
) -> Result<Option<SyncFile>, VulkanError> {
|
||||||
zone!("execute");
|
zone!("execute");
|
||||||
let res = self.try_execute(fb, fb_acquire_sync, fb_release_sync, opts, clear, region);
|
let res = self.try_execute(
|
||||||
|
fb,
|
||||||
|
fb_acquire_sync,
|
||||||
|
fb_release_sync,
|
||||||
|
opts,
|
||||||
|
clear,
|
||||||
|
region,
|
||||||
|
blend_buffer,
|
||||||
|
);
|
||||||
let sync_file = {
|
let sync_file = {
|
||||||
let mut memory = self.memory.borrow_mut();
|
let mut memory = self.memory.borrow_mut();
|
||||||
memory.textures.clear();
|
memory.textures.clear();
|
||||||
|
|
@ -1119,26 +1334,29 @@ impl VulkanRenderer {
|
||||||
opts: &[GfxApiOpt],
|
opts: &[GfxApiOpt],
|
||||||
clear: Option<&Color>,
|
clear: Option<&Color>,
|
||||||
region: &Region,
|
region: &Region,
|
||||||
|
blend_buffer: Option<Rc<VulkanImage>>,
|
||||||
) -> Result<(), VulkanError> {
|
) -> Result<(), VulkanError> {
|
||||||
|
let bb = blend_buffer.as_deref();
|
||||||
self.check_defunct()?;
|
self.check_defunct()?;
|
||||||
self.create_paint_regions(fb, region);
|
self.create_paint_regions(fb, region);
|
||||||
let buf = self.gfx_command_buffers.allocate()?;
|
let buf = self.gfx_command_buffers.allocate()?;
|
||||||
self.collect_memory(opts);
|
self.collect_memory(opts);
|
||||||
self.begin_command_buffer(buf.buffer)?;
|
self.begin_command_buffer(buf.buffer)?;
|
||||||
self.create_descriptor_buffers(buf.buffer, opts)?;
|
self.create_descriptor_buffers(buf.buffer, opts, bb)?;
|
||||||
self.initial_barriers(buf.buffer, fb)?;
|
self.initial_barriers(buf.buffer, fb, bb)?;
|
||||||
self.begin_rendering(buf.buffer, fb, clear);
|
self.begin_rendering(buf.buffer, fb, clear, bb);
|
||||||
self.set_viewport(buf.buffer, fb);
|
self.set_viewport(buf.buffer, fb);
|
||||||
self.record_draws(buf.buffer, fb, opts)?;
|
self.record_draws(buf.buffer, fb, opts, bb)?;
|
||||||
self.end_rendering(buf.buffer);
|
self.end_rendering(buf.buffer);
|
||||||
|
self.copy_blend_buffer(buf.buffer, fb, bb)?;
|
||||||
self.copy_bridge_to_dmabuf(buf.buffer, fb);
|
self.copy_bridge_to_dmabuf(buf.buffer, fb);
|
||||||
self.final_barriers(buf.buffer, fb);
|
self.final_barriers(buf.buffer, fb);
|
||||||
self.end_command_buffer(buf.buffer)?;
|
self.end_command_buffer(buf.buffer)?;
|
||||||
self.create_wait_semaphores(fb, &fb_acquire_sync)?;
|
self.create_wait_semaphores(fb, &fb_acquire_sync)?;
|
||||||
self.submit(buf.buffer)?;
|
self.submit(buf.buffer)?;
|
||||||
self.import_release_semaphore(fb, fb_release_sync);
|
self.import_release_semaphore(fb, fb_release_sync);
|
||||||
self.store_layouts(fb);
|
self.store_layouts(fb, bb);
|
||||||
self.create_pending_frame(buf, fb);
|
self.create_pending_frame(buf, fb, blend_buffer);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1210,6 +1428,17 @@ impl dyn GfxTexture {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl dyn GfxBlendBuffer {
|
||||||
|
pub(super) fn into_vk(self: Rc<Self>, device: &Device) -> Rc<VulkanImage> {
|
||||||
|
let img: Rc<VulkanImage> = self
|
||||||
|
.into_any()
|
||||||
|
.downcast()
|
||||||
|
.expect("Non-vulkan blend buffer passed into vulkan");
|
||||||
|
img.assert_device(device);
|
||||||
|
img
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub(super) fn image_barrier() -> ImageMemoryBarrier2<'static> {
|
pub(super) fn image_barrier() -> ImageMemoryBarrier2<'static> {
|
||||||
ImageMemoryBarrier2::default().subresource_range(
|
ImageMemoryBarrier2::default().subresource_range(
|
||||||
ImageSubresourceRange::default()
|
ImageSubresourceRange::default()
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,8 @@ pub const FILL_VERT: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/fill.vert
|
||||||
pub const FILL_FRAG: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/fill.frag.spv"));
|
pub const FILL_FRAG: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/fill.frag.spv"));
|
||||||
pub const TEX_VERT: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/tex.vert.spv"));
|
pub const TEX_VERT: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/tex.vert.spv"));
|
||||||
pub const TEX_FRAG: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/tex.frag.spv"));
|
pub const TEX_FRAG: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/tex.frag.spv"));
|
||||||
|
pub const OUT_VERT: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/out.vert.spv"));
|
||||||
|
pub const OUT_FRAG: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/out.frag.spv"));
|
||||||
|
|
||||||
pub struct VulkanShader {
|
pub struct VulkanShader {
|
||||||
pub(super) device: Rc<VulkanDevice>,
|
pub(super) device: Rc<VulkanDevice>,
|
||||||
|
|
@ -34,6 +36,14 @@ pub struct TexPushConstants {
|
||||||
|
|
||||||
unsafe impl Packed for TexPushConstants {}
|
unsafe impl Packed for TexPushConstants {}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct OutPushConstants {
|
||||||
|
pub pos: [[f32; 2]; 4],
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl Packed for OutPushConstants {}
|
||||||
|
|
||||||
impl VulkanDevice {
|
impl VulkanDevice {
|
||||||
pub(super) fn create_shader(
|
pub(super) fn create_shader(
|
||||||
self: &Rc<Self>,
|
self: &Rc<Self>,
|
||||||
|
|
|
||||||
|
|
@ -1,2 +1,8 @@
|
||||||
|
#ifndef FRAG_SPEC_CONST_GLSL
|
||||||
|
#define FRAG_SPEC_CONST_GLSL
|
||||||
|
|
||||||
layout(constant_id = 0) const bool src_has_alpha = false;
|
layout(constant_id = 0) const bool src_has_alpha = false;
|
||||||
layout(constant_id = 1) const bool has_alpha_multiplier = false;
|
layout(constant_id = 1) const bool has_alpha_multiplier = false;
|
||||||
|
layout(constant_id = 2) const bool color_management = false;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
||||||
3
src/gfx_apis/vulkan/shaders/out.common.glsl
Normal file
3
src/gfx_apis/vulkan/shaders/out.common.glsl
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
layout(push_constant, std430) uniform Data {
|
||||||
|
layout(offset = 0) vec2 pos[4];
|
||||||
|
} data;
|
||||||
17
src/gfx_apis/vulkan/shaders/out.frag
Normal file
17
src/gfx_apis/vulkan/shaders/out.frag
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
#version 450
|
||||||
|
#extension GL_EXT_samplerless_texture_functions : require
|
||||||
|
|
||||||
|
#include "frag_spec_const.glsl"
|
||||||
|
#include "transfer_functions.glsl"
|
||||||
|
#include "out.common.glsl"
|
||||||
|
|
||||||
|
layout(set = 0, binding = 0) uniform texture2D in_color;
|
||||||
|
layout(location = 0) out vec4 out_color;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec4 c = texelFetch(in_color, ivec2(gl_FragCoord.xy), 0);
|
||||||
|
c.rgb /= mix(c.a, 1.0, c.a == 0.0);
|
||||||
|
c.rgb = oetf_srgb(c.rgb);
|
||||||
|
c.rgb *= c.a;
|
||||||
|
out_color = c;
|
||||||
|
}
|
||||||
16
src/gfx_apis/vulkan/shaders/out.vert
Normal file
16
src/gfx_apis/vulkan/shaders/out.vert
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
#version 450
|
||||||
|
//#extension GL_EXT_debug_printf : enable
|
||||||
|
|
||||||
|
#include "out.common.glsl"
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec2 pos;
|
||||||
|
switch (gl_VertexIndex) {
|
||||||
|
case 0: pos = data.pos[0]; break;
|
||||||
|
case 1: pos = data.pos[1]; break;
|
||||||
|
case 2: pos = data.pos[2]; break;
|
||||||
|
case 3: pos = data.pos[3]; break;
|
||||||
|
}
|
||||||
|
gl_Position = vec4(pos, 0.0, 1.0);
|
||||||
|
// debugPrintfEXT("X gl_Position = %v4f, pos = %v2f", gl_Position, pos);
|
||||||
|
}
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
#version 450
|
#version 450
|
||||||
|
|
||||||
#include "frag_spec_const.glsl"
|
#include "frag_spec_const.glsl"
|
||||||
|
#include "transfer_functions.glsl"
|
||||||
#include "tex.common.glsl"
|
#include "tex.common.glsl"
|
||||||
|
|
||||||
layout(set = 0, binding = 0) uniform sampler2D tex;
|
layout(set = 0, binding = 0) uniform sampler2D tex;
|
||||||
|
|
@ -8,13 +9,22 @@ layout(location = 0) in vec2 tex_pos;
|
||||||
layout(location = 0) out vec4 out_color;
|
layout(location = 0) out vec4 out_color;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
|
vec4 c = textureLod(tex, tex_pos, 0);
|
||||||
|
if (color_management) {
|
||||||
|
if (src_has_alpha) {
|
||||||
|
c.rgb /= mix(c.a, 1.0, c.a == 0.0);
|
||||||
|
}
|
||||||
|
c.rgb = eotf_srgb(c.rgb);
|
||||||
|
if (src_has_alpha) {
|
||||||
|
c.rgb *= c.a;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (has_alpha_multiplier) {
|
if (has_alpha_multiplier) {
|
||||||
if (src_has_alpha) {
|
if (src_has_alpha) {
|
||||||
out_color = textureLod(tex, tex_pos, 0) * data.mul;
|
c *= data.mul;
|
||||||
} else {
|
} else {
|
||||||
out_color = vec4(textureLod(tex, tex_pos, 0).rgb * data.mul, data.mul);
|
c = vec4(c.rgb * data.mul, data.mul);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
out_color = textureLod(tex, tex_pos, 0);
|
|
||||||
}
|
}
|
||||||
|
out_color = c;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
21
src/gfx_apis/vulkan/shaders/transfer_functions.glsl
Normal file
21
src/gfx_apis/vulkan/shaders/transfer_functions.glsl
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
#ifndef TRANSFER_FUNCTIONS_GLSL
|
||||||
|
#define TRANSFER_FUNCTIONS_GLSL
|
||||||
|
|
||||||
|
vec3 eotf_srgb(vec3 c) {
|
||||||
|
return mix(
|
||||||
|
c * vec3(1.0 / 12.92),
|
||||||
|
pow((c + vec3(0.055)) / vec3(1.055), vec3(2.4)),
|
||||||
|
greaterThan(c, vec3(0.04045))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 oetf_srgb(vec3 c) {
|
||||||
|
c = clamp(c, 0.0, 1.0);
|
||||||
|
return mix(
|
||||||
|
c * vec3(12.92),
|
||||||
|
vec3(1.055) * pow(c, vec3(1/2.4)) - vec3(0.055),
|
||||||
|
greaterThan(c, vec3(0.0031308))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -460,12 +460,14 @@ impl VulkanRenderer {
|
||||||
ty: VulkanImageMemory::Internal(shm),
|
ty: VulkanImageMemory::Internal(shm),
|
||||||
bridge: None,
|
bridge: None,
|
||||||
shader_read_only_optimal_descriptor: self.sampler_read_only_descriptor(view),
|
shader_read_only_optimal_descriptor: self.sampler_read_only_descriptor(view),
|
||||||
|
sampled_image_descriptor: Box::new([]),
|
||||||
descriptor_buffer_version: Cell::new(0),
|
descriptor_buffer_version: Cell::new(0),
|
||||||
descriptor_buffer_offset: Cell::new(0),
|
descriptor_buffer_offset: Cell::new(0),
|
||||||
execution_version: Cell::new(0),
|
execution_version: Cell::new(0),
|
||||||
});
|
});
|
||||||
let shm = match &img.ty {
|
let shm = match &img.ty {
|
||||||
VulkanImageMemory::DmaBuf(_) => unreachable!(),
|
VulkanImageMemory::DmaBuf(_) => unreachable!(),
|
||||||
|
VulkanImageMemory::Blend(_) => unreachable!(),
|
||||||
VulkanImageMemory::Internal(s) => s,
|
VulkanImageMemory::Internal(s) => s,
|
||||||
};
|
};
|
||||||
if data.is_not_empty() {
|
if data.is_not_empty() {
|
||||||
|
|
|
||||||
15
src/theme.rs
15
src/theme.rs
|
|
@ -120,20 +120,21 @@ impl Color {
|
||||||
[self.r * a, self.g * a, self.b * a, self.a * a]
|
[self.r * a, self.g * a, self.b * a, self.a * a]
|
||||||
}
|
}
|
||||||
|
|
||||||
#[expect(dead_code)]
|
pub fn to_array_linear(self, alpha: Option<f32>) -> [f32; 4] {
|
||||||
pub fn to_array_linear(self) -> [f32; 4] {
|
|
||||||
fn to_linear(srgb: f32) -> f32 {
|
fn to_linear(srgb: f32) -> f32 {
|
||||||
if srgb <= 0.04045 {
|
if srgb <= 0.04045 {
|
||||||
srgb / 12.92
|
srgb / 12.92
|
||||||
} else {
|
} else {
|
||||||
(srgb + 0.055 / 1.055).powf(2.4)
|
((srgb + 0.055) / 1.055).powf(2.4)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
let a1 = if self.a == 0.0 { 1.0 } else { self.a };
|
||||||
|
let a2 = self.a * alpha.unwrap_or(1.0);
|
||||||
[
|
[
|
||||||
to_linear(self.r),
|
to_linear(self.r / a1) * a2,
|
||||||
to_linear(self.g),
|
to_linear(self.g / a1) * a2,
|
||||||
to_linear(self.b),
|
to_linear(self.b / a1) * a2,
|
||||||
self.a,
|
a2,
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue