mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
temp
This commit is contained in:
parent
c7a4b93c90
commit
205d798fae
@ -8,6 +8,7 @@ pub mod mesh;
|
||||
pub mod model;
|
||||
pub mod pipelines;
|
||||
pub mod renderer;
|
||||
mod screenshot;
|
||||
pub mod texture;
|
||||
|
||||
// Reexports
|
||||
|
129
voxygen/src/render/pipelines/blit.rs
Normal file
129
voxygen/src/render/pipelines/blit.rs
Normal file
@ -0,0 +1,129 @@
|
||||
use super::{
|
||||
super::{AaMode, Consts},
|
||||
GlobalsLayouts,
|
||||
};
|
||||
use bytemuck::{Pod, Zeroable};
|
||||
use vek::*;
|
||||
|
||||
pub struct BindGroup {
|
||||
pub(in super::super) bind_group: wgpu::BindGroup,
|
||||
}
|
||||
|
||||
pub struct BlitLayout {
|
||||
pub layout: wgpu::BindGroupLayout,
|
||||
}
|
||||
|
||||
impl BlitLayout {
|
||||
pub fn new(device: &wgpu::Device) -> Self {
|
||||
Self {
|
||||
layout: device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
|
||||
label: None,
|
||||
entries: &[
|
||||
// Color source
|
||||
wgpu::BindGroupLayoutEntry {
|
||||
binding: 0,
|
||||
visibility: wgpu::ShaderStage::FRAGMENT,
|
||||
ty: wgpu::BindingType::Texture {
|
||||
sample_type: wgpu::TextureSampleType::Float { filterable: true },
|
||||
view_dimension: wgpu::TextureViewDimension::D2,
|
||||
multisampled: false,
|
||||
},
|
||||
count: None,
|
||||
},
|
||||
wgpu::BindGroupLayoutEntry {
|
||||
binding: 1,
|
||||
visibility: wgpu::ShaderStage::FRAGMENT,
|
||||
ty: wgpu::BindingType::Sampler {
|
||||
filtering: true,
|
||||
comparison: false,
|
||||
},
|
||||
count: None,
|
||||
},
|
||||
],
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn bind(
|
||||
&self,
|
||||
device: &wgpu::Device,
|
||||
src_color: &wgpu::TextureView,
|
||||
sampler: &wgpu::Sampler,
|
||||
) -> BindGroup {
|
||||
let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
|
||||
label: None,
|
||||
layout: &self.layout,
|
||||
entries: &[
|
||||
wgpu::BindGroupEntry {
|
||||
binding: 0,
|
||||
resource: wgpu::BindingResource::TextureView(src_color),
|
||||
},
|
||||
wgpu::BindGroupEntry {
|
||||
binding: 1,
|
||||
resource: wgpu::BindingResource::Sampler(sampler),
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
BindGroup { bind_group }
|
||||
}
|
||||
}
|
||||
|
||||
pub struct BlitPipeline {
|
||||
pub pipeline: wgpu::RenderPipeline,
|
||||
}
|
||||
|
||||
impl BlitPipeline {
|
||||
pub fn new(
|
||||
device: &wgpu::Device,
|
||||
vs_module: &wgpu::ShaderModule,
|
||||
fs_module: &wgpu::ShaderModule,
|
||||
sc_desc: &wgpu::SwapChainDescriptor,
|
||||
layout: &BlitLayout,
|
||||
) -> Self {
|
||||
common::span!(_guard, "BlitPipeline::new");
|
||||
let render_pipeline_layout =
|
||||
device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
||||
label: Some("Blit pipeline layout"),
|
||||
push_constant_ranges: &[],
|
||||
bind_group_layouts: &[&layout.layout],
|
||||
});
|
||||
|
||||
let render_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
|
||||
label: Some("Blit pipeline"),
|
||||
layout: Some(&render_pipeline_layout),
|
||||
vertex: wgpu::VertexState {
|
||||
module: vs_module,
|
||||
entry_point: "main",
|
||||
buffers: &[],
|
||||
},
|
||||
primitive: wgpu::PrimitiveState {
|
||||
topology: wgpu::PrimitiveTopology::TriangleList,
|
||||
strip_index_format: None,
|
||||
front_face: wgpu::FrontFace::Ccw,
|
||||
cull_mode: wgpu::CullMode::None,
|
||||
polygon_mode: wgpu::PolygonMode::Fill,
|
||||
},
|
||||
depth_stencil: None,
|
||||
multisample: wgpu::MultisampleState {
|
||||
count: samples,
|
||||
mask: !0,
|
||||
alpha_to_coverage_enabled: false,
|
||||
},
|
||||
fragment: Some(wgpu::FragmentState {
|
||||
module: fs_module,
|
||||
entry_point: "main",
|
||||
targets: &[wgpu::ColorTargetState {
|
||||
format: sc_desc.format,
|
||||
alpha_blend: wgpu::BlendState::REPLACE,
|
||||
color_blend: wgpu::BlendState::REPLACE,
|
||||
write_mask: wgpu::ColorWrite::ALL,
|
||||
}],
|
||||
}),
|
||||
});
|
||||
|
||||
Self {
|
||||
pipeline: render_pipeline,
|
||||
}
|
||||
}
|
||||
}
|
@ -1,3 +1,4 @@
|
||||
pub mod blit;
|
||||
pub mod clouds;
|
||||
pub mod figure;
|
||||
pub mod fluid;
|
||||
|
@ -1038,7 +1038,7 @@ impl Renderer {
|
||||
Err(wgpu::SwapChainError::Timeout) => {
|
||||
// This will probably be resolved on the next frame
|
||||
// NOTE: we don't log this because it happens very frequently with
|
||||
// PresentMode::Fifo and unlimited FPS
|
||||
// PresentMode::Fifo and unlimited FPS on certain machines
|
||||
return Ok(None);
|
||||
},
|
||||
Err(err @ wgpu::SwapChainError::Outdated) => {
|
||||
|
@ -19,6 +19,8 @@ pub struct Drawer<'a> {
|
||||
pub renderer: &'a mut Renderer,
|
||||
tex: wgpu::SwapChainTexture,
|
||||
globals: &'a GlobalsBindGroup,
|
||||
// Texture to write in screenshot data if that was requested this frame
|
||||
taking_screenshot: Option<super::screenshot::TakingScreenshot>,
|
||||
}
|
||||
|
||||
impl<'a> Drawer<'a> {
|
||||
@ -141,7 +143,9 @@ impl<'a> Drawer<'a> {
|
||||
.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||||
label: Some("third pass (postprocess + ui)"),
|
||||
color_attachments: &[wgpu::RenderPassColorAttachmentDescriptor {
|
||||
attachment: &self.tex.view,
|
||||
// If a screenshot was requested render to that as an intermediate texture
|
||||
// instead
|
||||
attachment: self.taking_screenshot.map_or(&self.tex.view, |s| &s.tex),
|
||||
resolve_target: None,
|
||||
ops: wgpu::Operations {
|
||||
load: wgpu::LoadOp::Clear(wgpu::Color::TRANSPARENT),
|
||||
@ -295,6 +299,31 @@ impl<'a> Drawer<'a> {
|
||||
|
||||
impl<'a> Drop for Drawer<'a> {
|
||||
fn drop(&mut self) {
|
||||
// If taking a screenshot
|
||||
if let Some(screenshot) = self.taking_screenshot {
|
||||
// Image needs to be copied from the screenshot texture to the swapchain texture
|
||||
let mut render_pass =
|
||||
self.encoder
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||||
label: Some(&label),
|
||||
color_attachments: &[wgpu::RenderPassColorAttachmentDescriptor {
|
||||
attachment: &self.tex.view,
|
||||
resolve_target: None,
|
||||
ops: wgpu::Operations {
|
||||
load: wgpu::LoadOp::Clear(wgpu::Color::TRANSPARENT),
|
||||
store: true,
|
||||
},
|
||||
}],
|
||||
});
|
||||
self.render_pass.set_pipeline(&self.blit.pipeline);
|
||||
self.render_pass
|
||||
.set_bind_group(0, &screenshot.bind_group.bind_group, &[]);
|
||||
self.render_pass.draw(0..3, 0..1);
|
||||
drop(render_pass);
|
||||
// TODO: Send screenshot off to another thread here
|
||||
}
|
||||
// TODO: submitting things to the queue can let the gpu start on them sooner
|
||||
// maybe we should submit each render pass to the queue as they are produced?
|
||||
self.renderer
|
||||
|
124
voxygen/src/render/renderer/screenshot.rs
Normal file
124
voxygen/src/render/renderer/screenshot.rs
Normal file
@ -0,0 +1,124 @@
|
||||
use super::super::pipelines::blit;
|
||||
|
||||
pub type ScreenshotFn = Box<dyn FnMut(image::DynamicImage) + Send>;
|
||||
|
||||
pub struct ScreenshotDownloader {
|
||||
buffer: wgpu::Buffer,
|
||||
screenshot_fn: ScreenshotFn,
|
||||
}
|
||||
|
||||
pub struct TakeScreenshot {
|
||||
bind_group: blit::BindGroup,
|
||||
view: wgpu::TextureView,
|
||||
texture: wgpu::Texture,
|
||||
// /// Option so that we can pass ownership of the contents of this field around (and eventually to a new thread) without
|
||||
// /// taking ownership of this whole struct
|
||||
downloader: ScreenshotDownloader,
|
||||
// Dimensions used for copying from the screenshot texture to a buffer
|
||||
width: u32,
|
||||
height: u32,
|
||||
bytes_per_pixel: u8,
|
||||
}
|
||||
|
||||
//pub struct TakingScreenshot<'a> {
|
||||
// pub bind_group: &'a blit::BindGroup,
|
||||
// pub tex: &'a wgpu::TextureView,
|
||||
// downloader: Option<ScreenshotDownloader>
|
||||
//}
|
||||
|
||||
impl TakeScreenshot {
|
||||
pub fn new(
|
||||
device: &wgpu::Device,
|
||||
blit_layout: &blit::BlitLayout,
|
||||
sampler: &wgpu::Sampler,
|
||||
/// Used to determine the resolution and texture format
|
||||
sc_desc: &wgpu::SwapChainDescriptor,
|
||||
/// Function that is given the image after downloading it from the GPU
|
||||
/// This is executed in a background thread
|
||||
screenshot_fn: ScreenshotFn,
|
||||
) -> Self {
|
||||
let texture = device.create_texture(&wgpu::TextureDescriptor {
|
||||
label: Some("screenshot tex"),
|
||||
size: wgpu::Extent3d {
|
||||
width: sc_desc.width,
|
||||
height: sc_desc.height,
|
||||
depth: 1,
|
||||
},
|
||||
mip_level_count: 1,
|
||||
sample_count: 1,
|
||||
dimension: wgpu::TextureDimension::D2,
|
||||
format: sc_desc.format,
|
||||
usage: wgpu::TextureUsage::COPY_SRC
|
||||
| wgpu::TextureUsage::SAMPLED
|
||||
| wgpu::TextureUsage::RENDER_ATTACHEMENT,
|
||||
});
|
||||
|
||||
let view = texture.create_view(&wgpu::TextureViewDescriptor {
|
||||
label: Some("screenshot tex view"),
|
||||
format: Some(sc_desc.format),
|
||||
dimension: Some(wgpu::TextureViewDimension::D2),
|
||||
aspect: wgpu::TextureAspect::All,
|
||||
base_mip_level: 0,
|
||||
level_count: None,
|
||||
base_array_layer: 0,
|
||||
array_layer_count: None,
|
||||
});
|
||||
|
||||
let bind_group = blit_layout.bind(device, &taking_tex, sampler);
|
||||
|
||||
let bytes_per_pixel = sc_desc.format.describe().block_size;
|
||||
|
||||
let buffer = device.create_buffer(&wgpu::BufferDescriptor{
|
||||
label: Some("screenshot download buffer"),
|
||||
size: padded_bytes_per_row *
|
||||
}
|
||||
)
|
||||
let downloader = ScreenshotDownloader { screenshot_fn, buffer };
|
||||
|
||||
Self {
|
||||
bind_group,
|
||||
texture,
|
||||
view,
|
||||
downloader: Some(Downloader),
|
||||
|
||||
}
|
||||
|
||||
/// NOTE: spawns thread
|
||||
/// Call this after rendering to the screenshot texture
|
||||
pub fn download_and_handle(
|
||||
self,
|
||||
encoder: &mut wgpu::CommandEncoder,
|
||||
) {
|
||||
// Calculate padded bytes per row
|
||||
let align = wgpu::COPY_BYTES_PER_ROW_ALIGNMENT;
|
||||
let unpadded_bytes_per_row =
|
||||
// Copy image to a buffer
|
||||
encoder.copy_texture_to_buffer(
|
||||
wgpu::TextureCopyView {
|
||||
texture: &self.texture,
|
||||
mip_level: 0,
|
||||
orgin: wgpu::Origin3d::ZERO,
|
||||
},
|
||||
wgpu::BufferCopyView {
|
||||
buffer: &self.buffer,
|
||||
layout: wgpu::TextureDataLayout {
|
||||
offset: 0,
|
||||
bytes_per_row: padded_bytes_per_row(self.width, self.bytes_per_pixel),
|
||||
rows_per_image: 0,
|
||||
}
|
||||
},
|
||||
)
|
||||
// Send buffer to another thread for async mapping, downloading, and passing to the given
|
||||
// handler function (which probably saves it to the disk)
|
||||
std::thread::Builder::new().name("screenshot".into()).spawn(|| {
|
||||
|
||||
});
|
||||
.expect("Failed to spawn screenshot thread");
|
||||
}
|
||||
}
|
||||
|
||||
fn padded_bytes_per_row(width: u32, bytes_per_pixel: u8) -> u32 {
|
||||
let unpadded_bytes_per_row = width * bytes_per_pixel;
|
||||
let padding = (align - unpadded_bytes_per_row % align) % align;
|
||||
unpadded_bytes_per_row + padding
|
||||
}
|
Loading…
Reference in New Issue
Block a user