feat(rendering): Vendor Bevy rendering crates (Phase 1 complete)
Closes #6, #7, #8, #9, #10 Refs #2, #122 Vendored bevy_render, bevy_core_pipeline, and bevy_pbr from Bevy v0.17.2 (commit 566358363126dd69f6e457e47f306c68f8041d2a) into libmarathon. - ~51K LOC vendored to crates/libmarathon/src/render/ - Merged bevy_render_macros into crates/macros/ - Fixed 773→0 compilation errors - Updated dependencies (encase 0.10→0.11, added 4 new deps) - Removed bevy_render/pbr/core_pipeline from app Cargo features All builds passing, macOS smoke test successful. Signed-off-by: Sienna Meridian Satterwhite <sienna@r3t.io>
This commit is contained in:
88
crates/libmarathon/src/render/upscaling/mod.rs
Normal file
88
crates/libmarathon/src/render/upscaling/mod.rs
Normal file
@@ -0,0 +1,88 @@
|
||||
use crate::render::blit::{BlitPipeline, BlitPipelineKey};
|
||||
use bevy_app::prelude::*;
|
||||
use bevy_camera::CameraOutputMode;
|
||||
use bevy_ecs::prelude::*;
|
||||
use bevy_platform::collections::HashSet;
|
||||
use crate::render::{
|
||||
camera::ExtractedCamera, render_resource::*, view::ViewTarget, Render, RenderApp, RenderSystems,
|
||||
};
|
||||
|
||||
mod node;
|
||||
|
||||
pub use node::UpscalingNode;
|
||||
|
||||
pub struct UpscalingPlugin;
|
||||
|
||||
impl Plugin for UpscalingPlugin {
|
||||
fn build(&self, app: &mut App) {
|
||||
if let Some(render_app) = app.get_sub_app_mut(RenderApp) {
|
||||
render_app.add_systems(
|
||||
Render,
|
||||
// This system should probably technically be run *after* all of the other systems
|
||||
// that might modify `PipelineCache` via interior mutability, but for now,
|
||||
// we've chosen to simply ignore the ambiguities out of a desire for a better refactor
|
||||
// and aversion to extensive and intrusive system ordering.
|
||||
// See https://github.com/bevyengine/bevy/issues/14770 for more context.
|
||||
prepare_view_upscaling_pipelines
|
||||
.in_set(RenderSystems::Prepare)
|
||||
.ambiguous_with_all(),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Component)]
|
||||
pub struct ViewUpscalingPipeline(CachedRenderPipelineId);
|
||||
|
||||
fn prepare_view_upscaling_pipelines(
|
||||
mut commands: Commands,
|
||||
mut pipeline_cache: ResMut<PipelineCache>,
|
||||
mut pipelines: ResMut<SpecializedRenderPipelines<BlitPipeline>>,
|
||||
blit_pipeline: Res<BlitPipeline>,
|
||||
view_targets: Query<(Entity, &ViewTarget, Option<&ExtractedCamera>)>,
|
||||
) {
|
||||
let mut output_textures = <HashSet<_>>::default();
|
||||
for (entity, view_target, camera) in view_targets.iter() {
|
||||
let out_texture_id = view_target.out_texture().id();
|
||||
let blend_state = if let Some(extracted_camera) = camera {
|
||||
match extracted_camera.output_mode {
|
||||
CameraOutputMode::Skip => None,
|
||||
CameraOutputMode::Write { blend_state, .. } => {
|
||||
let already_seen = output_textures.contains(&out_texture_id);
|
||||
output_textures.insert(out_texture_id);
|
||||
|
||||
match blend_state {
|
||||
None => {
|
||||
// If we've already seen this output for a camera and it doesn't have an output blend
|
||||
// mode configured, default to alpha blend so that we don't accidentally overwrite
|
||||
// the output texture
|
||||
if already_seen {
|
||||
Some(BlendState::ALPHA_BLENDING)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
_ => blend_state,
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
output_textures.insert(out_texture_id);
|
||||
None
|
||||
};
|
||||
|
||||
let key = BlitPipelineKey {
|
||||
texture_format: view_target.out_texture_format(),
|
||||
blend_state,
|
||||
samples: 1,
|
||||
};
|
||||
let pipeline = pipelines.specialize(&pipeline_cache, &blit_pipeline, key);
|
||||
|
||||
// Ensure the pipeline is loaded before continuing the frame to prevent frames without any GPU work submitted
|
||||
pipeline_cache.block_on_render_pipeline(pipeline);
|
||||
|
||||
commands
|
||||
.entity(entity)
|
||||
.insert(ViewUpscalingPipeline(pipeline));
|
||||
}
|
||||
}
|
||||
104
crates/libmarathon/src/render/upscaling/node.rs
Normal file
104
crates/libmarathon/src/render/upscaling/node.rs
Normal file
@@ -0,0 +1,104 @@
|
||||
use crate::render::{blit::BlitPipeline, upscaling::ViewUpscalingPipeline};
|
||||
use bevy_camera::{CameraOutputMode, ClearColor, ClearColorConfig};
|
||||
use bevy_ecs::{prelude::*, query::QueryItem};
|
||||
use crate::render::{
|
||||
camera::ExtractedCamera,
|
||||
diagnostic::RecordDiagnostics,
|
||||
render_graph::{NodeRunError, RenderGraphContext, ViewNode},
|
||||
render_resource::{BindGroup, PipelineCache, RenderPassDescriptor, TextureViewId},
|
||||
renderer::RenderContext,
|
||||
view::ViewTarget,
|
||||
};
|
||||
use std::sync::Mutex;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct UpscalingNode {
|
||||
cached_texture_bind_group: Mutex<Option<(TextureViewId, BindGroup)>>,
|
||||
}
|
||||
|
||||
impl ViewNode for UpscalingNode {
|
||||
type ViewQuery = (
|
||||
&'static ViewTarget,
|
||||
&'static ViewUpscalingPipeline,
|
||||
Option<&'static ExtractedCamera>,
|
||||
);
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
_graph: &mut RenderGraphContext,
|
||||
render_context: &mut RenderContext,
|
||||
(target, upscaling_target, camera): QueryItem<Self::ViewQuery>,
|
||||
world: &World,
|
||||
) -> Result<(), NodeRunError> {
|
||||
let pipeline_cache = world.resource::<PipelineCache>();
|
||||
let blit_pipeline = world.resource::<BlitPipeline>();
|
||||
let clear_color_global = world.resource::<ClearColor>();
|
||||
|
||||
let diagnostics = render_context.diagnostic_recorder();
|
||||
|
||||
let clear_color = if let Some(camera) = camera {
|
||||
match camera.output_mode {
|
||||
CameraOutputMode::Write { clear_color, .. } => clear_color,
|
||||
CameraOutputMode::Skip => return Ok(()),
|
||||
}
|
||||
} else {
|
||||
ClearColorConfig::Default
|
||||
};
|
||||
let clear_color = match clear_color {
|
||||
ClearColorConfig::Default => Some(clear_color_global.0),
|
||||
ClearColorConfig::Custom(color) => Some(color),
|
||||
ClearColorConfig::None => None,
|
||||
};
|
||||
let converted_clear_color = clear_color.map(Into::into);
|
||||
// texture to be upscaled to the output texture
|
||||
let main_texture_view = target.main_texture_view();
|
||||
|
||||
let mut cached_bind_group = self.cached_texture_bind_group.lock().unwrap();
|
||||
let bind_group = match &mut *cached_bind_group {
|
||||
Some((id, bind_group)) if main_texture_view.id() == *id => bind_group,
|
||||
cached_bind_group => {
|
||||
let bind_group = blit_pipeline
|
||||
.create_bind_group(render_context.render_device(), main_texture_view);
|
||||
|
||||
let (_, bind_group) =
|
||||
cached_bind_group.insert((main_texture_view.id(), bind_group));
|
||||
bind_group
|
||||
}
|
||||
};
|
||||
|
||||
let Some(pipeline) = pipeline_cache.get_render_pipeline(upscaling_target.0) else {
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
let pass_descriptor = RenderPassDescriptor {
|
||||
label: Some("upscaling"),
|
||||
color_attachments: &[Some(
|
||||
target.out_texture_color_attachment(converted_clear_color),
|
||||
)],
|
||||
depth_stencil_attachment: None,
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: None,
|
||||
};
|
||||
|
||||
let mut render_pass = render_context
|
||||
.command_encoder()
|
||||
.begin_render_pass(&pass_descriptor);
|
||||
let pass_span = diagnostics.pass_span(&mut render_pass, "upscaling");
|
||||
|
||||
if let Some(camera) = camera
|
||||
&& let Some(viewport) = &camera.viewport
|
||||
{
|
||||
let size = viewport.physical_size;
|
||||
let position = viewport.physical_position;
|
||||
render_pass.set_scissor_rect(position.x, position.y, size.x, size.y);
|
||||
}
|
||||
|
||||
render_pass.set_pipeline(pipeline);
|
||||
render_pass.set_bind_group(0, bind_group, &[]);
|
||||
render_pass.draw(0..3, 0..1);
|
||||
|
||||
pass_span.end(&mut render_pass);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user