rt: unify render target logic

This commit is contained in:
chyyran 2023-02-07 23:08:44 -05:00
parent 06161b5aad
commit 59e0b5da86
21 changed files with 134 additions and 170 deletions

View file

@ -19,13 +19,13 @@ use crate::filter_pass::{ConstantBufferBinding, FilterPass};
use crate::framebuffer::OwnedFramebuffer;
use crate::graphics_pipeline::D3D11State;
use crate::options::{FilterChainOptionsD3D11, FrameOptionsD3D11};
use crate::render_target::RenderTarget;
use crate::samplers::SamplerSet;
use crate::util::d3d11_compile_bound_shader;
use crate::{error, util, D3D11OutputView};
use librashader_reflect::reflect::presets::{CompilePresetTarget, ShaderPassArtifact};
use librashader_runtime::binding::{BindingUtil, TextureInput};
use librashader_runtime::quad::{QuadType, IDENTITY_MVP};
use librashader_runtime::quad::QuadType;
use librashader_runtime::render_target::RenderTarget;
use librashader_runtime::scaling::ScaleFramebuffer;
use librashader_runtime::uniforms::UniformStorage;
use rayon::prelude::*;
@ -485,7 +485,7 @@ impl FilterChainD3D11 {
viewport,
&original,
&source,
RenderTarget::new(target.as_output_framebuffer()?, Some(IDENTITY_MVP)),
RenderTarget::identity(&target.as_output()?),
QuadType::Offscreen,
)?;
@ -513,7 +513,7 @@ impl FilterChainD3D11 {
viewport,
&original,
&source,
RenderTarget::from(viewport),
RenderTarget::viewport(viewport),
QuadType::Final,
)?;
}

View file

@ -12,13 +12,13 @@ use rustc_hash::FxHashMap;
use librashader_runtime::binding::{BindSemantics, TextureInput};
use librashader_runtime::filter_pass::FilterPassMeta;
use librashader_runtime::quad::QuadType;
use librashader_runtime::render_target::RenderTarget;
use windows::Win32::Graphics::Direct3D11::{
ID3D11Buffer, ID3D11InputLayout, ID3D11PixelShader, ID3D11SamplerState,
ID3D11ShaderResourceView, ID3D11VertexShader, D3D11_MAPPED_SUBRESOURCE,
D3D11_MAP_WRITE_DISCARD,
D3D11_MAP_WRITE_DISCARD, D3D11_VIEWPORT,
};
use crate::render_target::RenderTarget;
use crate::samplers::SamplerSet;
use crate::{error, D3D11OutputView};
use librashader_runtime::uniforms::{UniformStorage, UniformStorageAccess};
@ -144,7 +144,7 @@ impl FilterPass {
viewport: &Viewport<D3D11OutputView>,
original: &InputTexture,
source: &InputTexture,
output: RenderTarget,
output: RenderTarget<D3D11OutputView>,
vbo_type: QuadType,
) -> error::Result<()> {
let _device = &parent.d3d11.device;
@ -236,8 +236,15 @@ impl FilterPass {
context.PSSetShaderResources(0, Some(std::mem::transmute(textures.as_ref())));
context.PSSetSamplers(0, Some(std::mem::transmute(samplers.as_ref())));
context.OMSetRenderTargets(Some(&[output.output.rtv.clone()]), None);
context.RSSetViewports(Some(&[output.output.viewport]))
context.OMSetRenderTargets(Some(&[output.output.handle.clone()]), None);
context.RSSetViewports(Some(&[D3D11_VIEWPORT {
TopLeftX: output.x,
TopLeftY: output.y,
Width: output.output.size.width as f32,
Height: output.output.size.height as f32,
MinDepth: 0.0,
MaxDepth: 1.0,
}]))
}
parent.draw_quad.draw_quad(context, vbo_type);

View file

@ -1,8 +1,8 @@
use crate::error;
use crate::error::{assume_d3d11_init, FilterChainError};
use crate::texture::D3D11InputView;
use crate::util::d3d11_get_closest_format;
use librashader_common::{ImageFormat, Size};
use crate::{error, D3D11OutputView};
use librashader_common::{ImageFormat, Size, Viewport};
use librashader_presets::Scale2D;
use librashader_runtime::scaling::{MipmapSize, ScaleFramebuffer, ViewportSize};
use windows::core::Interface;
@ -163,11 +163,11 @@ impl OwnedFramebuffer {
Ok(rtv)
}
pub fn as_output_framebuffer(&self) -> error::Result<OutputFramebuffer> {
Ok(OutputFramebuffer {
rtv: self.create_render_target_view()?,
pub fn as_output(&self) -> error::Result<D3D11OutputView> {
let rtv = self.create_render_target_view()?;
Ok(D3D11OutputView {
handle: rtv,
size: self.size,
viewport: default_viewport(self.size),
})
}
@ -221,7 +221,15 @@ impl OwnedFramebuffer {
pub(crate) struct OutputFramebuffer {
pub rtv: ID3D11RenderTargetView,
pub size: Size<u32>,
pub viewport: D3D11_VIEWPORT,
}
impl<'a> From<&Viewport<'a, D3D11OutputView>> for OutputFramebuffer {
fn from(value: &Viewport<'a, D3D11OutputView>) -> Self {
OutputFramebuffer {
rtv: value.output.handle.clone(),
size: value.output.size,
}
}
}
fn default_desc(size: Size<u32>, format: DXGI_FORMAT, mip_levels: u32) -> D3D11_TEXTURE2D_DESC {

View file

@ -17,7 +17,6 @@ mod framebuffer;
mod graphics_pipeline;
pub mod options;
mod parameters;
mod render_target;
mod samplers;
mod texture;
mod util;
@ -35,9 +34,10 @@ mod tests {
// "../test/slang-shaders/scalefx/scalefx-9x.slangp",
// "../test/slang-shaders/bezel/koko-aio/monitor-bloom.slangp",
// "../test/slang-shaders/presets/crt-geom-ntsc-upscale-sharp.slangp",
// const FILTER_PATH: &str = "../test/slang-shaders/bezel/Mega_Bezel/Presets/MBZ__0__SMOOTH-ADV.slangp";
const FILTER_PATH: &str =
"../test/slang-shaders/bezel/Mega_Bezel/Presets/MBZ__0__SMOOTH-ADV.slangp";
// "../test/null.slangp",
const FILTER_PATH: &str = "../test/slang-shaders/scalefx/scalefx-9x.slangp";
// const FILTER_PATH: &str = "../test/slang-shaders/crt/crt-royale.slangp";
// const FILTER_PATH: &str = "../test/slang-shaders/crt/crt-royale.slangp";
const IMAGE_PATH: &str = "../test/finalfightlong.png";

View file

@ -1,47 +0,0 @@
use crate::framebuffer::OutputFramebuffer;
use crate::D3D11OutputView;
use librashader_common::Viewport;
use librashader_runtime::quad::DEFAULT_MVP;
use windows::Win32::Graphics::Direct3D11::D3D11_VIEWPORT;
#[derive(Debug, Clone)]
pub(crate) struct RenderTarget<'a> {
pub mvp: &'a [f32; 16],
pub output: OutputFramebuffer,
}
impl<'a> RenderTarget<'a> {
pub fn new(backbuffer: OutputFramebuffer, mvp: Option<&'a [f32; 16]>) -> Self {
if let Some(mvp) = mvp {
RenderTarget {
output: backbuffer,
mvp,
}
} else {
RenderTarget {
output: backbuffer,
mvp: DEFAULT_MVP,
}
}
}
}
impl<'a> From<&Viewport<'a, D3D11OutputView>> for RenderTarget<'a> {
fn from(value: &Viewport<'a, D3D11OutputView>) -> Self {
RenderTarget::new(
OutputFramebuffer {
rtv: value.output.handle.clone(),
size: value.output.size,
viewport: D3D11_VIEWPORT {
TopLeftX: value.x,
TopLeftY: value.y,
Width: value.output.size.width as f32,
Height: value.output.size.height as f32,
MinDepth: 0.0,
MaxDepth: 1.0,
},
},
value.mvp,
)
}
}

View file

@ -10,7 +10,6 @@ use crate::luts::LutTexture;
use crate::mipmap::D3D12MipmapGen;
use crate::options::{FilterChainOptionsD3D12, FrameOptionsD3D12};
use crate::quad_render::DrawQuad;
use crate::render_target::RenderTarget;
use crate::samplers::SamplerSet;
use crate::texture::{D3D12InputImage, D3D12OutputView, InputTexture, OutputDescriptor};
use crate::{error, util};
@ -24,7 +23,7 @@ use librashader_reflect::reflect::semantics::{BindingMeta, ShaderSemantics, MAX_
use librashader_reflect::reflect::ReflectShader;
use librashader_runtime::binding::{BindingUtil, TextureInput};
use librashader_runtime::image::{Image, UVDirection};
use librashader_runtime::quad::{QuadType, DEFAULT_MVP, IDENTITY_MVP};
use librashader_runtime::quad::QuadType;
use librashader_runtime::uniforms::UniformStorage;
use rustc_hash::FxHashMap;
use spirv_cross::hlsl::ShaderModel;
@ -46,6 +45,7 @@ use windows::Win32::Graphics::Dxgi::Common::DXGI_FORMAT_UNKNOWN;
use windows::Win32::System::Threading::{CreateEventA, ResetEvent, WaitForSingleObject};
use windows::Win32::System::WindowsProgramming::INFINITE;
use librashader_runtime::render_target::RenderTarget;
use librashader_runtime::scaling::{MipmapSize, ScaleFramebuffer};
use rayon::prelude::*;
@ -657,18 +657,9 @@ impl FilterChainD3D12 {
D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE,
D3D12_RESOURCE_STATE_RENDER_TARGET,
);
let size = target.size;
let view = target.create_render_target_view(&mut self.rtv_heap)?;
let out = RenderTarget {
x: 0.0,
y: 0.0,
mvp: IDENTITY_MVP,
output: D3D12OutputView {
descriptor: view.descriptor,
size,
},
};
let view = target.create_render_target_view(&mut self.rtv_heap)?;
let out = RenderTarget::identity(&view);
pass.draw(
cmd,
@ -690,7 +681,7 @@ impl FilterChainD3D12 {
D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE,
);
self.residuals.push(out.output.descriptor);
self.residuals.push(view.descriptor);
source = self.common.output_textures[index].as_ref().unwrap().clone()
}
@ -700,12 +691,7 @@ impl FilterChainD3D12 {
source.filter = pass.config.filter;
source.wrap_mode = pass.config.wrap_mode;
let out = RenderTarget {
x: 0.0,
y: 0.0,
mvp: DEFAULT_MVP,
output: viewport.output.clone(),
};
let out = RenderTarget::viewport(viewport);
pass.draw(
cmd,

View file

@ -3,7 +3,6 @@ use crate::descriptor_heap::{D3D12DescriptorHeapSlot, ResourceWorkHeap, SamplerW
use crate::error;
use crate::filter_chain::FilterCommon;
use crate::graphics_pipeline::D3D12GraphicsPipeline;
use crate::render_target::RenderTarget;
use crate::samplers::SamplerSet;
use crate::texture::{D3D12OutputView, InputTexture};
use librashader_common::{ImageFormat, Size, Viewport};
@ -14,6 +13,7 @@ use librashader_reflect::reflect::ShaderReflection;
use librashader_runtime::binding::{BindSemantics, TextureInput};
use librashader_runtime::filter_pass::FilterPassMeta;
use librashader_runtime::quad::QuadType;
use librashader_runtime::render_target::RenderTarget;
use librashader_runtime::uniforms::{NoUniformBinder, UniformStorage};
use rustc_hash::FxHashMap;
use std::ops::Deref;
@ -139,7 +139,7 @@ impl FilterPass {
viewport: &Viewport<D3D12OutputView>,
original: &InputTexture,
source: &InputTexture,
output: &RenderTarget,
output: &RenderTarget<D3D12OutputView>,
vbo_type: QuadType,
) -> error::Result<()> {
unsafe {

View file

@ -2,6 +2,7 @@
#![feature(const_trait_impl)]
#![feature(let_chains)]
#![feature(type_alias_impl_trait)]
mod buffer;
mod descriptor_heap;
pub mod error;
@ -15,7 +16,6 @@ mod mipmap;
pub mod options;
mod parameters;
mod quad_render;
mod render_target;
mod samplers;
mod texture;
mod util;

View file

@ -1,8 +0,0 @@
use crate::texture::D3D12OutputView;
pub(crate) struct RenderTarget<'a> {
pub x: f32,
pub y: f32,
pub mvp: &'a [f32; 16],
pub output: D3D12OutputView,
}

View file

@ -3,7 +3,6 @@ use crate::error::FilterChainError;
use crate::filter_pass::{FilterPass, UniformOffset};
use crate::gl::{DrawQuad, Framebuffer, FramebufferInterface, GLInterface, LoadLut, UboRing};
use crate::options::{FilterChainOptionsGL, FrameOptionsGL};
use crate::render_target::{RenderTarget, GL_MVP_DEFAULT};
use crate::samplers::SamplerSet;
use crate::texture::InputTexture;
use crate::util::{gl_get_version, gl_u16_to_version};
@ -21,11 +20,20 @@ use librashader_reflect::reflect::semantics::{BindingMeta, ShaderSemantics, Unif
use librashader_reflect::reflect::presets::{CompilePresetTarget, ShaderPassArtifact};
use librashader_reflect::reflect::ReflectShader;
use librashader_runtime::binding::BindingUtil;
use librashader_runtime::render_target::RenderTarget;
use librashader_runtime::scaling::ScaleFramebuffer;
use rustc_hash::FxHashMap;
use spirv_cross::spirv::Decoration;
use std::collections::VecDeque;
#[rustfmt::skip]
pub static GL_MVP_DEFAULT: &[f32; 16] = &[
2f32, 0.0, 0.0, 0.0,
0.0, 2.0, 0.0, 0.0,
0.0, 0.0, 2.0, 0.0,
-1.0, -1.0, 0.0, 1.0,
];
pub(crate) struct FilterChainImpl<T: GLInterface> {
pub(crate) common: FilterCommon,
passes: Box<[FilterPass<T>]>,
@ -406,7 +414,7 @@ impl<T: GLInterface> FilterChainImpl<T> {
viewport,
&original,
&source,
RenderTarget::new(target, viewport.mvp.unwrap_or(GL_MVP_DEFAULT), 0, 0),
RenderTarget::offscreen(target, viewport.mvp.unwrap_or(GL_MVP_DEFAULT)),
);
let target = target.as_texture(pass.config.filter, pass.config.wrap_mode);
@ -429,12 +437,7 @@ impl<T: GLInterface> FilterChainImpl<T> {
viewport,
&original,
&source,
RenderTarget::new(
viewport.output,
viewport.mvp.unwrap_or(GL_MVP_DEFAULT),
viewport.x as i32,
viewport.y as i32,
),
RenderTarget::viewport(viewport),
);
self.common.output_textures[passes_len - 1] = viewport
.output

View file

@ -1,4 +1,4 @@
use gl::types::{GLsizei, GLuint};
use gl::types::{GLint, GLsizei, GLuint};
use librashader_reflect::back::cross::CrossGlslContext;
use librashader_reflect::back::ShaderCompilerOutput;
use librashader_reflect::reflect::ShaderReflection;
@ -9,12 +9,12 @@ use librashader_presets::ShaderPassConfig;
use librashader_reflect::reflect::semantics::{MemberOffset, TextureBinding, UniformBinding};
use librashader_runtime::binding::{BindSemantics, ContextOffset, TextureInput};
use librashader_runtime::filter_pass::FilterPassMeta;
use librashader_runtime::render_target::RenderTarget;
use rustc_hash::FxHashMap;
use crate::binding::{GlUniformBinder, GlUniformStorage, UniformLocation, VariableLocation};
use crate::filter_chain::FilterCommon;
use crate::gl::{BindTexture, GLInterface, UboRing};
use crate::render_target::RenderTarget;
use crate::samplers::SamplerSet;
use crate::Framebuffer;
@ -87,9 +87,9 @@ impl<T: GLInterface> FilterPass<T> {
viewport: &Viewport<&Framebuffer>,
original: &InputTexture,
source: &InputTexture,
output: RenderTarget,
output: RenderTarget<Framebuffer, GLint>,
) {
let framebuffer = output.framebuffer;
let framebuffer = output.output;
if self.config.mipmap_input && !parent.disable_mipmaps {
T::BindTexture::gen_mipmaps(source);

View file

@ -12,7 +12,6 @@ mod binding;
mod filter_chain;
mod filter_pass;
mod framebuffer;
mod render_target;
mod util;
mod gl;

View file

@ -1,28 +0,0 @@
use crate::gl::Framebuffer;
#[rustfmt::skip]
pub static GL_MVP_DEFAULT: &[f32; 16] = &[
2f32, 0.0, 0.0, 0.0,
0.0, 2.0, 0.0, 0.0,
0.0, 0.0, 2.0, 0.0,
-1.0, -1.0, 0.0, 1.0,
];
#[derive(Debug, Copy, Clone)]
pub(crate) struct RenderTarget<'a> {
pub mvp: &'a [f32; 16],
pub framebuffer: &'a Framebuffer,
pub x: i32,
pub y: i32,
}
impl<'a> RenderTarget<'a> {
pub fn new(backbuffer: &'a Framebuffer, mvp: &'a [f32; 16], x: i32, y: i32) -> Self {
RenderTarget {
framebuffer: backbuffer,
x,
mvp,
y,
}
}
}

View file

@ -5,7 +5,6 @@ use crate::framebuffer::OutputImage;
use crate::luts::LutTexture;
use crate::options::{FilterChainOptionsVulkan, FrameOptionsVulkan};
use crate::queue_selection::get_graphics_queue;
use crate::render_target::RenderTarget;
use crate::samplers::SamplerSet;
use crate::texture::{InputImage, OwnedImage, OwnedImageLayout, VulkanImage};
use crate::vulkan_primitives::RawVulkanBuffer;
@ -23,13 +22,14 @@ use librashader_reflect::reflect::semantics::{BindingMeta, ShaderSemantics};
use librashader_reflect::reflect::ReflectShader;
use librashader_runtime::binding::BindingUtil;
use librashader_runtime::image::{Image, UVDirection};
use librashader_runtime::quad::{QuadType, DEFAULT_MVP, IDENTITY_MVP};
use librashader_runtime::quad::QuadType;
use librashader_runtime::uniforms::UniformStorage;
use rustc_hash::FxHashMap;
use std::collections::VecDeque;
use std::path::Path;
use std::sync::Arc;
use librashader_runtime::render_target::RenderTarget;
use librashader_runtime::scaling::ScaleFramebuffer;
use rayon::prelude::*;
@ -652,12 +652,8 @@ impl FilterChainVulkan {
source.wrap_mode = pass.config.wrap_mode;
source.mip_filter = pass.config.filter;
let out = RenderTarget {
x: 0.0,
y: 0.0,
mvp: IDENTITY_MVP,
output: OutputImage::new(&self.vulkan, target.image.clone())?,
};
let output_image = OutputImage::new(&self.vulkan, target.image.clone())?;
let out = RenderTarget::identity(&output_image);
let residual_fb = pass.draw(
cmd,
@ -679,7 +675,7 @@ impl FilterChainVulkan {
}
source = self.common.output_inputs[index].clone().unwrap();
intermediates.dispose_outputs(out.output);
intermediates.dispose_outputs(output_image);
intermediates.dispose_framebuffers(residual_fb);
}
@ -690,12 +686,8 @@ impl FilterChainVulkan {
source.wrap_mode = pass.config.wrap_mode;
source.mip_filter = pass.config.filter;
let out = RenderTarget {
x: viewport.x,
y: viewport.y,
mvp: viewport.mvp.unwrap_or(DEFAULT_MVP),
output: OutputImage::new(&self.vulkan, viewport.output.clone())?,
};
let output_image = OutputImage::new(&self.vulkan, viewport.output.clone())?;
let out = RenderTarget::viewport_with_output(&output_image, viewport);
let residual_fb = pass.draw(
cmd,
@ -710,7 +702,7 @@ impl FilterChainVulkan {
QuadType::Final,
)?;
intermediates.dispose_outputs(out.output);
intermediates.dispose_outputs(output_image);
intermediates.dispose_framebuffers(residual_fb);
}

View file

@ -1,5 +1,5 @@
use crate::filter_chain::FilterCommon;
use crate::render_target::RenderTarget;
use crate::framebuffer::OutputImage;
use crate::samplers::SamplerSet;
use crate::texture::InputImage;
use crate::vulkan_primitives::RawVulkanBuffer;
@ -16,6 +16,7 @@ use librashader_reflect::reflect::ShaderReflection;
use librashader_runtime::binding::{BindSemantics, TextureInput};
use librashader_runtime::filter_pass::FilterPassMeta;
use librashader_runtime::quad::QuadType;
use librashader_runtime::render_target::RenderTarget;
use librashader_runtime::uniforms::{NoUniformBinder, UniformStorage, UniformStorageAccess};
use rustc_hash::FxHashMap;
use std::sync::Arc;
@ -95,7 +96,7 @@ impl FilterPass {
viewport: &Viewport<VulkanImage>,
original: &InputImage,
source: &InputImage,
output: &RenderTarget,
output: &RenderTarget<OutputImage>,
vbo_type: QuadType,
) -> error::Result<Option<vk::Framebuffer>> {
let mut descriptor = self.graphics_pipeline.layout.descriptor_sets

View file

@ -16,7 +16,6 @@ mod hello_triangle;
mod luts;
mod parameters;
mod queue_selection;
mod render_target;
mod samplers;
mod texture;
mod util;
@ -45,8 +44,8 @@ mod tests {
dbg!("finished");
let filter = FilterChainVulkan::load_from_path(
&base,
"../test/slang-shaders/crt/crt-royale.slangp",
// "../test/slang-shaders/bezel/Mega_Bezel/Presets/MBZ__2__ADV-NO-REFLECT.slangp",
// "../test/slang-shaders/crt/crt-royale.slangp",
"../test/slang-shaders/bezel/Mega_Bezel/Presets/MBZ__2__ADV-NO-REFLECT.slangp",
// "../test/basic.slangp",
Some(&FilterChainOptionsVulkan {
frames_in_flight: 3,

View file

@ -1,9 +0,0 @@
use crate::framebuffer::OutputImage;
#[derive(Clone)]
pub(crate) struct RenderTarget<'a> {
pub x: f32,
pub y: f32,
pub mvp: &'a [f32; 16],
pub output: OutputImage,
}

View file

@ -1,11 +1,12 @@
use crate::{error, util};
use ash::vk;
use crate::framebuffer::OutputImage;
use crate::render_pass::VulkanRenderPass;
use crate::render_target::RenderTarget;
use librashader_reflect::back::ShaderCompilerOutput;
use librashader_reflect::reflect::semantics::{TextureBinding, UboReflection};
use librashader_reflect::reflect::ShaderReflection;
use librashader_runtime::render_target::RenderTarget;
use std::ffi::CStr;
const ENTRY_POINT: &CStr = unsafe { CStr::from_bytes_with_nul_unchecked(b"main\0") };
@ -326,7 +327,7 @@ impl VulkanGraphicsPipeline {
pub(crate) fn begin_rendering(
&self,
device: &ash::Device,
output: &RenderTarget,
output: &RenderTarget<OutputImage>,
cmd: vk::CommandBuffer,
) -> error::Result<Option<vk::Framebuffer>> {
if let Some(render_pass) = &self.render_pass {

View file

@ -31,3 +31,6 @@ pub mod quad;
/// Filter pass helpers and common traits.
pub mod filter_pass;
/// Common types for render targets.
pub mod render_target;

View file

@ -0,0 +1,57 @@
use crate::quad::{DEFAULT_MVP, IDENTITY_MVP};
use librashader_common::Viewport;
use num_traits::{zero, AsPrimitive, Num};
use std::borrow::Borrow;
#[derive(Debug, Clone)]
pub struct RenderTarget<'a, T, C = f32>
where
C: Num,
{
pub mvp: &'a [f32; 16],
pub x: C,
pub y: C,
pub output: &'a T,
}
impl<'a, T, C: Num> RenderTarget<'a, T, C> {
/// Create a new render target.
pub fn new(output: &'a T, mvp: &'a [f32; 16], x: C, y: C) -> Self {
RenderTarget { output, mvp, x, y }
}
/// Create a render target with the identity MVP.
pub fn identity(output: &'a T) -> Self {
Self::offscreen(output, IDENTITY_MVP)
}
/// Create an offscreen render target with the given MVP.
pub fn offscreen(output: &'a T, mvp: &'a [f32; 16]) -> Self {
Self::new(output, mvp, zero(), zero())
}
}
impl<'a, T, C: Num + Copy + 'static> RenderTarget<'a, T, C>
where
f32: AsPrimitive<C>,
{
/// Create a viewport render target.
pub fn viewport(viewport: &'a Viewport<'a, impl Borrow<T>>) -> Self {
Self::new(
viewport.output.borrow(),
viewport.mvp.unwrap_or(DEFAULT_MVP),
viewport.x.as_(),
viewport.y.as_(),
)
}
/// Create a viewport render target with the given output.
pub fn viewport_with_output<S>(output: &'a T, viewport: &'a Viewport<'a, S>) -> Self {
Self::new(
output,
viewport.mvp.unwrap_or(DEFAULT_MVP),
viewport.x.as_(),
viewport.y.as_(),
)
}
}