Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- use vulkan_lib :: error ; use std :: sync :: Arc ; use ash :: vk ; use ash ::
- version :: DeviceV1_0 ; pub struct Images {
- msaa_image : std :: sync :: Arc < vulkan_lib :: image :: IntermediaryImage > ,
- depth_image : std :: sync :: Arc < vulkan_lib :: image :: DepthImage > , }
- impl Images {
- pub fn new ( renderer : & vulkan_lib :: Renderer ) -> error :: Result < Self >
- {
- let depth_image = std :: sync :: Arc :: new (
- vulkan_lib :: image :: DepthImage :: new (
- renderer . device ( ) . clone ( ) , renderer . swapchain ( ) . clone ( ) ,
- renderer . allocator ( ) . clone ( ) , renderer . setup_command_buffer ( )
- . clone ( ) , renderer . samples ( ) , vk :: Format :: from_raw ( 124i32 ) )
- ? ) ; Ok (
- Images {
- msaa_image : std :: sync :: Arc :: new (
- vulkan_lib :: image :: IntermediaryImage :: new (
- renderer . device ( ) . clone ( ) , renderer . swapchain ( ) . clone ( ) ,
- renderer . allocator ( ) . clone ( ) , renderer . setup_command_buffer ( )
- . clone ( ) , renderer . samples ( ) , vk :: Format :: R32G32B32A32_SFLOAT ,
- ) ? ) , depth_image : depth_image , } ) } pub fn msaa_image ( & self ) -> std
- :: sync :: Arc < vulkan_lib :: image :: IntermediaryImage > {
- self . msaa_image . clone ( ) } # [ inline ] pub fn depth_image ( & self ) ->
- Arc < vulkan_lib :: image :: DepthImage > { self . depth_image . clone ( ) }
- } # [ derive ( Default ) ] struct MainPipeline {
- descriptor_sizes : Vec < vk :: DescriptorPoolSize > , desc_layout_bindings :
- Vec < vk :: DescriptorSetLayoutBinding > , descriptor_pool_info : Option < vk
- :: DescriptorPoolCreateInfo > , descriptor_info : Option < vk ::
- DescriptorSetLayoutCreateInfo > , desc_set_layouts : Vec < vk ::
- DescriptorSetLayout > , desc_alloc_info : Option < vk ::
- DescriptorSetAllocateInfo > , descriptor_sets : Vec < vk :: DescriptorSet > ,
- layout_create_info : Option < vk :: PipelineLayoutCreateInfo > ,
- pipeline_layout : Option < vk :: PipelineLayout > , write_desc_sets : Vec < vk
- :: WriteDescriptorSet > , vertex : Option < vulkan_lib :: shader :: Shader > ,
- fragment : Option < vulkan_lib :: shader :: Shader > ,
- shader_stage_create_infos : Vec < vk :: PipelineShaderStageCreateInfo > ,
- vertex_input_state_info : Option < vk :: PipelineVertexInputStateCreateInfo >
- , vertex_input_assembly_state_info : Option < vk ::
- PipelineInputAssemblyStateCreateInfo > , rasterization_info : Option < vk ::
- PipelineRasterizationStateCreateInfo > , color_blend_attachment_states : Vec <
- vk :: PipelineColorBlendAttachmentState > , color_blend_state : Option < vk ::
- PipelineColorBlendStateCreateInfo > , depth_state_info : Option < vk ::
- PipelineDepthStencilStateCreateInfo > , dynamic_state : Vec < vk ::
- DynamicState > , dynamic_state_info : Option < vk ::
- PipelineDynamicStateCreateInfo > , multisample_state_info : Option < vk ::
- PipelineMultisampleStateCreateInfo > , viewports : Vec < vk :: Viewport > ,
- scissors : Vec < vk :: Rect2D > , viewport_state_info : Option < vk ::
- PipelineViewportStateCreateInfo > , desc_0 : Option < vk ::
- DescriptorBufferInfo > , ubo : Option < vulkan_lib :: buffer :: CpuBuffer > ,
- desc_1 : Option < vk :: DescriptorImageInfo > , texture : Option < vulkan_lib
- :: texture :: Texture > , } impl MainPipeline {
- pub fn new (
- renderer : & vulkan_lib :: Renderer , images : std :: sync :: Arc < Images > ,
- texture : vulkan_lib :: texture :: Texture ) -> vulkan_lib :: error :: Result
- < Self > {
- let descriptor_sizes = vec ! [
- vk :: DescriptorPoolSize {
- ty : vk :: DescriptorType :: UNIFORM_BUFFER , descriptor_count : 1 , } , vk ::
- DescriptorPoolSize {
- ty : vk :: DescriptorType :: COMBINED_IMAGE_SAMPLER , descriptor_count : 1 , }
- ] ; let desc_layout_bindings = vec ! [
- vk :: DescriptorSetLayoutBinding {
- binding : 0u32 , descriptor_type : vk :: DescriptorType :: UNIFORM_BUFFER ,
- descriptor_count : 1 , stage_flags : vk :: ShaderStageFlags :: FRAGMENT | vk
- :: ShaderStageFlags :: VERTEX , .. Default :: default ( ) } , vk ::
- DescriptorSetLayoutBinding {
- binding : 1u32 , descriptor_type : vk :: DescriptorType ::
- COMBINED_IMAGE_SAMPLER , descriptor_count : 1 , stage_flags : vk ::
- ShaderStageFlags :: FRAGMENT , .. Default :: default ( ) } ] ; let mut this =
- Self { descriptor_sizes , desc_layout_bindings , .. Default :: default ( ) }
- ; this . descriptor_pool_info = Some (
- vk :: DescriptorPoolCreateInfo :: builder ( ) . pool_sizes (
- & this . descriptor_sizes ) . max_sets ( 4u32 ) . build ( ) ) ; let
- descriptor_pool = unsafe {
- renderer . device ( ) . device ( ) . create_descriptor_pool (
- this . descriptor_pool_info . as_ref ( ) . unwrap ( ) , None ) } ? ; this .
- descriptor_info = Some (
- vk :: DescriptorSetLayoutCreateInfo :: builder ( ) . bindings (
- & this . desc_layout_bindings [ .. ] ) . build ( ) ) ; this .
- desc_set_layouts . push (
- unsafe {
- renderer . device ( ) . device ( ) . create_descriptor_set_layout (
- this . descriptor_info . as_ref ( ) . unwrap ( ) , None ) } ? ) ; this .
- desc_alloc_info = Some (
- vk :: DescriptorSetAllocateInfo :: builder ( ) . descriptor_pool (
- descriptor_pool ) . set_layouts ( & this . desc_set_layouts [ .. ] ) . build (
- ) ) ; let mut descriptor_sets = unsafe {
- renderer . device ( ) . device ( ) . allocate_descriptor_sets (
- this . desc_alloc_info . as_ref ( ) . unwrap ( ) ) } ? ; this .
- descriptor_sets . append ( & mut descriptor_sets ) ; this . layout_create_info
- = Some (
- vk :: PipelineLayoutCreateInfo :: builder ( ) . set_layouts (
- & this . desc_set_layouts [ .. ] ) . build ( ) ) ; this . pipeline_layout =
- Some (
- unsafe {
- renderer . device ( ) . device ( ) . create_pipeline_layout (
- this . layout_create_info . as_ref ( ) . unwrap ( ) , None ) } ? ) ; this .
- ubo = Some (
- vulkan_lib :: buffer :: CpuBuffer :: new (
- renderer . allocator ( ) . clone ( ) , None , vk :: BufferUsageFlags ::
- UNIFORM_BUFFER , std :: mem :: size_of :: < super :: MyUBO > ( ) as u64 ) ? )
- ; this . desc_0 = Some (
- vk :: DescriptorBufferInfo {
- buffer : * this . ubo ( ) . buffer ( ) , offset : 0 , range : this . ubo (
- ) . size ( ) as u64 } ) ; this . texture = Some ( texture ) ; this . desc_1 =
- Some (
- vk :: DescriptorImageInfo {
- image_layout : vk :: ImageLayout :: SHADER_READ_ONLY_OPTIMAL , image_view :
- this . texture ( ) . image_view ( ) , sampler : this . texture ( ) .
- sampler ( ) , } ) ; this . write_desc_sets = vec ! [
- vk :: WriteDescriptorSet {
- dst_set : this . descriptor_sets [ 0 ] , dst_binding : 0u32 , descriptor_count
- : 1 , descriptor_type : vk :: DescriptorType :: UNIFORM_BUFFER , p_buffer_info
- : this . desc_0 . as_ref ( ) . unwrap ( ) , .. Default :: default ( ) } ,
- vk :: WriteDescriptorSet {
- dst_set : this . descriptor_sets [ 0 ] , dst_binding : 1u32 , descriptor_count
- : 1 , descriptor_type : vk :: DescriptorType :: COMBINED_IMAGE_SAMPLER ,
- p_image_info : this . desc_1 . as_ref ( ) . unwrap ( ) , .. Default ::
- default ( ) } ] ; unsafe {
- renderer . device ( ) . device ( ) . update_descriptor_sets (
- & this . write_desc_sets [ .. ] , & [ ] ) ; } let mut compiler = shaderc ::
- Compiler :: new ( ) . ok_or_else (
- || error :: Error :: ShaderCompilerCreationFailed ) ? ; this . vertex = Some (
- vulkan_lib :: shader :: Shader :: new (
- & mut compiler , renderer . device ( ) . clone ( ) ,
- "path_to_vertex_shader.glsl" , "vertex" , "main" , shaderc :: ShaderKind ::
- Vertex ) ? ) ; this . shader_stage_create_infos . push (
- this . vertex . as_ref ( ) . unwrap ( ) . as_pipeline_shader_stage_info ( )
- ) ; this . fragment = Some (
- vulkan_lib :: shader :: Shader :: new (
- & mut compiler , renderer . device ( ) . clone ( ) ,
- "path_to_vertex_shader.glsl" , "fragment" , "main" , shaderc :: ShaderKind ::
- Fragment ) ? ) ; this . shader_stage_create_infos . push (
- this . fragment . as_ref ( ) . unwrap ( ) . as_pipeline_shader_stage_info (
- ) ) ; let vertex_input_binding_descriptions = [
- vk :: VertexInputBindingDescription {
- binding : 0 , stride : std :: mem :: size_of :: < super :: MyVertex > ( ) as
- u32 , input_rate : vk :: VertexInputRate :: VERTEX , } ] ; use vulkan_lib ::
- Vertex ; let mut i = 0 ; let vertex_input_attribute_descriptions : Vec < vk ::
- VertexInputAttributeDescription > = super :: MyVertex :: get_fields ( ) .
- iter ( ) . map (
- | ( offset , kind ) | {
- i += 1 ; vk :: VertexInputAttributeDescription {
- location : i - 1 , binding : 0 , format : * kind , offset : * offset as u32 }
- } ) . collect ( ) ; this . vertex_input_state_info = Some (
- vk :: PipelineVertexInputStateCreateInfo {
- vertex_attribute_description_count : vertex_input_attribute_descriptions . len
- ( ) as u32 , p_vertex_attribute_descriptions :
- vertex_input_attribute_descriptions . as_ptr ( ) ,
- vertex_binding_description_count : vertex_input_binding_descriptions . len (
- ) as u32 , p_vertex_binding_descriptions : vertex_input_binding_descriptions .
- as_ptr ( ) , .. Default :: default ( ) } ) ; this .
- vertex_input_assembly_state_info = Some (
- vk :: PipelineInputAssemblyStateCreateInfo {
- topology : vk :: PrimitiveTopology :: TRIANGLE_LIST , .. Default :: default (
- ) } ) ; this . rasterization_info = Some (
- vk :: PipelineRasterizationStateCreateInfo {
- front_face : vk :: FrontFace :: COUNTER_CLOCKWISE , line_width : 1.0 ,
- polygon_mode : vk :: PolygonMode :: FILL , cull_mode : vk :: CullModeFlags ::
- BACK , .. Default :: default ( ) } ) ; let noop_stencil_state = vk ::
- StencilOpState {
- fail_op : vk :: StencilOp :: KEEP , pass_op : vk :: StencilOp :: KEEP ,
- depth_fail_op : vk :: StencilOp :: KEEP , compare_op : vk :: CompareOp ::
- ALWAYS , .. Default :: default ( ) } ; this . depth_state_info = Some (
- vk :: PipelineDepthStencilStateCreateInfo {
- depth_test_enable : 1 , depth_write_enable : 1 , depth_compare_op : vk ::
- CompareOp :: LESS_OR_EQUAL , front : noop_stencil_state . clone ( ) , back :
- noop_stencil_state . clone ( ) , max_depth_bounds : 1.0 , .. Default ::
- default ( ) } ) ; this . color_blend_attachment_states . append (
- & mut vec ! [
- vk :: PipelineColorBlendAttachmentState {
- blend_enable : 0 , src_color_blend_factor : vk :: BlendFactor :: SRC_COLOR ,
- dst_color_blend_factor : vk :: BlendFactor :: ONE_MINUS_DST_COLOR ,
- color_blend_op : vk :: BlendOp :: ADD , src_alpha_blend_factor : vk ::
- BlendFactor :: ZERO , dst_alpha_blend_factor : vk :: BlendFactor :: ZERO ,
- alpha_blend_op : vk :: BlendOp :: ADD , color_write_mask : vk ::
- ColorComponentFlags :: all ( ) , } ] ) ; this . color_blend_state = Some (
- vk :: PipelineColorBlendStateCreateInfo :: builder ( ) . logic_op (
- vk :: LogicOp :: CLEAR ) . attachments (
- & this . color_blend_attachment_states [ .. ] ) . build ( ) ) ; this .
- dynamic_state . append (
- & mut vec ! [ vk :: DynamicState :: VIEWPORT , vk :: DynamicState :: SCISSOR ]
- ) ; this . dynamic_state_info = Some (
- vk :: PipelineDynamicStateCreateInfo :: builder ( ) . dynamic_states (
- & this . dynamic_state [ .. ] ) . build ( ) ) ; Ok ( this ) } pub fn
- create_pipeline (
- & mut self , renderer : & vulkan_lib :: Renderer , renderpass : vk ::
- RenderPass ) -> vk :: GraphicsPipelineCreateInfo {
- self . multisample_state_info = Some (
- vk :: PipelineMultisampleStateCreateInfo {
- rasterization_samples : vk :: SampleCountFlags :: TYPE_1 , .. Default ::
- default ( ) } ) ; self . viewports = vec ! [
- vk :: Viewport {
- x : 0.0 , y : 0.0 , width : renderer . swapchain ( ) . surface_resolution (
- ) . width as f32 , height : renderer . swapchain ( ) . surface_resolution (
- ) . height as f32 , min_depth : 0.0 , max_depth : 1.0 , } ] ; self . scissors
- = vec ! [
- vk :: Rect2D {
- offset : vk :: Offset2D { x : 0 , y : 0 } , extent : renderer . swapchain ( )
- . surface_resolution ( ) , } ] ; self . viewport_state_info = Some (
- vk :: PipelineViewportStateCreateInfo :: builder ( ) . scissors (
- & self . scissors [ .. ] ) . viewports ( & self . viewports [ .. ] ) . build (
- ) ) ; vk :: GraphicsPipelineCreateInfo :: builder ( ) . stages (
- & self . shader_stage_create_infos ) . vertex_input_state (
- self . vertex_input_state_info . as_ref ( ) . unwrap ( ) ) .
- input_assembly_state (
- self . vertex_input_assembly_state_info . as_ref ( ) . unwrap ( ) ) .
- viewport_state ( self . viewport_state_info . as_ref ( ) . unwrap ( ) ) .
- rasterization_state ( self . rasterization_info . as_ref ( ) . unwrap ( ) )
- . multisample_state (
- self . multisample_state_info . as_ref ( ) . unwrap ( ) ) .
- depth_stencil_state ( self . depth_state_info . as_ref ( ) . unwrap ( ) ) .
- color_blend_state ( self . color_blend_state . as_ref ( ) . unwrap ( ) ) .
- dynamic_state ( self . dynamic_state_info . as_ref ( ) . unwrap ( ) ) .
- layout ( * self . pipeline_layout . as_ref ( ) . unwrap ( ) ) . render_pass
- ( renderpass ) . build ( ) } pub fn ubo ( & self ) -> & vulkan_lib :: buffer
- :: CpuBuffer { self . ubo . as_ref ( ) . unwrap ( ) } pub fn texture (
- & self ) -> & vulkan_lib :: texture :: Texture {
- self . texture . as_ref ( ) . unwrap ( ) } } # [ derive ( Default ) ] pub
- struct MainRenderpass {
- images : Option < std :: sync :: Arc < Images >> , attachments : Vec < vk ::
- AttachmentDescription > , renderpass : Option < vk :: RenderPass > ,
- dependencies : Vec < vk :: SubpassDependency > , renderpass_attachments : Vec
- < vk :: AttachmentDescription > , subpasses : Vec < vk :: SubpassDescription >
- , framebuffers : Vec < vk :: Framebuffer > , main_pipeline_colors : Vec < vk
- :: AttachmentReference > , main_pipeline_depth : Option < vk ::
- AttachmentReference > , main_pipeline_inputs : Vec < vk :: AttachmentReference
- > , main_pipeline : Option < MainPipeline > } impl MainRenderpass {
- pub fn new (
- renderer : & vulkan_lib :: Renderer , images : std :: sync :: Arc < Images > ,
- samples : u8 , texture : vulkan_lib :: texture :: Texture ) -> vulkan_lib ::
- error :: Result < Self > {
- let mut this = Self {
- images : Some ( images . clone ( ) ) , .. Default :: default ( ) } ; this .
- attachments = vec ! [
- vk :: AttachmentDescription {
- format : renderer . device ( ) . surface_format ( ) . format , samples : vk
- :: SampleCountFlags :: TYPE_1 , load_op : vk :: AttachmentLoadOp :: CLEAR ,
- store_op : vk :: AttachmentStoreOp :: STORE , final_layout : vk :: ImageLayout
- :: COLOR_ATTACHMENT_OPTIMAL , .. Default :: default ( ) } , vk ::
- AttachmentDescription {
- format : vk :: Format :: from_raw ( 124i32 ) , samples : vk ::
- SampleCountFlags :: from_raw ( samples as u32 ) , load_op : vk ::
- AttachmentLoadOp :: CLEAR , stencil_load_op : vk :: AttachmentLoadOp ::
- DONT_CARE , stencil_store_op : vk :: AttachmentStoreOp :: DONT_CARE ,
- final_layout : vk :: ImageLayout :: DEPTH_STENCIL_ATTACHMENT_OPTIMAL , ..
- Default :: default ( ) } ] ; if samples != 1 {
- this . attachments . push (
- vk :: AttachmentDescription {
- format : renderer . device ( ) . surface_format ( ) . format , samples : vk
- :: SampleCountFlags :: TYPE_1 , load_op : vk :: AttachmentLoadOp :: CLEAR ,
- store_op : vk :: AttachmentStoreOp :: STORE , final_layout : vk :: ImageLayout
- :: COLOR_ATTACHMENT_OPTIMAL , .. Default :: default ( ) } ) } let mut
- dependencies = vec ! [
- vk :: SubpassDependency {
- src_subpass : 4294967295u32 , dst_subpass : 4294967295u32 , src_stage_mask :
- vk :: PipelineStageFlags :: from_raw ( 8192u32 ) , dst_stage_mask : vk ::
- PipelineStageFlags :: from_raw ( 1024u32 ) , src_access_mask : vk ::
- AccessFlags :: from_raw ( 32768u32 ) , dst_access_mask : vk :: AccessFlags ::
- from_raw ( 1536u32 ) , dependency_flags : vk :: DependencyFlags :: BY_REGION ,
- .. Default :: default ( ) } , ] ; if samples != 1 {
- let len = dependencies . len ( ) ; dependencies [ len - 1 ] . dst_subpass =
- dependencies . len ( ) as u32 ; dependencies [ len - 1 ] . dst_stage_mask =
- vk :: PipelineStageFlags :: COLOR_ATTACHMENT_OUTPUT ; dependencies [ len - 1 ]
- . dst_access_mask = vk :: AccessFlags :: COLOR_ATTACHMENT_READ | vk ::
- AccessFlags :: COLOR_ATTACHMENT_WRITE ; dependencies . push (
- vk :: SubpassDependency {
- src_subpass : ( dependencies . len ( ) - 1 ) as u32 , dst_subpass : vk ::
- SUBPASS_EXTERNAL , src_stage_mask : vk :: PipelineStageFlags ::
- COLOR_ATTACHMENT_OUTPUT , dst_stage_mask : vk :: PipelineStageFlags ::
- BOTTOM_OF_PIPE , src_access_mask : vk :: AccessFlags :: COLOR_ATTACHMENT_READ
- | vk :: AccessFlags :: COLOR_ATTACHMENT_WRITE , dst_access_mask : vk ::
- AccessFlags :: MEMORY_READ , dependency_flags : vk :: DependencyFlags ::
- BY_REGION , .. Default :: default ( ) } ) ; } this . main_pipeline_colors .
- push (
- vk :: AttachmentReference {
- attachment : 1u32 , layout : vk :: ImageLayout :: COLOR_ATTACHMENT_OPTIMAL , }
- ) ; this . main_pipeline_depth = Some (
- vk :: AttachmentReference {
- attachment : 1u32 , layout : vk :: ImageLayout ::
- DEPTH_STENCIL_ATTACHMENT_OPTIMAL , } ) ; this . subpasses . push (
- vk :: SubpassDescription :: builder ( ) . color_attachments (
- & this . main_pipeline_colors [ .. ] ) . depth_stencil_attachment (
- this . main_pipeline_depth . as_ref ( ) . unwrap ( ) ) . pipeline_bind_point
- ( vk :: PipelineBindPoint :: GRAPHICS ) . build ( ) ) ; if samples != 1 {
- let len = this . subpasses . len ( ) ; let resolveReference = vk ::
- AttachmentReference {
- attachment : ( dependencies . len ( ) - 1 ) as u32 , layout : vk ::
- ImageLayout :: COLOR_ATTACHMENT_OPTIMAL , } ; this . subpasses [ len - 1 ] .
- color_attachment_count += 1 ; unsafe {
- (
- & mut * (
- this . subpasses [ len - 1 ] . p_color_attachments as * const Vec < vk ::
- AttachmentReference > ) ) . push ( resolveReference ) ; } } let
- renderpass_create_info = vk :: RenderPassCreateInfo :: builder ( ) .
- attachments ( & this . renderpass_attachments [ .. ] ) . subpasses (
- & this . subpasses [ .. ] ) . dependencies ( & this . dependencies [ .. ] ) ;
- this . renderpass = Some (
- unsafe {
- renderer . device ( ) . device ( ) . create_render_pass (
- & renderpass_create_info , None ) } ? ) ; let framebuffers : std :: result ::
- Result < Vec < _ > , _ > = renderer . images ( ) . iter ( ) . map (
- | present_image_view | {
- let framebuffer_attachments = [
- present_image_view . image ( ) , images . depth_image ( ) . depth_image_view
- ( ) ] ; let frame_buffer_create_info = vk :: FramebufferCreateInfo :: builder
- ( ) . render_pass ( * this . renderpass . as_ref ( ) . unwrap ( ) ) .
- attachments ( & framebuffer_attachments ) . width (
- renderer . swapchain ( ) . surface_resolution ( ) . width ) . height (
- renderer . swapchain ( ) . surface_resolution ( ) . height ) . layers ( 1 )
- ; unsafe {
- renderer . device ( ) . device ( ) . create_framebuffer (
- & frame_buffer_create_info , None ) } } ) . collect ( ) ; let framebuffers =
- framebuffers ? ; this . framebuffers = framebuffers ; this . main_pipeline =
- Some ( MainPipeline :: new ( renderer , images . clone ( ) , texture ) ? ) ;
- Ok ( this ) } } pub struct Renderer {
- renderer : vulkan_lib :: Renderer , images : std :: sync :: Arc < Images > ,
- main_renderpass : MainRenderpass } impl Renderer {
- # [ inline ] pub fn new (
- resolution : [ f64 ; 2 ] , samples : u8 , vsync : bool , triple_buffering :
- bool , texture : vulkan_lib :: texture :: Texture ) -> error :: Result < Self
- > {
- use std :: sync :: Arc ; use ash :: vk ; let renderer = vulkan_lib :: Renderer
- :: new ( resolution , samples , vsync , triple_buffering ) ? ; let images =
- Arc :: new ( Images :: new ( & renderer ) ? ) ; let main_renderpass =
- MainRenderpass :: new ( & renderer , images . clone ( ) , samples , texture )
- ? ; Ok ( Renderer { renderer , images , main_renderpass } ) } # [ inline ] pub
- fn main_renderpass ( & self ) -> & MainRenderpass { & self . main_renderpass }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement