vulkan: optimize blend-buffer usage
This commit is contained in:
parent
cb9da22ec2
commit
292f181615
4 changed files with 362 additions and 236 deletions
|
|
@ -165,6 +165,28 @@ impl FramebufferRect {
|
||||||
pub fn is_covering(&self) -> bool {
|
pub fn is_covering(&self) -> bool {
|
||||||
self.x1 == -1.0 && self.y1 == -1.0 && self.x2 == 1.0 && self.y2 == 1.0
|
self.x1 == -1.0 && self.y1 == -1.0 && self.x2 == 1.0 && self.y2 == 1.0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn to_rect(&self, width: f32, height: f32) -> Rect {
|
||||||
|
let mut x1 = self.x1;
|
||||||
|
let mut x2 = self.x2;
|
||||||
|
let mut y1 = self.y1;
|
||||||
|
let mut y2 = self.y2;
|
||||||
|
(x1, y1, x2, y2) = match self.output_transform {
|
||||||
|
Transform::None => (x1, y1, x2, y2),
|
||||||
|
Transform::Rotate90 => (y1, -x2, y2, -x1),
|
||||||
|
Transform::Rotate180 => (-x2, -y2, -x1, -y1),
|
||||||
|
Transform::Rotate270 => (-y2, x1, -y1, x2),
|
||||||
|
Transform::Flip => (-x2, y1, -x1, y2),
|
||||||
|
Transform::FlipRotate90 => (y1, x1, y2, x2),
|
||||||
|
Transform::FlipRotate180 => (x1, -y2, x2, -y1),
|
||||||
|
Transform::FlipRotate270 => (-y2, -x2, -y1, -x1),
|
||||||
|
};
|
||||||
|
let x1 = ((x1 + 1.0) / 2.0 * width).round() as i32;
|
||||||
|
let x2 = ((x2 + 1.0) / 2.0 * width).round() as i32;
|
||||||
|
let y1 = ((y1 + 1.0) / 2.0 * height).round() as i32;
|
||||||
|
let y2 = ((y2 + 1.0) / 2.0 * height).round() as i32;
|
||||||
|
Rect::new(x1, y1, x2, y2).unwrap_or_default()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
|
@ -192,7 +214,6 @@ pub struct CopyTexture {
|
||||||
pub acquire_sync: AcquireSync,
|
pub acquire_sync: AcquireSync,
|
||||||
pub release_sync: ReleaseSync,
|
pub release_sync: ReleaseSync,
|
||||||
pub alpha: Option<f32>,
|
pub alpha: Option<f32>,
|
||||||
#[expect(dead_code)]
|
|
||||||
pub opaque: bool,
|
pub opaque: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ use {
|
||||||
format::XRGB8888,
|
format::XRGB8888,
|
||||||
gfx_api::{
|
gfx_api::{
|
||||||
AcquireSync, BufferResv, BufferResvUser, GfxApiOpt, GfxBlendBuffer, GfxFormat,
|
AcquireSync, BufferResv, BufferResvUser, GfxApiOpt, GfxBlendBuffer, GfxFormat,
|
||||||
GfxFramebuffer, GfxTexture, GfxWriteModifier, ReleaseSync, SyncFile,
|
GfxTexture, GfxWriteModifier, ReleaseSync, SyncFile,
|
||||||
},
|
},
|
||||||
gfx_apis::vulkan::{
|
gfx_apis::vulkan::{
|
||||||
VulkanError,
|
VulkanError,
|
||||||
|
|
@ -17,7 +17,6 @@ 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,
|
||||||
|
|
@ -28,7 +27,7 @@ use {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
io_uring::IoUring,
|
io_uring::IoUring,
|
||||||
rect::Region,
|
rect::{Rect, Region},
|
||||||
theme::Color,
|
theme::Color,
|
||||||
utils::{
|
utils::{
|
||||||
copyhashmap::CopyHashMap, errorfmt::ErrorFmt, numcell::NumCell, once::Once,
|
copyhashmap::CopyHashMap, errorfmt::ErrorFmt, numcell::NumCell, once::Once,
|
||||||
|
|
@ -53,8 +52,10 @@ use {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
isnt::std_1::{collections::IsntHashMapExt, primitive::IsntSliceExt},
|
isnt::std_1::{collections::IsntHashMapExt, primitive::IsntSliceExt},
|
||||||
|
jay_algorithms::rect::Tag,
|
||||||
linearize::{Linearize, StaticMap, static_map},
|
linearize::{Linearize, StaticMap, static_map},
|
||||||
std::{
|
std::{
|
||||||
|
borrow::Cow,
|
||||||
cell::{Cell, RefCell},
|
cell::{Cell, RefCell},
|
||||||
collections::hash_map::Entry,
|
collections::hash_map::Entry,
|
||||||
fmt::{Debug, Formatter},
|
fmt::{Debug, Formatter},
|
||||||
|
|
@ -68,8 +69,7 @@ use {
|
||||||
pub struct VulkanRenderer {
|
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: StaticMap<RenderPass, 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) 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>,
|
||||||
|
|
@ -149,16 +149,22 @@ pub(super) struct Memory {
|
||||||
release_fence: Option<Rc<VulkanFence>>,
|
release_fence: Option<Rc<VulkanFence>>,
|
||||||
release_sync_file: Option<SyncFile>,
|
release_sync_file: Option<SyncFile>,
|
||||||
descriptor_buffers: ArrayVec<VulkanDescriptorBuffer, 2>,
|
descriptor_buffers: ArrayVec<VulkanDescriptorBuffer, 2>,
|
||||||
paint_regions: Vec<PaintRegion>,
|
paint_regions: StaticMap<RenderPass, Vec<PaintRegion>>,
|
||||||
clear_rects: Vec<ClearRect>,
|
clear_rects: StaticMap<RenderPass, 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,
|
resource_descriptor_buffer_writer: VulkanDescriptorBufferWriter,
|
||||||
|
regions_1: Vec<Rect>,
|
||||||
|
regions_2: Vec<Rect<u32>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, Linearize, Eq, PartialEq)]
|
||||||
|
pub(super) enum RenderPass {
|
||||||
|
BlendBuffer,
|
||||||
|
FrameBuffer,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct PaintRegion {
|
struct PaintRegion {
|
||||||
rect: Rect2D,
|
|
||||||
x1: f32,
|
x1: f32,
|
||||||
y1: f32,
|
y1: f32,
|
||||||
x2: f32,
|
x2: f32,
|
||||||
|
|
@ -179,7 +185,7 @@ pub(super) struct PendingFrame {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) struct VulkanFormatPipelines {
|
pub(super) struct VulkanFormatPipelines {
|
||||||
pub(super) fill: Rc<VulkanPipeline>,
|
pub(super) fill: StaticMap<TexSourceType, Rc<VulkanPipeline>>,
|
||||||
pub(super) tex: StaticMap<TexCopyType, StaticMap<TexSourceType, Rc<VulkanPipeline>>>,
|
pub(super) tex: StaticMap<TexCopyType, StaticMap<TexSourceType, Rc<VulkanPipeline>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -248,7 +254,6 @@ impl VulkanDevice {
|
||||||
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(),
|
out_pipelines: Default::default(),
|
||||||
gfx_command_buffers,
|
gfx_command_buffers,
|
||||||
transfer_command_buffers,
|
transfer_command_buffers,
|
||||||
|
|
@ -277,7 +282,7 @@ impl VulkanDevice {
|
||||||
resource_descriptor_buffer_cache,
|
resource_descriptor_buffer_cache,
|
||||||
blend_buffers: Default::default(),
|
blend_buffers: Default::default(),
|
||||||
});
|
});
|
||||||
render.get_or_create_pipelines(XRGB8888.vk_format, None)?;
|
render.get_or_create_pipelines(XRGB8888.vk_format, RenderPass::FrameBuffer)?;
|
||||||
Ok(render)
|
Ok(render)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -286,28 +291,28 @@ impl VulkanRenderer {
|
||||||
fn get_or_create_pipelines(
|
fn get_or_create_pipelines(
|
||||||
&self,
|
&self,
|
||||||
format: vk::Format,
|
format: vk::Format,
|
||||||
bb: Option<&VulkanImage>,
|
pass: RenderPass,
|
||||||
) -> Result<Rc<VulkanFormatPipelines>, VulkanError> {
|
) -> Result<Rc<VulkanFormatPipelines>, VulkanError> {
|
||||||
let with_linear_output = bb.is_some();
|
let with_linear_output = pass == RenderPass::BlendBuffer;
|
||||||
let pipelines = match with_linear_output {
|
let pipelines = &self.pipelines[pass];
|
||||||
false => &self.pipelines,
|
|
||||||
true => &self.pipelines_with_blend_buffer,
|
|
||||||
};
|
|
||||||
if let Some(pl) = pipelines.get(&format) {
|
if let Some(pl) = pipelines.get(&format) {
|
||||||
return Ok(pl);
|
return Ok(pl);
|
||||||
}
|
}
|
||||||
let fill = self
|
let create_fill_pipeline = |src_has_alpha| {
|
||||||
.device
|
self.device
|
||||||
.create_pipeline::<FillPushConstants>(PipelineCreateInfo {
|
.create_pipeline::<FillPushConstants>(PipelineCreateInfo {
|
||||||
format,
|
format,
|
||||||
vert: self.fill_vert_shader.clone(),
|
vert: self.fill_vert_shader.clone(),
|
||||||
frag: self.fill_frag_shader.clone(),
|
frag: self.fill_frag_shader.clone(),
|
||||||
blend: true,
|
blend: src_has_alpha,
|
||||||
src_has_alpha: true,
|
src_has_alpha,
|
||||||
has_alpha_mult: false,
|
has_alpha_mult: false,
|
||||||
with_linear_output,
|
with_linear_output,
|
||||||
frag_descriptor_set_layout: None,
|
frag_descriptor_set_layout: None,
|
||||||
})?;
|
})
|
||||||
|
};
|
||||||
|
let fill_opaque = create_fill_pipeline(false)?;
|
||||||
|
let fill_alpha = create_fill_pipeline(true)?;
|
||||||
let create_tex_pipeline = |src_has_alpha, has_alpha_mult| {
|
let create_tex_pipeline = |src_has_alpha, has_alpha_mult| {
|
||||||
self.device
|
self.device
|
||||||
.create_pipeline::<TexPushConstants>(PipelineCreateInfo {
|
.create_pipeline::<TexPushConstants>(PipelineCreateInfo {
|
||||||
|
|
@ -326,7 +331,10 @@ impl VulkanRenderer {
|
||||||
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 format_pipelines = Rc::new(VulkanFormatPipelines {
|
let format_pipelines = Rc::new(VulkanFormatPipelines {
|
||||||
fill,
|
fill: static_map! {
|
||||||
|
TexSourceType::HasAlpha => fill_alpha.clone(),
|
||||||
|
TexSourceType::Opaque => fill_opaque.clone(),
|
||||||
|
},
|
||||||
tex: static_map! {
|
tex: static_map! {
|
||||||
TexCopyType::Identity => static_map! {
|
TexCopyType::Identity => static_map! {
|
||||||
TexSourceType::HasAlpha => tex_alpha.clone(),
|
TexSourceType::HasAlpha => tex_alpha.clone(),
|
||||||
|
|
@ -452,31 +460,11 @@ impl VulkanRenderer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn initial_barriers(
|
fn initial_barriers(&self, buf: CommandBuffer, fb: &VulkanImage) -> Result<(), VulkanError> {
|
||||||
&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()
|
||||||
|
|
@ -569,62 +557,58 @@ impl VulkanRenderer {
|
||||||
fn begin_rendering(
|
fn begin_rendering(
|
||||||
&self,
|
&self,
|
||||||
buf: CommandBuffer,
|
buf: CommandBuffer,
|
||||||
fb: &VulkanImage,
|
target: &VulkanImage,
|
||||||
clear: Option<&Color>,
|
clear: Option<&Color>,
|
||||||
bb: Option<&VulkanImage>,
|
pass: RenderPass,
|
||||||
) {
|
) {
|
||||||
zone!("begin_rendering");
|
zone!("begin_rendering");
|
||||||
let memory = &mut *self.memory.borrow_mut();
|
let memory = &mut *self.memory.borrow_mut();
|
||||||
let mut load_clear = None;
|
let mut load_clear = None;
|
||||||
let mut manual_clear = None;
|
let mut manual_clear = None;
|
||||||
memory.is_full_clear = false;
|
let clear_rects = &memory.clear_rects[pass];
|
||||||
if let Some(clear) = clear {
|
if let Some(clear) = clear {
|
||||||
let clear_value = ClearValue {
|
if clear_rects.is_not_empty() {
|
||||||
color: ClearColorValue {
|
let clear_value = ClearValue {
|
||||||
float32: if bb.is_some() {
|
color: ClearColorValue {
|
||||||
clear.to_array_linear(None)
|
float32: match pass {
|
||||||
} else {
|
RenderPass::BlendBuffer => clear.to_array_linear(None),
|
||||||
clear.to_array_srgb(None)
|
RenderPass::FrameBuffer => clear.to_array_srgb(None),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
};
|
||||||
};
|
let use_load_clear = clear_rects.len() == 1 && {
|
||||||
let use_load_clear = memory.paint_regions.len() == 1 && {
|
let rect = &clear_rects[0].rect;
|
||||||
let rect = &memory.paint_regions[0].rect;
|
rect.offset.x == 0
|
||||||
rect.offset.x == 0
|
&& rect.offset.y == 0
|
||||||
&& rect.offset.y == 0
|
&& rect.extent.width == target.width
|
||||||
&& rect.extent.width == fb.width
|
&& rect.extent.height == target.height
|
||||||
&& rect.extent.height == fb.height
|
};
|
||||||
};
|
if use_load_clear {
|
||||||
if use_load_clear {
|
load_clear = Some(clear_value);
|
||||||
load_clear = Some(clear_value);
|
} else {
|
||||||
} else {
|
manual_clear = Some(clear_value);
|
||||||
manual_clear = Some(clear_value);
|
}
|
||||||
}
|
}
|
||||||
memory.is_full_clear = use_load_clear;
|
|
||||||
}
|
}
|
||||||
let mut rendering_attachment_info = RenderingAttachmentInfo::default()
|
let mut rendering_attachment_info = RenderingAttachmentInfo::default()
|
||||||
.image_layout(ImageLayout::COLOR_ATTACHMENT_OPTIMAL)
|
.image_layout(ImageLayout::COLOR_ATTACHMENT_OPTIMAL)
|
||||||
|
.image_view(target.render_view.unwrap_or(target.texture_view))
|
||||||
.store_op(AttachmentStoreOp::STORE);
|
.store_op(AttachmentStoreOp::STORE);
|
||||||
rendering_attachment_info = if let Some(bb) = bb {
|
let load_op = if let Some(clear) = load_clear {
|
||||||
rendering_attachment_info
|
rendering_attachment_info = rendering_attachment_info.clear_value(clear);
|
||||||
.image_view(bb.render_view.unwrap_or(bb.texture_view))
|
AttachmentLoadOp::CLEAR
|
||||||
.load_op(AttachmentLoadOp::DONT_CARE)
|
} else if pass == RenderPass::BlendBuffer {
|
||||||
|
AttachmentLoadOp::DONT_CARE
|
||||||
} else {
|
} else {
|
||||||
rendering_attachment_info
|
AttachmentLoadOp::LOAD
|
||||||
.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.load_op(load_op);
|
||||||
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(),
|
||||||
extent: Extent2D {
|
extent: Extent2D {
|
||||||
width: fb.width,
|
width: target.width,
|
||||||
height: fb.height,
|
height: target.height,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.layer_count(1)
|
.layer_count(1)
|
||||||
|
|
@ -632,26 +616,16 @@ impl VulkanRenderer {
|
||||||
unsafe {
|
unsafe {
|
||||||
self.device.device.cmd_begin_rendering(buf, &rendering_info);
|
self.device.device.cmd_begin_rendering(buf, &rendering_info);
|
||||||
}
|
}
|
||||||
if memory.paint_regions.is_not_empty() {
|
if clear_rects.is_not_empty() {
|
||||||
if let Some(clear) = manual_clear {
|
if let Some(clear) = manual_clear {
|
||||||
let clear_attachment = ClearAttachment::default()
|
let clear_attachment = ClearAttachment::default()
|
||||||
.color_attachment(0)
|
.color_attachment(0)
|
||||||
.clear_value(clear)
|
.clear_value(clear)
|
||||||
.aspect_mask(ImageAspectFlags::COLOR);
|
.aspect_mask(ImageAspectFlags::COLOR);
|
||||||
memory.clear_rects.clear();
|
|
||||||
for region in &memory.paint_regions {
|
|
||||||
memory.clear_rects.push(ClearRect {
|
|
||||||
rect: region.rect,
|
|
||||||
base_array_layer: 0,
|
|
||||||
layer_count: 1,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
unsafe {
|
unsafe {
|
||||||
self.device.device.cmd_clear_attachments(
|
self.device
|
||||||
buf,
|
.device
|
||||||
&[clear_attachment],
|
.cmd_clear_attachments(buf, &[clear_attachment], clear_rects);
|
||||||
&memory.clear_rects,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -687,17 +661,14 @@ impl VulkanRenderer {
|
||||||
fn record_draws(
|
fn record_draws(
|
||||||
&self,
|
&self,
|
||||||
buf: CommandBuffer,
|
buf: CommandBuffer,
|
||||||
fb: &VulkanImage,
|
target: &VulkanImage,
|
||||||
opts: &[GfxApiOpt],
|
opts: &[GfxApiOpt],
|
||||||
bb: Option<&VulkanImage>,
|
pass: RenderPass,
|
||||||
) -> Result<(), VulkanError> {
|
) -> Result<(), VulkanError> {
|
||||||
zone!("record_draws");
|
zone!("record_draws");
|
||||||
let memory = &*self.memory.borrow();
|
let memory = &*self.memory.borrow();
|
||||||
let format = match bb.is_some() {
|
let paint_regions = &memory.paint_regions[pass];
|
||||||
false => fb.format.vk_format,
|
let pipelines = self.get_or_create_pipelines(target.format.vk_format, pass)?;
|
||||||
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| {
|
||||||
|
|
@ -714,23 +685,27 @@ 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: if bb.is_some() {
|
color: match pass {
|
||||||
r.color.to_array_linear(r.alpha)
|
RenderPass::BlendBuffer => r.color.to_array_linear(r.alpha),
|
||||||
} else {
|
RenderPass::FrameBuffer => r.color.to_array_srgb(r.alpha),
|
||||||
r.color.to_array_srgb(r.alpha)
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
for region in &memory.paint_regions {
|
let source_type = match push.color[3] < 1.0 {
|
||||||
|
true => TexSourceType::HasAlpha,
|
||||||
|
false => TexSourceType::Opaque,
|
||||||
|
};
|
||||||
|
let pipeline = &pipelines.fill[source_type];
|
||||||
|
for region in paint_regions {
|
||||||
let mut push = push;
|
let mut push = push;
|
||||||
let draw = region.constrain(&mut push.pos, None);
|
let draw = region.constrain(&mut push.pos, None);
|
||||||
if !draw {
|
if !draw {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
bind(&pipelines.fill);
|
bind(pipeline);
|
||||||
unsafe {
|
unsafe {
|
||||||
dev.cmd_push_constants(
|
dev.cmd_push_constants(
|
||||||
buf,
|
buf,
|
||||||
pipelines.fill.pipeline_layout,
|
pipeline.pipeline_layout,
|
||||||
ShaderStageFlags::VERTEX | ShaderStageFlags::FRAGMENT,
|
ShaderStageFlags::VERTEX | ShaderStageFlags::FRAGMENT,
|
||||||
0,
|
0,
|
||||||
uapi::as_bytes(&push),
|
uapi::as_bytes(&push),
|
||||||
|
|
@ -754,7 +729,7 @@ impl VulkanRenderer {
|
||||||
true => TexCopyType::Multiply,
|
true => TexCopyType::Multiply,
|
||||||
false => TexCopyType::Identity,
|
false => TexCopyType::Identity,
|
||||||
};
|
};
|
||||||
let source_type = match tex.format.has_alpha {
|
let source_type = match tex.format.has_alpha && !c.opaque {
|
||||||
true => TexSourceType::HasAlpha,
|
true => TexSourceType::HasAlpha,
|
||||||
false => TexSourceType::Opaque,
|
false => TexSourceType::Opaque,
|
||||||
};
|
};
|
||||||
|
|
@ -768,7 +743,7 @@ impl VulkanRenderer {
|
||||||
.image_view(tex.texture_view)
|
.image_view(tex.texture_view)
|
||||||
.image_layout(ImageLayout::SHADER_READ_ONLY_OPTIMAL);
|
.image_layout(ImageLayout::SHADER_READ_ONLY_OPTIMAL);
|
||||||
let init = Once::default();
|
let init = Once::default();
|
||||||
for region in &memory.paint_regions {
|
for region in paint_regions {
|
||||||
let mut push = push;
|
let mut push = push;
|
||||||
let draw = region.constrain(&mut push.pos, Some(&mut push.tex_pos));
|
let draw = region.constrain(&mut push.pos, Some(&mut push.tex_pos));
|
||||||
if !draw {
|
if !draw {
|
||||||
|
|
@ -815,18 +790,37 @@ impl VulkanRenderer {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn copy_blend_buffer(
|
fn blend_buffer_initial_barrier(&self, buf: CommandBuffer, bb: &VulkanImage) {
|
||||||
|
zone!("blend_buffer_initial_barrier");
|
||||||
|
let memory = &mut *self.memory.borrow_mut();
|
||||||
|
memory.image_barriers.clear();
|
||||||
|
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 dep_info = DependencyInfoKHR::default().image_memory_barriers(&memory.image_barriers);
|
||||||
|
unsafe {
|
||||||
|
self.device.device.cmd_pipeline_barrier2(buf, &dep_info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn blend_buffer_copy(
|
||||||
&self,
|
&self,
|
||||||
buf: CommandBuffer,
|
buf: CommandBuffer,
|
||||||
fb: &VulkanImage,
|
fb: &VulkanImage,
|
||||||
bb: Option<&VulkanImage>,
|
bb: &VulkanImage,
|
||||||
) -> Result<(), VulkanError> {
|
) -> Result<(), VulkanError> {
|
||||||
let Some(bb) = bb else {
|
zone!("blend_buffer_copy");
|
||||||
return Ok(());
|
|
||||||
};
|
|
||||||
zone!("copy_blend_buffer");
|
|
||||||
let memory = &*self.memory.borrow();
|
let memory = &*self.memory.borrow();
|
||||||
let dev = &self.device.device;
|
|
||||||
let db = self.device.descriptor_buffer.as_ref().unwrap();
|
let db = self.device.descriptor_buffer.as_ref().unwrap();
|
||||||
let pipeline = match self.out_pipelines.borrow_mut().entry(fb.format.vk_format) {
|
let pipeline = match self.out_pipelines.borrow_mut().entry(fb.format.vk_format) {
|
||||||
Entry::Occupied(pipeline) => pipeline.get().clone(),
|
Entry::Occupied(pipeline) => pipeline.get().clone(),
|
||||||
|
|
@ -848,6 +842,43 @@ impl VulkanRenderer {
|
||||||
out
|
out
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
let dev = &self.device.device;
|
||||||
|
unsafe {
|
||||||
|
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[RenderPass::BlendBuffer] {
|
||||||
|
let push = OutPushConstants {
|
||||||
|
pos: [
|
||||||
|
[region.x2, region.y1],
|
||||||
|
[region.x1, region.y1],
|
||||||
|
[region.x2, region.y2],
|
||||||
|
[region.x1, region.y2],
|
||||||
|
],
|
||||||
|
};
|
||||||
|
unsafe {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn blend_buffer_final_barrier(&self, buf: CommandBuffer, bb: &VulkanImage) {
|
||||||
|
zone!("blend_buffer_final_barrier");
|
||||||
let image_barrier = image_barrier()
|
let image_barrier = image_barrier()
|
||||||
.image(bb.image)
|
.image(bb.image)
|
||||||
.old_layout(ImageLayout::COLOR_ATTACHMENT_OPTIMAL)
|
.old_layout(ImageLayout::COLOR_ATTACHMENT_OPTIMAL)
|
||||||
|
|
@ -858,58 +889,11 @@ impl VulkanRenderer {
|
||||||
.dst_stage_mask(PipelineStageFlags2::FRAGMENT_SHADER);
|
.dst_stage_mask(PipelineStageFlags2::FRAGMENT_SHADER);
|
||||||
let dependency_info =
|
let dependency_info =
|
||||||
DependencyInfoKHR::default().image_memory_barriers(slice::from_ref(&image_barrier));
|
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 {
|
unsafe {
|
||||||
dev.cmd_pipeline_barrier2(buf, &dependency_info);
|
self.device
|
||||||
dev.cmd_begin_rendering(buf, &rendering_info);
|
.device
|
||||||
dev.cmd_bind_pipeline(buf, PipelineBindPoint::GRAPHICS, pipeline.pipeline);
|
.cmd_pipeline_barrier2(buf, &dependency_info);
|
||||||
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) {
|
||||||
|
|
@ -919,7 +903,7 @@ impl VulkanRenderer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn copy_bridge_to_dmabuf(&self, buf: CommandBuffer, fb: &VulkanImage) {
|
fn copy_bridge_to_dmabuf(&self, buf: CommandBuffer, fb: &VulkanImage, region: &Region) {
|
||||||
zone!("copy_bridge_to_dmabuf");
|
zone!("copy_bridge_to_dmabuf");
|
||||||
let Some(bridge) = &fb.bridge else {
|
let Some(bridge) = &fb.bridge else {
|
||||||
return;
|
return;
|
||||||
|
|
@ -961,15 +945,14 @@ impl VulkanRenderer {
|
||||||
.base_array_layer(0)
|
.base_array_layer(0)
|
||||||
.mip_level(0);
|
.mip_level(0);
|
||||||
memory.image_copy_regions.clear();
|
memory.image_copy_regions.clear();
|
||||||
for region in &memory.paint_regions {
|
for rect in region.rects() {
|
||||||
let offset = Offset3D {
|
let Some([x1, y1, x2, y2]) = constrain_to_fb(fb, rect) else {
|
||||||
x: region.rect.offset.x,
|
continue;
|
||||||
y: region.rect.offset.y,
|
|
||||||
z: 0,
|
|
||||||
};
|
};
|
||||||
|
let offset = Offset3D { x: x1, y: y1, z: 0 };
|
||||||
let extent = Extent3D {
|
let extent = Extent3D {
|
||||||
width: region.rect.extent.width,
|
width: (x2 - x1) as _,
|
||||||
height: region.rect.extent.height,
|
height: (y2 - y1) as _,
|
||||||
depth: 1,
|
depth: 1,
|
||||||
};
|
};
|
||||||
memory.image_copy_regions.push(
|
memory.image_copy_regions.push(
|
||||||
|
|
@ -981,14 +964,16 @@ impl VulkanRenderer {
|
||||||
.extent(extent),
|
.extent(extent),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
let copy_image_info = CopyImageInfo2::default()
|
if memory.image_copy_regions.is_not_empty() {
|
||||||
.src_image(fb.image)
|
let copy_image_info = CopyImageInfo2::default()
|
||||||
.src_image_layout(ImageLayout::TRANSFER_SRC_OPTIMAL)
|
.src_image(fb.image)
|
||||||
.dst_image(bridge.dmabuf_image)
|
.src_image_layout(ImageLayout::TRANSFER_SRC_OPTIMAL)
|
||||||
.dst_image_layout(ImageLayout::TRANSFER_DST_OPTIMAL)
|
.dst_image(bridge.dmabuf_image)
|
||||||
.regions(&memory.image_copy_regions);
|
.dst_image_layout(ImageLayout::TRANSFER_DST_OPTIMAL)
|
||||||
unsafe {
|
.regions(&memory.image_copy_regions);
|
||||||
self.device.device.cmd_copy_image2(buf, ©_image_info);
|
unsafe {
|
||||||
|
self.device.device.cmd_copy_image2(buf, ©_image_info);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1287,43 +1272,124 @@ impl VulkanRenderer {
|
||||||
Ok(semaphore)
|
Ok(semaphore)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_paint_regions(&self, fb: &VulkanImage, region: &Region) {
|
fn create_regions(
|
||||||
let mut region = region;
|
&self,
|
||||||
let region_owned;
|
fb: &VulkanImage,
|
||||||
if fb.contents_are_undefined.get() {
|
opts: &[GfxApiOpt],
|
||||||
region_owned = fb.full_region();
|
clear: Option<&Color>,
|
||||||
region = ®ion_owned;
|
region: &Region,
|
||||||
}
|
bb: Option<&VulkanImage>,
|
||||||
|
) {
|
||||||
|
zone!("create_paint_regions");
|
||||||
let memory = &mut *self.memory.borrow_mut();
|
let memory = &mut *self.memory.borrow_mut();
|
||||||
memory.paint_regions.clear();
|
memory.regions_1.clear();
|
||||||
for rect in region.rects() {
|
memory.regions_2.clear();
|
||||||
let x1 = rect.x1().max(0);
|
let width = fb.width as f32;
|
||||||
let y1 = rect.y1().max(0);
|
let height = fb.height as f32;
|
||||||
let x2 = rect.x2();
|
let mut tag = 0;
|
||||||
let y2 = rect.y2();
|
for opt in opts.iter().rev() {
|
||||||
if x1 as u32 > fb.width || y1 as u32 > fb.height || x2 <= 0 || y2 <= 0 {
|
let (opaque, fb_rect) = match opt {
|
||||||
continue;
|
GfxApiOpt::Sync => continue,
|
||||||
|
GfxApiOpt::FillRect(f) => (f.effective_color().a >= 1.0, f.rect),
|
||||||
|
GfxApiOpt::CopyTexture(c) => {
|
||||||
|
let opaque = 'opaque: {
|
||||||
|
if let Some(a) = c.alpha {
|
||||||
|
if a < 1.0 {
|
||||||
|
break 'opaque false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !c.opaque {
|
||||||
|
let tex = c.tex.as_vk(&self.device.device);
|
||||||
|
if tex.format.has_alpha {
|
||||||
|
break 'opaque false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
true
|
||||||
|
};
|
||||||
|
(opaque, c.target)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if opaque || bb.is_none() {
|
||||||
|
tag |= 1;
|
||||||
|
} else {
|
||||||
|
tag += tag & 1;
|
||||||
}
|
}
|
||||||
let x2 = x2.min(fb.width as i32);
|
let rect = fb_rect.to_rect(width, height);
|
||||||
let y2 = y2.min(fb.height as i32);
|
if opaque && clear.is_some() {
|
||||||
let to_fb = |c: i32, max: u32| 2.0 * (c as f32 / max as f32) - 1.0;
|
memory.regions_1.push(rect);
|
||||||
memory.paint_regions.push(PaintRegion {
|
}
|
||||||
rect: Rect2D {
|
memory.regions_2.push(rect.with_tag(tag));
|
||||||
offset: Offset2D {
|
}
|
||||||
x: x1 as _,
|
let clear_region = if clear.is_some() {
|
||||||
y: y1 as _,
|
let opaque_region = Region::from_rects2(&memory.regions_1);
|
||||||
},
|
region.subtract_cow(&opaque_region)
|
||||||
extent: Extent2D {
|
} else {
|
||||||
width: (x2 - x1) as u32,
|
Cow::Owned(Region::default())
|
||||||
height: (y2 - y1) as u32,
|
};
|
||||||
},
|
let tagged_region = Region::from_rects_tagged(&memory.regions_2).intersect_tagged(region);
|
||||||
},
|
memory.regions_1.clear();
|
||||||
|
memory.paint_regions[RenderPass::BlendBuffer].clear();
|
||||||
|
memory.paint_regions[RenderPass::FrameBuffer].clear();
|
||||||
|
let to_fb = |c: i32, max: u32| 2.0 * (c as f32 / max as f32) - 1.0;
|
||||||
|
for rect in tagged_region.rects() {
|
||||||
|
if rect.tag() == 0 && clear.is_some() {
|
||||||
|
memory.regions_1.push(rect.untag());
|
||||||
|
}
|
||||||
|
let Some([x1, y1, x2, y2]) = constrain_to_fb(fb, rect) else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
let region = match rect.tag() {
|
||||||
|
0 => &mut memory.paint_regions[RenderPass::BlendBuffer],
|
||||||
|
_ => &mut memory.paint_regions[RenderPass::FrameBuffer],
|
||||||
|
};
|
||||||
|
region.push(PaintRegion {
|
||||||
x1: to_fb(x1, fb.width),
|
x1: to_fb(x1, fb.width),
|
||||||
x2: to_fb(x2, fb.width),
|
x2: to_fb(x2, fb.width),
|
||||||
y1: to_fb(y1, fb.height),
|
y1: to_fb(y1, fb.height),
|
||||||
y2: to_fb(y2, fb.height),
|
y2: to_fb(y2, fb.height),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
let blend_clear = clear_region.intersect(&Region::from_rects2(&memory.regions_1));
|
||||||
|
let opaque_clear = clear_region.subtract_cow(&blend_clear);
|
||||||
|
// if bb.is_none() {
|
||||||
|
// log::info!("blend_clear = {:?}", blend_clear);
|
||||||
|
// log::info!("opaque_clear = {:?}", opaque_clear);
|
||||||
|
// }
|
||||||
|
for (pass, clear_region) in [
|
||||||
|
(RenderPass::BlendBuffer, &blend_clear),
|
||||||
|
(RenderPass::FrameBuffer, &opaque_clear),
|
||||||
|
] {
|
||||||
|
memory.clear_rects[pass].clear();
|
||||||
|
for rect in clear_region.rects() {
|
||||||
|
let Some([x1, y1, x2, y2]) = constrain_to_fb(fb, rect) else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
memory.clear_rects[pass].push(ClearRect {
|
||||||
|
rect: Rect2D {
|
||||||
|
offset: Offset2D {
|
||||||
|
x: x1 as _,
|
||||||
|
y: y1 as _,
|
||||||
|
},
|
||||||
|
extent: Extent2D {
|
||||||
|
width: (x2 - x1) as u32,
|
||||||
|
height: (y2 - y1) as u32,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
base_array_layer: 0,
|
||||||
|
layer_count: 1,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn elide_blend_buffer(&self, blend_buffer: &mut Option<Rc<VulkanImage>>) {
|
||||||
|
if blend_buffer.is_none() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let memory = &*self.memory.borrow();
|
||||||
|
if memory.paint_regions[RenderPass::BlendBuffer].is_empty() {
|
||||||
|
*blend_buffer = None;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn try_execute(
|
fn try_execute(
|
||||||
|
|
@ -1334,22 +1400,36 @@ impl VulkanRenderer {
|
||||||
opts: &[GfxApiOpt],
|
opts: &[GfxApiOpt],
|
||||||
clear: Option<&Color>,
|
clear: Option<&Color>,
|
||||||
region: &Region,
|
region: &Region,
|
||||||
blend_buffer: Option<Rc<VulkanImage>>,
|
mut 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_regions(fb, opts, clear, region, blend_buffer.as_deref());
|
||||||
|
self.elide_blend_buffer(&mut blend_buffer);
|
||||||
|
let bb = blend_buffer.as_deref();
|
||||||
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, bb)?;
|
self.create_descriptor_buffers(buf.buffer, opts, bb)?;
|
||||||
self.initial_barriers(buf.buffer, fb, bb)?;
|
self.initial_barriers(buf.buffer, fb)?;
|
||||||
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, bb)?;
|
if let Some(bb) = bb {
|
||||||
self.end_rendering(buf.buffer);
|
zone!("blend buffer pass");
|
||||||
self.copy_blend_buffer(buf.buffer, fb, bb)?;
|
self.blend_buffer_initial_barrier(buf.buffer, bb);
|
||||||
self.copy_bridge_to_dmabuf(buf.buffer, fb);
|
self.begin_rendering(buf.buffer, bb, clear, RenderPass::BlendBuffer);
|
||||||
|
self.record_draws(buf.buffer, bb, opts, RenderPass::BlendBuffer)?;
|
||||||
|
self.end_rendering(buf.buffer);
|
||||||
|
self.blend_buffer_final_barrier(buf.buffer, bb);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
zone!("frame buffer pass");
|
||||||
|
self.begin_rendering(buf.buffer, fb, clear, RenderPass::FrameBuffer);
|
||||||
|
self.record_draws(buf.buffer, fb, opts, RenderPass::FrameBuffer)?;
|
||||||
|
if let Some(bb) = bb {
|
||||||
|
self.blend_buffer_copy(buf.buffer, fb, bb)?;
|
||||||
|
}
|
||||||
|
self.end_rendering(buf.buffer);
|
||||||
|
}
|
||||||
|
self.copy_bridge_to_dmabuf(buf.buffer, fb, region);
|
||||||
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)?;
|
||||||
|
|
@ -1524,3 +1604,19 @@ impl PaintRegion {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn constrain_to_fb<T>(fb: &VulkanImage, rect: &Rect<T>) -> Option<[i32; 4]>
|
||||||
|
where
|
||||||
|
T: Tag,
|
||||||
|
{
|
||||||
|
let x1 = rect.x1().max(0);
|
||||||
|
let y1 = rect.y1().max(0);
|
||||||
|
let x2 = rect.x2();
|
||||||
|
let y2 = rect.y2();
|
||||||
|
if x1 as u32 > fb.width || y1 as u32 > fb.height || x2 <= 0 || y2 <= 0 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let x2 = x2.min(fb.width as i32);
|
||||||
|
let y2 = y2.min(fb.height as i32);
|
||||||
|
Some([x1, y1, x2, y2])
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -163,7 +163,6 @@ impl Rect {
|
||||||
Self::new_sized(self.raw.x1, self.raw.y1, width, height)
|
Self::new_sized(self.raw.x1, self.raw.y1, width, height)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[expect(dead_code)]
|
|
||||||
pub fn with_tag(&self, tag: u32) -> Rect<u32> {
|
pub fn with_tag(&self, tag: u32) -> Rect<u32> {
|
||||||
Rect {
|
Rect {
|
||||||
raw: RectRaw {
|
raw: RectRaw {
|
||||||
|
|
@ -337,7 +336,6 @@ where
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[expect(dead_code)]
|
|
||||||
pub fn tag(&self) -> T {
|
pub fn tag(&self) -> T {
|
||||||
self.raw.tag
|
self.raw.tag
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ use {
|
||||||
},
|
},
|
||||||
smallvec::SmallVec,
|
smallvec::SmallVec,
|
||||||
std::{
|
std::{
|
||||||
|
borrow::Cow,
|
||||||
cell::UnsafeCell,
|
cell::UnsafeCell,
|
||||||
fmt::{Debug, Formatter},
|
fmt::{Debug, Formatter},
|
||||||
mem,
|
mem,
|
||||||
|
|
@ -86,7 +87,19 @@ impl Region {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(not(test), expect(dead_code))]
|
pub fn subtract_cow<'a>(&'a self, other: &Self) -> Cow<'a, Self> {
|
||||||
|
if self.extents.is_empty() || other.extents.is_empty() {
|
||||||
|
return Cow::Borrowed(self);
|
||||||
|
}
|
||||||
|
let rects = subtract(&self.rects, &other.rects);
|
||||||
|
Cow::Owned(Self {
|
||||||
|
extents: Rect {
|
||||||
|
raw: extents(&rects),
|
||||||
|
},
|
||||||
|
rects,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
pub fn intersect(&self, other: &Region) -> Self {
|
pub fn intersect(&self, other: &Region) -> Self {
|
||||||
if self.is_empty() || other.is_empty() {
|
if self.is_empty() || other.is_empty() {
|
||||||
return Self::default();
|
return Self::default();
|
||||||
|
|
@ -102,7 +115,6 @@ impl Region {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Region<u32> {
|
impl Region<u32> {
|
||||||
#[cfg_attr(not(test), expect(dead_code))]
|
|
||||||
pub fn from_rects_tagged(rects: &[Rect<u32>]) -> Self {
|
pub fn from_rects_tagged(rects: &[Rect<u32>]) -> Self {
|
||||||
if rects.is_empty() {
|
if rects.is_empty() {
|
||||||
return Self::default();
|
return Self::default();
|
||||||
|
|
@ -123,7 +135,6 @@ impl Region<u32> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(not(test), expect(dead_code))]
|
|
||||||
pub fn intersect_tagged(&self, other: &Region) -> Self {
|
pub fn intersect_tagged(&self, other: &Region) -> Self {
|
||||||
if self.is_empty() || other.is_empty() {
|
if self.is_empty() || other.is_empty() {
|
||||||
return Self::default();
|
return Self::default();
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue