vulkan: store fill vertices in buffer
This commit is contained in:
parent
f84934bd9a
commit
10be846e4c
7 changed files with 160 additions and 54 deletions
|
|
@ -66,7 +66,11 @@ impl VulkanBufferCache {
|
|||
self.usage
|
||||
}
|
||||
|
||||
pub fn allocate(self: &Rc<Self>, capacity: DeviceSize) -> Result<VulkanBuffer, VulkanError> {
|
||||
pub fn allocate(
|
||||
self: &Rc<Self>,
|
||||
capacity: DeviceSize,
|
||||
align: DeviceSize,
|
||||
) -> Result<VulkanBuffer, VulkanError> {
|
||||
const MIN_ALLOCATION: DeviceSize = 1024;
|
||||
let capacity = capacity.max(MIN_ALLOCATION);
|
||||
let mut smallest = None;
|
||||
|
|
@ -109,8 +113,9 @@ impl VulkanBufferCache {
|
|||
}
|
||||
};
|
||||
let destroy_buffer = OnDrop(|| unsafe { self.device.device.destroy_buffer(buffer, None) });
|
||||
let memory_requirements =
|
||||
let mut memory_requirements =
|
||||
unsafe { self.device.device.get_buffer_memory_requirements(buffer) };
|
||||
memory_requirements.alignment = memory_requirements.alignment.max(align);
|
||||
let allocation = {
|
||||
let flags = UsageFlags::UPLOAD
|
||||
| UsageFlags::FAST_DEVICE_ACCESS
|
||||
|
|
|
|||
|
|
@ -49,13 +49,13 @@ impl VulkanDevice {
|
|||
&self,
|
||||
info: PipelineCreateInfo,
|
||||
) -> Result<Rc<VulkanPipeline>, VulkanError> {
|
||||
self.create_pipeline_(info, size_of::<P>() as _)
|
||||
self.create_pipeline2(info, size_of::<P>())
|
||||
}
|
||||
|
||||
fn create_pipeline_(
|
||||
pub(super) fn create_pipeline2(
|
||||
&self,
|
||||
info: PipelineCreateInfo,
|
||||
push_size: u32,
|
||||
push_size: usize,
|
||||
) -> Result<Rc<VulkanPipeline>, VulkanError> {
|
||||
let pipeline_layout = {
|
||||
let mut push_constant_ranges = ArrayVec::<_, 1>::new();
|
||||
|
|
@ -64,7 +64,7 @@ impl VulkanDevice {
|
|||
PushConstantRange::default()
|
||||
.stage_flags(ShaderStageFlags::VERTEX | ShaderStageFlags::FRAGMENT)
|
||||
.offset(0)
|
||||
.size(push_size),
|
||||
.size(push_size as u32),
|
||||
);
|
||||
}
|
||||
let mut descriptor_set_layouts = ArrayVec::<_, 1>::new();
|
||||
|
|
|
|||
|
|
@ -22,8 +22,8 @@ use {
|
|||
semaphore::VulkanSemaphore,
|
||||
shaders::{
|
||||
FILL_FRAG, FILL_VERT, FillPushConstants, LEGACY_FILL_FRAG, LEGACY_FILL_VERT,
|
||||
LEGACY_TEX_FRAG, LEGACY_TEX_VERT, OUT_FRAG, OUT_VERT, OutPushConstants, TEX_FRAG,
|
||||
TEX_VERT, TexPushConstants, VulkanShader,
|
||||
LEGACY_TEX_FRAG, LEGACY_TEX_VERT, LegacyFillPushConstants, OUT_FRAG, OUT_VERT,
|
||||
OutPushConstants, TEX_FRAG, TEX_VERT, TexPushConstants, VulkanShader,
|
||||
},
|
||||
transfer_functions::{TF_LINEAR, TF_SRGB},
|
||||
},
|
||||
|
|
@ -38,15 +38,16 @@ use {
|
|||
ash::{
|
||||
Device,
|
||||
vk::{
|
||||
self, AccessFlags2, AttachmentLoadOp, AttachmentStoreOp, ClearAttachment,
|
||||
ClearColorValue, ClearRect, ClearValue, CommandBuffer, CommandBufferBeginInfo,
|
||||
CommandBufferSubmitInfo, CommandBufferUsageFlags, CopyImageInfo2, DependencyInfoKHR,
|
||||
DescriptorBufferBindingInfoEXT, DescriptorImageInfo, DescriptorType, DeviceSize,
|
||||
Extent2D, Extent3D, ImageAspectFlags, ImageCopy2, ImageLayout, ImageMemoryBarrier2,
|
||||
ImageSubresourceLayers, ImageSubresourceRange, Offset2D, Offset3D, PipelineBindPoint,
|
||||
PipelineStageFlags2, QUEUE_FAMILY_FOREIGN_EXT, Rect2D, RenderingAttachmentInfo,
|
||||
RenderingInfo, SemaphoreSubmitInfo, SemaphoreSubmitInfoKHR, ShaderStageFlags,
|
||||
SubmitInfo2, Viewport, WriteDescriptorSet,
|
||||
self, AccessFlags2, AttachmentLoadOp, AttachmentStoreOp, BufferUsageFlags,
|
||||
ClearAttachment, ClearColorValue, ClearRect, ClearValue, CommandBuffer,
|
||||
CommandBufferBeginInfo, CommandBufferSubmitInfo, CommandBufferUsageFlags,
|
||||
CopyImageInfo2, DependencyInfoKHR, DescriptorBufferBindingInfoEXT, DescriptorImageInfo,
|
||||
DescriptorType, DeviceAddress, DeviceSize, Extent2D, Extent3D, ImageAspectFlags,
|
||||
ImageCopy2, ImageLayout, ImageMemoryBarrier2, ImageSubresourceLayers,
|
||||
ImageSubresourceRange, Offset2D, Offset3D, PipelineBindPoint, PipelineStageFlags2,
|
||||
QUEUE_FAMILY_FOREIGN_EXT, Rect2D, RenderingAttachmentInfo, RenderingInfo,
|
||||
SemaphoreSubmitInfo, SemaphoreSubmitInfoKHR, ShaderStageFlags, SubmitInfo2, Viewport,
|
||||
WriteDescriptorSet,
|
||||
},
|
||||
},
|
||||
isnt::std_1::{collections::IsntHashMapExt, primitive::IsntSliceExt},
|
||||
|
|
@ -97,6 +98,7 @@ pub struct VulkanRenderer {
|
|||
pub(super) sampler_descriptor_buffer_cache: Rc<VulkanBufferCache>,
|
||||
pub(super) resource_descriptor_buffer_cache: Rc<VulkanBufferCache>,
|
||||
pub(super) blend_buffers: RefCell<AHashMap<(u32, u32), Weak<VulkanImage>>>,
|
||||
pub(super) shader_buffer_cache: Rc<VulkanBufferCache>,
|
||||
}
|
||||
|
||||
pub(super) struct CachedCommandBuffers {
|
||||
|
|
@ -148,7 +150,7 @@ pub(super) struct Memory {
|
|||
wait_semaphore_infos: Vec<SemaphoreSubmitInfo<'static>>,
|
||||
release_fence: Option<Rc<VulkanFence>>,
|
||||
release_sync_file: Option<SyncFile>,
|
||||
descriptor_buffers: ArrayVec<VulkanBuffer, 2>,
|
||||
used_buffers: ArrayVec<VulkanBuffer, 3>,
|
||||
paint_bounds: StaticMap<RenderPass, Option<PaintRegion>>,
|
||||
paint_regions: StaticMap<RenderPass, Vec<PaintRegion>>,
|
||||
clear_rects: StaticMap<RenderPass, Vec<ClearRect>>,
|
||||
|
|
@ -161,6 +163,7 @@ pub(super) struct Memory {
|
|||
ops_tmp: StaticMap<RenderPass, Vec<VulkanOp>>,
|
||||
fill_targets: Vec<Point>,
|
||||
tex_targets: Vec<[Point; 2]>,
|
||||
data_buffer: Vec<u8>,
|
||||
}
|
||||
|
||||
type Point = [[f32; 2]; 4];
|
||||
|
|
@ -185,6 +188,8 @@ struct VulkanFillOp {
|
|||
range: Range<usize>,
|
||||
color: [f32; 4],
|
||||
source_type: TexSourceType,
|
||||
range_address: DeviceAddress,
|
||||
instances: u32,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Linearize, Eq, PartialEq)]
|
||||
|
|
@ -211,7 +216,7 @@ pub(super) struct PendingFrame {
|
|||
wait_semaphores: Cell<Vec<Rc<VulkanSemaphore>>>,
|
||||
waiter: Cell<Option<SpawnedFuture<()>>>,
|
||||
_release_fence: Option<Rc<VulkanFence>>,
|
||||
_descriptor_buffers: ArrayVec<VulkanBuffer, 2>,
|
||||
_used_buffers: ArrayVec<VulkanBuffer, 3>,
|
||||
}
|
||||
|
||||
pub(super) struct VulkanFormatPipelines {
|
||||
|
|
@ -291,6 +296,11 @@ impl VulkanDevice {
|
|||
VulkanBufferCache::for_descriptor_buffer(self, &allocator, true);
|
||||
let resource_descriptor_buffer_cache =
|
||||
VulkanBufferCache::for_descriptor_buffer(self, &allocator, false);
|
||||
let shader_buffer_cache = {
|
||||
// TODO: https://github.com/KhronosGroup/Vulkan-Samples/issues/1286
|
||||
let usage = BufferUsageFlags::SHADER_DEVICE_ADDRESS | BufferUsageFlags::STORAGE_BUFFER;
|
||||
VulkanBufferCache::new(self, &allocator, usage)
|
||||
};
|
||||
let render = Rc::new(VulkanRenderer {
|
||||
formats: Rc::new(formats),
|
||||
device: self.clone(),
|
||||
|
|
@ -322,6 +332,7 @@ impl VulkanDevice {
|
|||
sampler_descriptor_buffer_cache,
|
||||
resource_descriptor_buffer_cache,
|
||||
blend_buffers: Default::default(),
|
||||
shader_buffer_cache,
|
||||
});
|
||||
render.get_or_create_pipelines(XRGB8888.vk_format, RenderPass::FrameBuffer)?;
|
||||
Ok(render)
|
||||
|
|
@ -343,18 +354,23 @@ impl VulkanRenderer {
|
|||
return Ok(pl);
|
||||
}
|
||||
let create_fill_pipeline = |src_has_alpha| {
|
||||
self.device
|
||||
.create_pipeline::<FillPushConstants>(PipelineCreateInfo {
|
||||
format,
|
||||
vert: self.fill_vert_shader.clone(),
|
||||
frag: self.fill_frag_shader.clone(),
|
||||
blend: src_has_alpha,
|
||||
src_has_alpha,
|
||||
has_alpha_mult: false,
|
||||
eotf,
|
||||
oetf,
|
||||
frag_descriptor_set_layout: None,
|
||||
})
|
||||
let push_size = if self.device.descriptor_buffer.is_some() {
|
||||
size_of::<FillPushConstants>()
|
||||
} else {
|
||||
size_of::<LegacyFillPushConstants>()
|
||||
};
|
||||
let info = PipelineCreateInfo {
|
||||
format,
|
||||
vert: self.fill_vert_shader.clone(),
|
||||
frag: self.fill_frag_shader.clone(),
|
||||
blend: src_has_alpha,
|
||||
src_has_alpha,
|
||||
has_alpha_mult: false,
|
||||
eotf,
|
||||
oetf,
|
||||
frag_descriptor_set_layout: None,
|
||||
};
|
||||
self.device.create_pipeline2(info, push_size)
|
||||
};
|
||||
let fill_opaque = create_fill_pipeline(false)?;
|
||||
let fill_alpha = create_fill_pipeline(true)?;
|
||||
|
|
@ -411,7 +427,6 @@ impl VulkanRenderer {
|
|||
zone!("create_descriptor_buffers");
|
||||
let version = self.allocate_point();
|
||||
let memory = &mut *self.memory.borrow_mut();
|
||||
memory.descriptor_buffers.clear();
|
||||
let sampler_writer = &mut memory.sampler_descriptor_buffer_writer;
|
||||
sampler_writer.clear();
|
||||
let resource_writer = &mut memory.resource_descriptor_buffer_writer;
|
||||
|
|
@ -446,7 +461,7 @@ impl VulkanRenderer {
|
|||
(&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, 1)?;
|
||||
buffer.buffer.allocation.upload(|ptr, _| unsafe {
|
||||
ptr::copy_nonoverlapping(writer.as_ptr(), ptr, writer.len())
|
||||
})?;
|
||||
|
|
@ -454,7 +469,7 @@ impl VulkanRenderer {
|
|||
.usage(cache.usage())
|
||||
.address(buffer.buffer.address);
|
||||
infos.push(info);
|
||||
memory.descriptor_buffers.push(buffer);
|
||||
memory.used_buffers.push(buffer);
|
||||
}
|
||||
unsafe {
|
||||
db.cmd_bind_descriptor_buffers(buf, &infos);
|
||||
|
|
@ -473,6 +488,7 @@ impl VulkanRenderer {
|
|||
}
|
||||
memory.tex_targets.clear();
|
||||
memory.fill_targets.clear();
|
||||
memory.data_buffer.clear();
|
||||
let sync = |memory: &mut Memory| {
|
||||
for pass in RenderPass::variants() {
|
||||
let ops = &mut memory.ops_tmp[pass];
|
||||
|
|
@ -489,7 +505,32 @@ impl VulkanRenderer {
|
|||
VulkanOp::Tex(_) => Key::Tex,
|
||||
}
|
||||
});
|
||||
memory.ops[pass].append(ops);
|
||||
let mops = &mut memory.ops[pass];
|
||||
if self.device.descriptor_buffer.is_none() {
|
||||
mops.append(ops);
|
||||
continue;
|
||||
}
|
||||
for (idx, op) in ops.drain(..).enumerate() {
|
||||
match op {
|
||||
VulkanOp::Fill(mut f) => {
|
||||
f.range_address = memory.data_buffer.len() as DeviceAddress;
|
||||
f.instances = f.range.len() as u32;
|
||||
for pos in &memory.fill_targets[f.range.clone()] {
|
||||
memory.data_buffer.extend_from_slice(uapi::as_bytes(pos));
|
||||
}
|
||||
if let Some(VulkanOp::Fill(p)) = mops.last_mut() {
|
||||
if p.color == f.color && idx > 0 {
|
||||
p.instances += f.instances;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
mops.push(VulkanOp::Fill(f));
|
||||
}
|
||||
VulkanOp::Tex(_) => {
|
||||
mops.push(op);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
for op in opts {
|
||||
|
|
@ -532,6 +573,8 @@ impl VulkanRenderer {
|
|||
range: lo..hi,
|
||||
color,
|
||||
source_type,
|
||||
range_address: 0,
|
||||
instances: 0,
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
|
@ -594,6 +637,34 @@ impl VulkanRenderer {
|
|||
sync(memory);
|
||||
}
|
||||
|
||||
fn create_data_buffer(&self) -> Result<(), VulkanError> {
|
||||
if self.device.descriptor_buffer.is_none() {
|
||||
return Ok(());
|
||||
}
|
||||
zone!("create_data_buffer");
|
||||
let memory = &mut *self.memory.borrow_mut();
|
||||
let buf = &mut memory.data_buffer;
|
||||
if buf.is_empty() {
|
||||
return Ok(());
|
||||
}
|
||||
let buffer = self.shader_buffer_cache.allocate(buf.len() as _, 8)?;
|
||||
buffer.buffer.allocation.upload(|ptr, _| unsafe {
|
||||
ptr::copy_nonoverlapping(buf.as_ptr(), ptr, buf.len());
|
||||
})?;
|
||||
for ops in memory.ops.values_mut() {
|
||||
for op in ops {
|
||||
match op {
|
||||
VulkanOp::Fill(f) => {
|
||||
f.range_address += buffer.buffer.address;
|
||||
}
|
||||
VulkanOp::Tex(_) => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
memory.used_buffers.push(buffer);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn collect_memory(&self) {
|
||||
zone!("collect_memory");
|
||||
let memory = &mut *self.memory.borrow_mut();
|
||||
|
|
@ -860,10 +931,12 @@ impl VulkanRenderer {
|
|||
VulkanOp::Fill(r) => {
|
||||
let pipeline = &pipelines.fill[r.source_type];
|
||||
bind(pipeline);
|
||||
for &pos in &memory.fill_targets[r.range.clone()] {
|
||||
if self.device.descriptor_buffer.is_some() {
|
||||
let push = FillPushConstants {
|
||||
pos,
|
||||
color: r.color,
|
||||
vertices: r.range_address,
|
||||
_padding1: 0,
|
||||
_padding2: 0,
|
||||
};
|
||||
unsafe {
|
||||
dev.cmd_push_constants(
|
||||
|
|
@ -873,7 +946,24 @@ impl VulkanRenderer {
|
|||
0,
|
||||
uapi::as_bytes(&push),
|
||||
);
|
||||
dev.cmd_draw(buf, 4, 1, 0, 0);
|
||||
dev.cmd_draw(buf, 4, r.instances, 0, 0);
|
||||
}
|
||||
} else {
|
||||
for &pos in &memory.fill_targets[r.range.clone()] {
|
||||
let push = LegacyFillPushConstants {
|
||||
pos,
|
||||
color: r.color,
|
||||
};
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1358,7 +1448,7 @@ impl VulkanRenderer {
|
|||
wait_semaphores: Cell::new(mem::take(&mut memory.wait_semaphores)),
|
||||
waiter: Cell::new(None),
|
||||
_release_fence: memory.release_fence.take(),
|
||||
_descriptor_buffers: mem::take(&mut memory.descriptor_buffers),
|
||||
_used_buffers: mem::take(&mut memory.used_buffers),
|
||||
});
|
||||
self.pending_frames.set(frame.point, frame.clone());
|
||||
let future = self.eng.spawn(
|
||||
|
|
@ -1400,7 +1490,7 @@ impl VulkanRenderer {
|
|||
memory.queue_transfer.clear();
|
||||
memory.wait_semaphores.clear();
|
||||
memory.release_fence.take();
|
||||
memory.descriptor_buffers.clear();
|
||||
memory.used_buffers.clear();
|
||||
memory.release_sync_file.take()
|
||||
};
|
||||
res.map(|_| sync_file)
|
||||
|
|
@ -1563,6 +1653,7 @@ impl VulkanRenderer {
|
|||
let bb = blend_buffer.as_deref();
|
||||
let buf = self.gfx_command_buffers.allocate()?;
|
||||
self.convert_ops(opts);
|
||||
self.create_data_buffer()?;
|
||||
self.collect_memory();
|
||||
self.begin_command_buffer(buf.buffer)?;
|
||||
self.create_descriptor_buffers(buf.buffer, bb)?;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use {
|
||||
crate::gfx_apis::vulkan::{VulkanError, device::VulkanDevice},
|
||||
ash::vk::{ShaderModule, ShaderModuleCreateInfo},
|
||||
ash::vk::{DeviceAddress, ShaderModule, ShaderModuleCreateInfo},
|
||||
std::rc::Rc,
|
||||
uapi::Packed,
|
||||
};
|
||||
|
|
@ -26,11 +26,22 @@ pub struct VulkanShader {
|
|||
#[derive(Copy, Clone, Debug)]
|
||||
#[repr(C)]
|
||||
pub struct FillPushConstants {
|
||||
pub color: [f32; 4],
|
||||
pub vertices: DeviceAddress,
|
||||
pub _padding1: u32,
|
||||
pub _padding2: u32,
|
||||
}
|
||||
|
||||
unsafe impl Packed for FillPushConstants {}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[repr(C)]
|
||||
pub struct LegacyFillPushConstants {
|
||||
pub pos: [[f32; 2]; 4],
|
||||
pub color: [f32; 4],
|
||||
}
|
||||
|
||||
unsafe impl Packed for FillPushConstants {}
|
||||
unsafe impl Packed for LegacyFillPushConstants {}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[repr(C)]
|
||||
|
|
|
|||
|
|
@ -1,4 +1,12 @@
|
|||
#extension GL_EXT_buffer_reference : require
|
||||
|
||||
layout(buffer_reference, buffer_reference_align = 8, std430) buffer Vertices {
|
||||
vec2 pos[][4];
|
||||
};
|
||||
|
||||
layout(push_constant, std430) uniform Data {
|
||||
layout(offset = 0) vec2 pos[4];
|
||||
layout(offset = 32) vec4 color;
|
||||
vec4 color;
|
||||
Vertices vertices;
|
||||
uint padding1;
|
||||
uint padding2;
|
||||
} data;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
#version 450
|
||||
|
||||
#include "frag_spec_const.glsl"
|
||||
#include "fill.common.glsl"
|
||||
|
||||
layout(location = 0) out vec4 out_color;
|
||||
|
|
|
|||
|
|
@ -1,16 +1,8 @@
|
|||
#version 450
|
||||
//#extension GL_EXT_debug_printf : enable
|
||||
|
||||
#include "fill.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;
|
||||
}
|
||||
vec2 pos = data.vertices.pos[gl_InstanceIndex][gl_VertexIndex];
|
||||
gl_Position = vec4(pos, 0.0, 1.0);
|
||||
// debugPrintfEXT("gl_Position = %v4f", gl_Position);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue