mirror of
				https://git.suyu.dev/suyu/suyu.git
				synced 2025-11-04 12:34:39 +08:00 
			
		
		
		
	VideoCore: Add gaussian filtering.
This commit is contained in:
		
							parent
							
								
									bf01b7993d
								
							
						
					
					
						commit
						9e065b9c7d
					
				@ -67,8 +67,9 @@ enum class ScalingFilter : u32 {
 | 
				
			|||||||
    NearestNeighbor = 0,
 | 
					    NearestNeighbor = 0,
 | 
				
			||||||
    Bilinear = 1,
 | 
					    Bilinear = 1,
 | 
				
			||||||
    Bicubic = 2,
 | 
					    Bicubic = 2,
 | 
				
			||||||
    ScaleForce = 3,
 | 
					    Gaussian = 3,
 | 
				
			||||||
    Fsr = 4,
 | 
					    ScaleForce = 4,
 | 
				
			||||||
 | 
					    Fsr = 5,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct ResolutionScalingInfo {
 | 
					struct ResolutionScalingInfo {
 | 
				
			||||||
 | 
				
			|||||||
@ -19,6 +19,7 @@ set(SHADER_FILES
 | 
				
			|||||||
    pitch_unswizzle.comp
 | 
					    pitch_unswizzle.comp
 | 
				
			||||||
    present_scaleforce.frag
 | 
					    present_scaleforce.frag
 | 
				
			||||||
    present_bicubic.frag
 | 
					    present_bicubic.frag
 | 
				
			||||||
 | 
					    present_gaussian.frag
 | 
				
			||||||
    vulkan_blit_color_float.frag
 | 
					    vulkan_blit_color_float.frag
 | 
				
			||||||
    vulkan_blit_depth_stencil.frag
 | 
					    vulkan_blit_depth_stencil.frag
 | 
				
			||||||
    vulkan_fidelityfx_fsr_easu.comp
 | 
					    vulkan_fidelityfx_fsr_easu.comp
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										74
									
								
								src/video_core/host_shaders/present_gaussian.frag
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								src/video_core/host_shaders/present_gaussian.frag
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,74 @@
 | 
				
			|||||||
 | 
					// Copyright 2019 yuzu Emulator Project
 | 
				
			||||||
 | 
					// Licensed under GPLv2 or any later version
 | 
				
			||||||
 | 
					// Refer to the license.txt file included.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#version 460 core
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef VULKAN
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define BINDING_COLOR_TEXTURE 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#else // ^^^ Vulkan ^^^ // vvv OpenGL vvv
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define BINDING_COLOR_TEXTURE 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					layout (location = 0) in vec2 frag_tex_coord;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					layout (location = 0) out vec4 color;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					layout (binding = BINDING_COLOR_TEXTURE) uniform sampler2D color_texture;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const float offset[3] = float[](0.0, 1.3846153846, 3.2307692308);
 | 
				
			||||||
 | 
					const float weight[3] = float[](0.2270270270, 0.3162162162, 0.0702702703);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					vec4 blurVertical(sampler2D textureSampler, vec2 coord, vec2 norm) {
 | 
				
			||||||
 | 
					    vec4 result = vec4(0.0f);
 | 
				
			||||||
 | 
					    for (int i=1; i<3; i++) {
 | 
				
			||||||
 | 
					        result +=
 | 
				
			||||||
 | 
					            texture(textureSampler, vec2(coord) + (vec2(0.0, offset[i]) * norm))
 | 
				
			||||||
 | 
					                * weight[i];
 | 
				
			||||||
 | 
					        result +=
 | 
				
			||||||
 | 
					            texture(textureSampler, vec2(coord) - (vec2(0.0, offset[i]) * norm))
 | 
				
			||||||
 | 
					                * weight[i];
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return result;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					vec4 blurHorizontal(sampler2D textureSampler, vec2 coord, vec2 norm) {
 | 
				
			||||||
 | 
					    vec4 result = vec4(0.0f);
 | 
				
			||||||
 | 
					    for (int i=1; i<3; i++) {
 | 
				
			||||||
 | 
					        result +=
 | 
				
			||||||
 | 
					            texture(textureSampler, vec2(coord) + (vec2(offset[i], 0.0) * norm))
 | 
				
			||||||
 | 
					                * weight[i];
 | 
				
			||||||
 | 
					        result +=
 | 
				
			||||||
 | 
					            texture(textureSampler, vec2(coord) - (vec2(offset[i], 0.0) * norm))
 | 
				
			||||||
 | 
					                * weight[i];
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return result;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					vec4 blurDiagonal(sampler2D textureSampler, vec2 coord, vec2 norm) {
 | 
				
			||||||
 | 
					    vec4 result = vec4(0.0f);
 | 
				
			||||||
 | 
					    for (int i=1; i<3; i++) {
 | 
				
			||||||
 | 
					        result +=
 | 
				
			||||||
 | 
					            texture(textureSampler, vec2(coord) + (vec2(offset[i], offset[i]) * norm))
 | 
				
			||||||
 | 
					                * weight[i];
 | 
				
			||||||
 | 
					        result +=
 | 
				
			||||||
 | 
					            texture(textureSampler, vec2(coord) - (vec2(offset[i], offset[i]) * norm))
 | 
				
			||||||
 | 
					                * weight[i];
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return result;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void main() {
 | 
				
			||||||
 | 
					    vec3 base = texture(color_texture, vec2(frag_tex_coord)).rgb * weight[0];
 | 
				
			||||||
 | 
					    vec2 tex_offset = 1.0f / textureSize(color_texture, 0);
 | 
				
			||||||
 | 
					    vec3 horizontal = blurHorizontal(color_texture, frag_tex_coord, tex_offset).rgb;
 | 
				
			||||||
 | 
					    vec3 vertical = blurVertical(color_texture, frag_tex_coord, tex_offset).rgb;
 | 
				
			||||||
 | 
					    vec3 diagonalA = blurVertical(color_texture, frag_tex_coord, tex_offset).rgb;
 | 
				
			||||||
 | 
					    vec3 diagonalB = blurVertical(color_texture, frag_tex_coord, -tex_offset).rgb;
 | 
				
			||||||
 | 
					    vec3 combination = mix(mix(horizontal, vertical, 0.5f), mix(diagonalA, diagonalB, 0.5f), 0.5f);
 | 
				
			||||||
 | 
					    color = vec4(combination + base, 1.0f);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -256,6 +256,8 @@ void RendererOpenGL::InitOpenGLObjects() {
 | 
				
			|||||||
    present_vertex = CreateProgram(HostShaders::OPENGL_PRESENT_VERT, GL_VERTEX_SHADER);
 | 
					    present_vertex = CreateProgram(HostShaders::OPENGL_PRESENT_VERT, GL_VERTEX_SHADER);
 | 
				
			||||||
    present_bilinear_fragment = CreateProgram(HostShaders::OPENGL_PRESENT_FRAG, GL_FRAGMENT_SHADER);
 | 
					    present_bilinear_fragment = CreateProgram(HostShaders::OPENGL_PRESENT_FRAG, GL_FRAGMENT_SHADER);
 | 
				
			||||||
    present_bicubic_fragment = CreateProgram(HostShaders::PRESENT_BICUBIC_FRAG, GL_FRAGMENT_SHADER);
 | 
					    present_bicubic_fragment = CreateProgram(HostShaders::PRESENT_BICUBIC_FRAG, GL_FRAGMENT_SHADER);
 | 
				
			||||||
 | 
					    present_gaussian_fragment =
 | 
				
			||||||
 | 
					        CreateProgram(HostShaders::PRESENT_GAUSSIAN_FRAG, GL_FRAGMENT_SHADER);
 | 
				
			||||||
    present_scaleforce_fragment =
 | 
					    present_scaleforce_fragment =
 | 
				
			||||||
        CreateProgram(HostShaders::PRESENT_SCALEFORCE_FRAG, GL_FRAGMENT_SHADER);
 | 
					        CreateProgram(HostShaders::PRESENT_SCALEFORCE_FRAG, GL_FRAGMENT_SHADER);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -359,6 +361,9 @@ void RendererOpenGL::DrawScreen(const Layout::FramebufferLayout& layout) {
 | 
				
			|||||||
    case Settings::ScalingFilter::Bicubic:
 | 
					    case Settings::ScalingFilter::Bicubic:
 | 
				
			||||||
        fragment_handle = present_bicubic_fragment.handle;
 | 
					        fragment_handle = present_bicubic_fragment.handle;
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
 | 
					    case Settings::ScalingFilter::Gaussian:
 | 
				
			||||||
 | 
					        fragment_handle = present_gaussian_fragment.handle;
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
    case Settings::ScalingFilter::ScaleForce:
 | 
					    case Settings::ScalingFilter::ScaleForce:
 | 
				
			||||||
        fragment_handle = present_scaleforce_fragment.handle;
 | 
					        fragment_handle = present_scaleforce_fragment.handle;
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
 | 
				
			|||||||
@ -114,6 +114,7 @@ private:
 | 
				
			|||||||
    OGLProgram present_vertex;
 | 
					    OGLProgram present_vertex;
 | 
				
			||||||
    OGLProgram present_bilinear_fragment;
 | 
					    OGLProgram present_bilinear_fragment;
 | 
				
			||||||
    OGLProgram present_bicubic_fragment;
 | 
					    OGLProgram present_bicubic_fragment;
 | 
				
			||||||
 | 
					    OGLProgram present_gaussian_fragment;
 | 
				
			||||||
    OGLProgram present_scaleforce_fragment;
 | 
					    OGLProgram present_scaleforce_fragment;
 | 
				
			||||||
    OGLFramebuffer screenshot_framebuffer;
 | 
					    OGLFramebuffer screenshot_framebuffer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -18,6 +18,7 @@
 | 
				
			|||||||
#include "core/memory.h"
 | 
					#include "core/memory.h"
 | 
				
			||||||
#include "video_core/gpu.h"
 | 
					#include "video_core/gpu.h"
 | 
				
			||||||
#include "video_core/host_shaders/present_bicubic_frag_spv.h"
 | 
					#include "video_core/host_shaders/present_bicubic_frag_spv.h"
 | 
				
			||||||
 | 
					#include "video_core/host_shaders/present_gaussian_frag_spv.h"
 | 
				
			||||||
#include "video_core/host_shaders/present_scaleforce_frag_spv.h"
 | 
					#include "video_core/host_shaders/present_scaleforce_frag_spv.h"
 | 
				
			||||||
#include "video_core/host_shaders/vulkan_present_frag_spv.h"
 | 
					#include "video_core/host_shaders/vulkan_present_frag_spv.h"
 | 
				
			||||||
#include "video_core/host_shaders/vulkan_present_vert_spv.h"
 | 
					#include "video_core/host_shaders/vulkan_present_vert_spv.h"
 | 
				
			||||||
@ -297,6 +298,9 @@ VkSemaphore VKBlitScreen::Draw(const Tegra::FramebufferConfig& framebuffer,
 | 
				
			|||||||
            case Settings::ScalingFilter::Bicubic:
 | 
					            case Settings::ScalingFilter::Bicubic:
 | 
				
			||||||
                cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, *bicubic_pipeline);
 | 
					                cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, *bicubic_pipeline);
 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
 | 
					            case Settings::ScalingFilter::Gaussian:
 | 
				
			||||||
 | 
					                cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, *gaussian_pipeline);
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
            case Settings::ScalingFilter::ScaleForce:
 | 
					            case Settings::ScalingFilter::ScaleForce:
 | 
				
			||||||
                cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, *scaleforce_pipeline);
 | 
					                cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, *scaleforce_pipeline);
 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
@ -388,6 +392,7 @@ void VKBlitScreen::CreateShaders() {
 | 
				
			|||||||
    vertex_shader = BuildShader(device, VULKAN_PRESENT_VERT_SPV);
 | 
					    vertex_shader = BuildShader(device, VULKAN_PRESENT_VERT_SPV);
 | 
				
			||||||
    bilinear_fragment_shader = BuildShader(device, VULKAN_PRESENT_FRAG_SPV);
 | 
					    bilinear_fragment_shader = BuildShader(device, VULKAN_PRESENT_FRAG_SPV);
 | 
				
			||||||
    bicubic_fragment_shader = BuildShader(device, PRESENT_BICUBIC_FRAG_SPV);
 | 
					    bicubic_fragment_shader = BuildShader(device, PRESENT_BICUBIC_FRAG_SPV);
 | 
				
			||||||
 | 
					    gaussian_fragment_shader = BuildShader(device, PRESENT_GAUSSIAN_FRAG_SPV);
 | 
				
			||||||
    scaleforce_fragment_shader = BuildShader(device, PRESENT_SCALEFORCE_FRAG_SPV);
 | 
					    scaleforce_fragment_shader = BuildShader(device, PRESENT_SCALEFORCE_FRAG_SPV);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -574,6 +579,27 @@ void VKBlitScreen::CreateGraphicsPipeline() {
 | 
				
			|||||||
        },
 | 
					        },
 | 
				
			||||||
    }};
 | 
					    }};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const std::array<VkPipelineShaderStageCreateInfo, 2> gaussian_shader_stages{{
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
 | 
				
			||||||
 | 
					            .pNext = nullptr,
 | 
				
			||||||
 | 
					            .flags = 0,
 | 
				
			||||||
 | 
					            .stage = VK_SHADER_STAGE_VERTEX_BIT,
 | 
				
			||||||
 | 
					            .module = *vertex_shader,
 | 
				
			||||||
 | 
					            .pName = "main",
 | 
				
			||||||
 | 
					            .pSpecializationInfo = nullptr,
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
 | 
				
			||||||
 | 
					            .pNext = nullptr,
 | 
				
			||||||
 | 
					            .flags = 0,
 | 
				
			||||||
 | 
					            .stage = VK_SHADER_STAGE_FRAGMENT_BIT,
 | 
				
			||||||
 | 
					            .module = *gaussian_fragment_shader,
 | 
				
			||||||
 | 
					            .pName = "main",
 | 
				
			||||||
 | 
					            .pSpecializationInfo = nullptr,
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					    }};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const std::array<VkPipelineShaderStageCreateInfo, 2> scaleforce_shader_stages{{
 | 
					    const std::array<VkPipelineShaderStageCreateInfo, 2> scaleforce_shader_stages{{
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
 | 
					            .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
 | 
				
			||||||
@ -733,6 +759,28 @@ void VKBlitScreen::CreateGraphicsPipeline() {
 | 
				
			|||||||
        .basePipelineIndex = 0,
 | 
					        .basePipelineIndex = 0,
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const VkGraphicsPipelineCreateInfo gaussian_pipeline_ci{
 | 
				
			||||||
 | 
					        .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
 | 
				
			||||||
 | 
					        .pNext = nullptr,
 | 
				
			||||||
 | 
					        .flags = 0,
 | 
				
			||||||
 | 
					        .stageCount = static_cast<u32>(gaussian_shader_stages.size()),
 | 
				
			||||||
 | 
					        .pStages = gaussian_shader_stages.data(),
 | 
				
			||||||
 | 
					        .pVertexInputState = &vertex_input_ci,
 | 
				
			||||||
 | 
					        .pInputAssemblyState = &input_assembly_ci,
 | 
				
			||||||
 | 
					        .pTessellationState = nullptr,
 | 
				
			||||||
 | 
					        .pViewportState = &viewport_state_ci,
 | 
				
			||||||
 | 
					        .pRasterizationState = &rasterization_ci,
 | 
				
			||||||
 | 
					        .pMultisampleState = &multisampling_ci,
 | 
				
			||||||
 | 
					        .pDepthStencilState = nullptr,
 | 
				
			||||||
 | 
					        .pColorBlendState = &color_blend_ci,
 | 
				
			||||||
 | 
					        .pDynamicState = &dynamic_state_ci,
 | 
				
			||||||
 | 
					        .layout = *pipeline_layout,
 | 
				
			||||||
 | 
					        .renderPass = *renderpass,
 | 
				
			||||||
 | 
					        .subpass = 0,
 | 
				
			||||||
 | 
					        .basePipelineHandle = 0,
 | 
				
			||||||
 | 
					        .basePipelineIndex = 0,
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const VkGraphicsPipelineCreateInfo scaleforce_pipeline_ci{
 | 
					    const VkGraphicsPipelineCreateInfo scaleforce_pipeline_ci{
 | 
				
			||||||
        .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
 | 
					        .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
 | 
				
			||||||
        .pNext = nullptr,
 | 
					        .pNext = nullptr,
 | 
				
			||||||
@ -757,6 +805,7 @@ void VKBlitScreen::CreateGraphicsPipeline() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    bilinear_pipeline = device.GetLogical().CreateGraphicsPipeline(bilinear_pipeline_ci);
 | 
					    bilinear_pipeline = device.GetLogical().CreateGraphicsPipeline(bilinear_pipeline_ci);
 | 
				
			||||||
    bicubic_pipeline = device.GetLogical().CreateGraphicsPipeline(bicubic_pipeline_ci);
 | 
					    bicubic_pipeline = device.GetLogical().CreateGraphicsPipeline(bicubic_pipeline_ci);
 | 
				
			||||||
 | 
					    gaussian_pipeline = device.GetLogical().CreateGraphicsPipeline(gaussian_pipeline_ci);
 | 
				
			||||||
    scaleforce_pipeline = device.GetLogical().CreateGraphicsPipeline(scaleforce_pipeline_ci);
 | 
					    scaleforce_pipeline = device.GetLogical().CreateGraphicsPipeline(scaleforce_pipeline_ci);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -111,6 +111,7 @@ private:
 | 
				
			|||||||
    vk::ShaderModule vertex_shader;
 | 
					    vk::ShaderModule vertex_shader;
 | 
				
			||||||
    vk::ShaderModule bilinear_fragment_shader;
 | 
					    vk::ShaderModule bilinear_fragment_shader;
 | 
				
			||||||
    vk::ShaderModule bicubic_fragment_shader;
 | 
					    vk::ShaderModule bicubic_fragment_shader;
 | 
				
			||||||
 | 
					    vk::ShaderModule gaussian_fragment_shader;
 | 
				
			||||||
    vk::ShaderModule scaleforce_fragment_shader;
 | 
					    vk::ShaderModule scaleforce_fragment_shader;
 | 
				
			||||||
    vk::DescriptorPool descriptor_pool;
 | 
					    vk::DescriptorPool descriptor_pool;
 | 
				
			||||||
    vk::DescriptorSetLayout descriptor_set_layout;
 | 
					    vk::DescriptorSetLayout descriptor_set_layout;
 | 
				
			||||||
@ -118,6 +119,7 @@ private:
 | 
				
			|||||||
    vk::Pipeline nearest_neightbor_pipeline;
 | 
					    vk::Pipeline nearest_neightbor_pipeline;
 | 
				
			||||||
    vk::Pipeline bilinear_pipeline;
 | 
					    vk::Pipeline bilinear_pipeline;
 | 
				
			||||||
    vk::Pipeline bicubic_pipeline;
 | 
					    vk::Pipeline bicubic_pipeline;
 | 
				
			||||||
 | 
					    vk::Pipeline gaussian_pipeline;
 | 
				
			||||||
    vk::Pipeline scaleforce_pipeline;
 | 
					    vk::Pipeline scaleforce_pipeline;
 | 
				
			||||||
    vk::RenderPass renderpass;
 | 
					    vk::RenderPass renderpass;
 | 
				
			||||||
    std::vector<vk::Framebuffer> framebuffers;
 | 
					    std::vector<vk::Framebuffer> framebuffers;
 | 
				
			||||||
 | 
				
			|||||||
@ -417,6 +417,11 @@
 | 
				
			|||||||
               <string>Bicubic</string>
 | 
					               <string>Bicubic</string>
 | 
				
			||||||
              </property>
 | 
					              </property>
 | 
				
			||||||
             </item>
 | 
					             </item>
 | 
				
			||||||
 | 
					             <item>
 | 
				
			||||||
 | 
					              <property name="text">
 | 
				
			||||||
 | 
					               <string>Gaussian</string>
 | 
				
			||||||
 | 
					              </property>
 | 
				
			||||||
 | 
					             </item>
 | 
				
			||||||
             <item>
 | 
					             <item>
 | 
				
			||||||
              <property name="text">
 | 
					              <property name="text">
 | 
				
			||||||
               <string>ScaleForce</string>
 | 
					               <string>ScaleForce</string>
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user