Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add RenderTarget::TextureView #8042

Merged
merged 19 commits into from
Jun 19, 2023
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 29 additions & 3 deletions crates/bevy_render/src/camera/camera.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::{
camera::CameraProjection,
camera::{ManualTextureViewHandle, ManualTextureViews},
prelude::Image,
render_asset::RenderAssets,
render_resource::TextureView,
Expand All @@ -26,7 +27,6 @@ use bevy_utils::{HashMap, HashSet};
use bevy_window::{
NormalizedWindowRef, PrimaryWindow, Window, WindowCreated, WindowRef, WindowResized,
};

use std::{borrow::Cow, ops::Range};
use wgpu::{BlendState, Extent3d, LoadOp, TextureFormat};

Expand Down Expand Up @@ -376,6 +376,8 @@ pub enum RenderTarget {
Window(WindowRef),
/// Image to which the camera's view is rendered.
Image(Handle<Image>),
/// Texture View to which the camera's view is rendered.
TextureView(ManualTextureViewHandle),
mrchantey marked this conversation as resolved.
Show resolved Hide resolved
}

/// Normalized version of the render target.
Expand All @@ -387,6 +389,8 @@ pub enum NormalizedRenderTarget {
Window(NormalizedWindowRef),
/// Image to which the camera's view is rendered.
Image(Handle<Image>),
/// Texture View to which the camera's view is rendered.
TextureView(ManualTextureViewHandle),
mrchantey marked this conversation as resolved.
Show resolved Hide resolved
}

impl Default for RenderTarget {
Expand All @@ -403,6 +407,7 @@ impl RenderTarget {
.normalize(primary_window)
.map(NormalizedRenderTarget::Window),
RenderTarget::Image(handle) => Some(NormalizedRenderTarget::Image(handle.clone())),
RenderTarget::TextureView(id) => Some(NormalizedRenderTarget::TextureView(*id)),
}
}
}
Expand All @@ -412,6 +417,7 @@ impl NormalizedRenderTarget {
&self,
windows: &'a ExtractedWindows,
images: &'a RenderAssets<Image>,
manual_texture_views: &'a ManualTextureViews,
) -> Option<&'a TextureView> {
match self {
NormalizedRenderTarget::Window(window_ref) => windows
Expand All @@ -420,6 +426,9 @@ impl NormalizedRenderTarget {
NormalizedRenderTarget::Image(image_handle) => {
images.get(image_handle).map(|image| &image.texture_view)
}
NormalizedRenderTarget::TextureView(id) => {
manual_texture_views.get(id).map(|tex| &tex.texture_view)
}
}
}

Expand All @@ -428,6 +437,7 @@ impl NormalizedRenderTarget {
&self,
windows: &'a ExtractedWindows,
images: &'a RenderAssets<Image>,
manual_texture_views: &'a ManualTextureViews,
) -> Option<TextureFormat> {
match self {
NormalizedRenderTarget::Window(window_ref) => windows
Expand All @@ -436,13 +446,17 @@ impl NormalizedRenderTarget {
NormalizedRenderTarget::Image(image_handle) => {
images.get(image_handle).map(|image| image.texture_format)
}
NormalizedRenderTarget::TextureView(id) => {
manual_texture_views.get(id).map(|tex| tex.format)
}
}
}

pub fn get_render_target_info<'a>(
&self,
resolutions: impl IntoIterator<Item = (Entity, &'a Window)>,
images: &Assets<Image>,
manual_texture_views: &ManualTextureViews,
) -> Option<RenderTargetInfo> {
match self {
NormalizedRenderTarget::Window(window_ref) => resolutions
Expand All @@ -463,6 +477,12 @@ impl NormalizedRenderTarget {
scale_factor: 1.0,
})
}
NormalizedRenderTarget::TextureView(id) => {
manual_texture_views.get(id).map(|tex| RenderTargetInfo {
physical_size: tex.size,
scale_factor: 1.0,
})
}
}
}

Expand All @@ -479,6 +499,7 @@ impl NormalizedRenderTarget {
NormalizedRenderTarget::Image(image_handle) => {
changed_image_handles.contains(&image_handle)
}
NormalizedRenderTarget::TextureView(_) => true,
}
}
}
Expand All @@ -502,13 +523,15 @@ impl NormalizedRenderTarget {
/// [`OrthographicProjection`]: crate::camera::OrthographicProjection
/// [`PerspectiveProjection`]: crate::camera::PerspectiveProjection
/// [`Projection`]: crate::camera::Projection
#[allow(clippy::too_many_arguments)]
pub fn camera_system<T: CameraProjection + Component>(
mut window_resized_events: EventReader<WindowResized>,
mut window_created_events: EventReader<WindowCreated>,
mut image_asset_events: EventReader<AssetEvent<Image>>,
primary_window: Query<Entity, With<PrimaryWindow>>,
windows: Query<(Entity, &Window)>,
images: Res<Assets<Image>>,
manual_texture_views: Res<ManualTextureViews>,
mut cameras: Query<(&mut Camera, &mut T)>,
) {
let primary_window = primary_window.iter().next();
Expand Down Expand Up @@ -540,8 +563,11 @@ pub fn camera_system<T: CameraProjection + Component>(
|| camera_projection.is_changed()
|| camera.computed.old_viewport_size != viewport_size
{
camera.computed.target_info =
normalized_target.get_render_target_info(&windows, &images);
camera.computed.target_info = normalized_target.get_render_target_info(
&windows,
&images,
&manual_texture_views,
);
if let Some(size) = camera.logical_viewport_size() {
camera_projection.update(size.x, size.y);
camera.computed.projection_matrix = camera_projection.get_projection_matrix();
Expand Down
64 changes: 64 additions & 0 deletions crates/bevy_render/src/camera/manual_texture_view.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
use crate::extract_resource::ExtractResource;
use crate::render_resource::TextureView;
use crate::texture::BevyDefault;
use bevy_ecs::system::Resource;
use bevy_ecs::{prelude::Component, reflect::ReflectComponent};
use bevy_math::UVec2;
use bevy_reflect::prelude::*;
use bevy_reflect::FromReflect;
use bevy_utils::HashMap;
use wgpu::TextureFormat;

/// A unique id that corresponds to a specific [`ManualTextureView`] in the [`ManualTextureViews`] collection.
#[derive(
Default,
Debug,
Clone,
Copy,
PartialEq,
Eq,
Hash,
PartialOrd,
Ord,
Component,
Reflect,
FromReflect,
)]
#[reflect(Component, Default)]
pub struct ManualTextureViewHandle(pub u32);

/// A manually managed [`TextureView`] for use as a [`crate::camera::RenderTarget`].
#[derive(Debug, Clone, Component)]
pub struct ManualTextureView {
pub texture_view: TextureView,
pub size: UVec2,
pub format: TextureFormat,
}

impl ManualTextureView {
pub fn with_default_format(texture_view: TextureView, size: UVec2) -> Self {
Self {
texture_view,
size,
format: TextureFormat::bevy_default(),
}
}
}

/// Stores manually managed [`ManualTextureView`]s for use as a [`crate::camera::RenderTarget`].
#[derive(Default, Clone, Resource, ExtractResource)]
pub struct ManualTextureViews(HashMap<ManualTextureViewHandle, ManualTextureView>);

impl std::ops::Deref for ManualTextureViews {
type Target = HashMap<ManualTextureViewHandle, ManualTextureView>;

fn deref(&self) -> &Self::Target {
&self.0
}
}

impl std::ops::DerefMut for ManualTextureViews {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
11 changes: 9 additions & 2 deletions crates/bevy_render/src/camera/mod.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
#[allow(clippy::module_inception)]
mod camera;
mod camera_driver_node;
mod manual_texture_view;
mod projection;

pub use camera::*;
pub use camera_driver_node::*;
pub use manual_texture_view::*;
pub use projection::*;

use crate::{render_graph::RenderGraph, ExtractSchedule, Render, RenderApp, RenderSet};
use crate::{
extract_resource::ExtractResourcePlugin, render_graph::RenderGraph, ExtractSchedule, Render,
RenderApp, RenderSet,
};
use bevy_app::{App, Plugin};
use bevy_ecs::schedule::IntoSystemConfigs;

Expand All @@ -22,9 +27,11 @@ impl Plugin for CameraPlugin {
.register_type::<ScalingMode>()
.register_type::<CameraRenderGraph>()
.register_type::<RenderTarget>()
.init_resource::<ManualTextureViews>()
.add_plugin(CameraProjectionPlugin::<Projection>::default())
.add_plugin(CameraProjectionPlugin::<OrthographicProjection>::default())
.add_plugin(CameraProjectionPlugin::<PerspectiveProjection>::default());
.add_plugin(CameraProjectionPlugin::<PerspectiveProjection>::default())
.add_plugin(ExtractResourcePlugin::<ManualTextureViews>::default());

if let Ok(render_app) = app.get_sub_app_mut(RenderApp) {
render_app
Expand Down
7 changes: 4 additions & 3 deletions crates/bevy_render/src/view/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ pub use visibility::*;
pub use window::*;

use crate::{
camera::{ExtractedCamera, TemporalJitter},
camera::{ExtractedCamera, ManualTextureViews, TemporalJitter},
extract_resource::{ExtractResource, ExtractResourcePlugin},
prelude::{Image, Shader},
render_asset::RenderAssets,
Expand Down Expand Up @@ -374,13 +374,14 @@ fn prepare_view_targets(
render_device: Res<RenderDevice>,
mut texture_cache: ResMut<TextureCache>,
cameras: Query<(Entity, &ExtractedCamera, &ExtractedView)>,
manual_texture_views: Res<ManualTextureViews>,
) {
let mut textures = HashMap::default();
for (entity, camera, view) in cameras.iter() {
if let (Some(target_size), Some(target)) = (camera.physical_target_size, &camera.target) {
if let (Some(out_texture_view), Some(out_texture_format)) = (
target.get_texture_view(&windows, &images),
target.get_texture_format(&windows, &images),
target.get_texture_view(&windows, &images, &manual_texture_views),
target.get_texture_format(&windows, &images, &manual_texture_views),
) {
let size = Extent3d {
width: target_size.x,
Expand Down