jay-compositor 1.15.0

The Jay compositor
use crate::gfx_api::GfxBlendBuffer;
use crate::gfx_apis::vulkan::VulkanError;
use crate::gfx_apis::vulkan::format::BLEND_FORMAT;
use crate::gfx_apis::vulkan::format::BLEND_USAGE;
use crate::gfx_apis::vulkan::image::QueueFamily;
use crate::gfx_apis::vulkan::image::QueueState;
use crate::gfx_apis::vulkan::image::VulkanImage;
use crate::gfx_apis::vulkan::image::VulkanImageMemory;
use crate::gfx_apis::vulkan::renderer::VulkanRenderer;
use ash::vk::Extent3D;
use ash::vk::ImageAspectFlags;
use ash::vk::ImageCreateInfo;
use ash::vk::ImageLayout;
use ash::vk::ImageSubresourceRange;
use ash::vk::ImageTiling;
use ash::vk::ImageType;
use ash::vk::ImageViewCreateInfo;
use ash::vk::ImageViewType;
use ash::vk::SampleCountFlags;
use ash::vk::SharingMode;
use gpu_alloc::UsageFlags;
use hashbrown::hash_map::Entry;
use run_on_drop::on_drop;
use std::cell::Cell;
use std::rc::Rc;

impl VulkanRenderer {
    pub fn acquire_blend_buffer(
        self: &Rc<Self>,
        width: i32,
        height: i32,
    ) -> Result<Rc<VulkanImage>, VulkanError> {
        if self.device.uses_legacy_descriptors() {
            return Err(VulkanError::NoBlendBuffers);
        }
        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
            && 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 usage = BLEND_USAGE;
        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(usage);
        let image = unsafe { self.device.device.create_image(&create_info, None) };
        let image = image.map_err(VulkanError::CreateImage)?;
        let destroy_image = on_drop(|| 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)?;
        let destroy_view = on_drop(|| unsafe { self.device.device.destroy_image_view(view, None) });
        let descriptor_heap = self.descriptor_heap_image(usage, &image_view_create_info)?;
        destroy_view.forget();
        destroy_image.forget();
        let img = Rc::new(VulkanImage {
            renderer: self.clone(),
            format: BLEND_FORMAT,
            width,
            height,
            stride: 0,
            texture_view: Some(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,
            execution_version: Default::default(),
            descriptor_buffer: self.descriptor_buffer_image(usage, view),
            descriptor_heap,
        });
        cached.insert(Rc::downgrade(&img));
        Ok(img)
    }
}

impl GfxBlendBuffer for VulkanImage {}