rsx: Add anaglyph 3D filter

This commit is contained in:
kd-11 2020-01-07 21:29:37 +03:00 committed by kd-11
parent 6e3406b3f5
commit 1725f7a34b
5 changed files with 151 additions and 27 deletions

View File

@ -154,7 +154,7 @@ private:
void update_draw_state();
GLuint get_present_source(gl::present_surface_info* info, const rsx::avconf* avconfig);
gl::texture* get_present_source(gl::present_surface_info* info, const rsx::avconf* avconfig);
public:
void set_viewport();

View File

@ -740,15 +740,39 @@ namespace gl
fs_src =
"#version 420\n\n"
"layout(binding=31) uniform sampler2D fs0;\n"
"layout(binding=30) uniform sampler2D fs1;\n"
"layout(location=0) in vec2 tc0;\n"
"layout(location=0) out vec4 ocol;\n"
"\n"
"uniform float gamma;\n"
"uniform int limit_range;\n"
"uniform int stereo;\n"
"uniform int stereo_image_count;\n"
"\n"
"vec4 read_source()\n"
"{\n"
" if (stereo == 0) return texture(fs0, tc0);\n"
"\n"
" vec4 left, right;\n"
" if (stereo_image_count == 2)\n"
" {\n"
" left = texture(fs0, tc0);\n"
" right = texture(fs1, tc0);\n"
" }\n"
" else\n"
" {\n"
" vec2 coord_left = tc0 * vec2(1.f, 0.4898f);\n"
" vec2 coord_right = coord_left + vec2(0.f, 0.510204f);\n"
" left = texture(fs0, coord_left);\n"
" right = texture(fs0, coord_right);\n"
" }\n"
"\n"
" return vec4(left.r, right.g, right.b, 1.);\n"
"}\n"
"\n"
"void main()\n"
"{\n"
" vec4 color = texture(fs0, tc0);\n"
" vec4 color = read_source();\n"
" color.rgb = pow(color.rgb, vec3(gamma));\n"
" if (limit_range > 0)\n"
" ocol = ((color * 220.) + 16.) / 255.;\n"
@ -759,13 +783,19 @@ namespace gl
input_filter = GL_LINEAR;
}
void run(const areau& viewport, GLuint source, f32 gamma, bool limited_rgb)
void run(const areau& viewport, const rsx::simple_array<GLuint>& source, f32 gamma, bool limited_rgb, bool _3d)
{
program_handle.uniforms["gamma"] = gamma;
program_handle.uniforms["limit_range"] = limited_rgb + 0;
program_handle.uniforms["stereo"] = _3d + 0;
program_handle.uniforms["stereo_image_count"] = (source[1] == GL_NONE? 1 : 2);
saved_sampler_state saved(31, m_sampler);
glBindTexture(GL_TEXTURE_2D, source);
glBindTexture(GL_TEXTURE_2D, source[0]);
saved_sampler_state saved2(30, m_sampler);
glBindTexture(GL_TEXTURE_2D, source[1]);
overlay_pass::run(viewport, GL_NONE, false, false);
}
};

View File

@ -3,9 +3,9 @@
LOG_CHANNEL(screenshot);
GLuint GLGSRender::get_present_source(gl::present_surface_info* info, const rsx::avconf* avconfig)
gl::texture* GLGSRender::get_present_source(gl::present_surface_info* info, const rsx::avconf* avconfig)
{
GLuint image = GL_NONE;
gl::texture* image = nullptr;
// Check the surface store first
gl::command_context cmd = { gl_state };
@ -45,7 +45,7 @@ GLuint GLGSRender::get_present_source(gl::present_surface_info* info, const rsx:
if (viable)
{
surface->read_barrier(cmd);
image = section.surface->get_surface(rsx::surface_access::read)->id();
image = section.surface->get_surface(rsx::surface_access::read);
info->width = rsx::apply_resolution_scale(std::min(surface_width, static_cast<u16>(info->width)), true);
info->height = rsx::apply_resolution_scale(std::min(surface_height, static_cast<u16>(info->height)), true);
@ -56,7 +56,7 @@ GLuint GLGSRender::get_present_source(gl::present_surface_info* info, const rsx:
{
// Hack - this should be the first location to check for output
// The render might have been done offscreen or in software and a blit used to display
if (const auto tex = surface->get_raw_texture(); tex) image = tex->id();
if (const auto tex = surface->get_raw_texture(); tex) image = tex;
}
if (!image)
@ -76,7 +76,7 @@ GLuint GLGSRender::get_present_source(gl::present_surface_info* info, const rsx:
m_gl_texture_cache.invalidate_range(cmd, range, rsx::invalidation_cause::read);
m_flip_tex_color->copy_from(vm::base(info->address), gl::texture::format::bgra, gl::texture::type::uint_8_8_8_8, unpack_settings);
image = m_flip_tex_color->id();
image = m_flip_tex_color.get();
}
return image;
@ -121,7 +121,7 @@ void GLGSRender::flip(const rsx::display_flip_info_t& info)
// Enable drawing to window backbuffer
gl::screen.bind();
GLuint image_to_flip = GL_NONE;
GLuint image_to_flip = GL_NONE, image_to_flip2 = GL_NONE;
if (info.buffer < display_buffers_count && buffer_width && buffer_height)
{
@ -133,7 +133,29 @@ void GLGSRender::flip(const rsx::display_flip_info_t& info)
present_info.format = av_format;
present_info.address = rsx::get_address(display_buffers[info.buffer].offset, CELL_GCM_LOCATION_LOCAL, HERE);
image_to_flip = get_present_source(&present_info, avconfig);
const auto image_to_flip_ = get_present_source(&present_info, avconfig);
image_to_flip = image_to_flip_->id();
if (avconfig->_3d) [[unlikely]]
{
const auto min_expected_height = rsx::apply_resolution_scale(buffer_height + 30, true);
if (image_to_flip_->height() < min_expected_height)
{
// Get image for second eye
const u32 image_offset = (buffer_height + 30) * buffer_pitch + display_buffers[info.buffer].offset;
present_info.width = buffer_width;
present_info.height = buffer_height;
present_info.address = rsx::get_address(image_offset, CELL_GCM_LOCATION_LOCAL, HERE);
image_to_flip2 = get_present_source(&present_info, avconfig)->id();
}
else
{
// Account for possible insets
buffer_height = std::min<u32>(image_to_flip_->height() - min_expected_height, rsx::apply_resolution_scale(buffer_height, true));
}
}
buffer_width = present_info.width;
buffer_height = present_info.height;
}
@ -194,7 +216,7 @@ void GLGSRender::flip(const rsx::display_flip_info_t& info)
areai screen_area = coordi({}, { static_cast<int>(buffer_width), static_cast<int>(buffer_height) });
if (g_cfg.video.full_rgb_range_output && rsx::fcmp(avconfig->gamma, 1.f))
if (g_cfg.video.full_rgb_range_output && rsx::fcmp(avconfig->gamma, 1.f) && !avconfig->_3d)
{
// Blit source image to the screen
m_flip_fbo.recreate();
@ -208,9 +230,10 @@ void GLGSRender::flip(const rsx::display_flip_info_t& info)
{
const f32 gamma = avconfig->gamma;
const bool limited_range = !g_cfg.video.full_rgb_range_output;
const rsx::simple_array<GLuint> images{ image_to_flip, image_to_flip2 };
gl::screen.bind();
m_video_output_pass.run(areau(aspect_ratio), image_to_flip, gamma, limited_range);
m_video_output_pass.run(areau(aspect_ratio), images, gamma, limited_range, avconfig->_3d);
}
}

View File

@ -1048,9 +1048,11 @@ namespace vk
{
float gamma;
int limit_range;
int stereo;
int stereo_image_count;
};
float data[2];
float data[4];
}
config;
@ -1072,6 +1074,7 @@ namespace vk
fs_src =
"#version 420\n\n"
"layout(set=0, binding=1) uniform sampler2D fs0;\n"
"layout(set=0, binding=2) uniform sampler2D fs1;\n"
"layout(location=0) in vec2 tc0;\n"
"layout(location=0) out vec4 ocol;\n"
"\n"
@ -1079,11 +1082,34 @@ namespace vk
"{\n"
" float gamma;\n"
" int limit_range;\n"
" int stereo;\n"
" int stereo_image_count;\n"
"};\n"
"\n"
"vec4 read_source()\n"
"{\n"
" if (stereo == 0) return texture(fs0, tc0);\n"
"\n"
" vec4 left, right;\n"
" if (stereo_image_count == 2)\n"
" {\n"
" left = texture(fs0, tc0);\n"
" right = texture(fs1, tc0);\n"
" }\n"
" else\n"
" {\n"
" vec2 coord_left = tc0 * vec2(1.f, 0.4898f);\n"
" vec2 coord_right = coord_left + vec2(0.f, 0.510204f);\n"
" left = texture(fs0, coord_left);\n"
" right = texture(fs0, coord_right);\n"
" }\n"
"\n"
" return vec4(left.r, right.g, right.b, 1.);\n"
"}\n"
"\n"
"void main()\n"
"{\n"
" vec4 color = texture(fs0, tc0);\n"
" vec4 color = read_source();\n"
" color.rgb = pow(color.rgb, vec3(gamma));\n"
" if (limit_range > 0)\n"
" ocol = ((color * 220.) + 16.) / 255.;\n"
@ -1094,6 +1120,8 @@ namespace vk
renderpass_config.set_depth_mask(false);
renderpass_config.set_color_mask(0, true, true, true, true);
renderpass_config.set_attachment_count(1);
m_num_usable_samplers = 2;
}
std::vector<VkPushConstantRange> get_push_constants() override
@ -1101,23 +1129,39 @@ namespace vk
VkPushConstantRange constant;
constant.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
constant.offset = 0;
constant.size = 8;
constant.size = 16;
return { constant };
}
void update_uniforms(vk::command_buffer& cmd, vk::glsl::program* /*program*/) override
{
vkCmdPushConstants(cmd, m_pipeline_layout, VK_SHADER_STAGE_FRAGMENT_BIT, 0, 8, config.data);
vkCmdPushConstants(cmd, m_pipeline_layout, VK_SHADER_STAGE_FRAGMENT_BIT, 0, 16, config.data);
}
void run(vk::command_buffer &cmd, const areau& viewport, vk::framebuffer* target, vk::viewable_image* src,
f32 gamma, bool limited_rgb, VkRenderPass render_pass)
void run(vk::command_buffer &cmd, const areau& viewport, vk::framebuffer* target,
const rsx::simple_array<vk::viewable_image*>& src,
f32 gamma, bool limited_rgb, bool _3d, VkRenderPass render_pass)
{
config.gamma = gamma;
config.limit_range = limited_rgb? 1 : 0;
config.stereo = _3d? 1 : 0;
config.stereo_image_count = std::min(::size32(src), 2u);
overlay_pass::run(cmd, viewport, target, { src->get_view(VK_REMAP_IDENTITY, rsx::default_remap_vector) }, render_pass);
std::vector<vk::image_view*> views;
views.reserve(2);
for (auto& img : src)
{
views.push_back(img->get_view(VK_REMAP_IDENTITY, rsx::default_remap_vector));
}
if (views.size() < 2)
{
views.push_back(vk::null_image_view(cmd, VK_IMAGE_VIEW_TYPE_2D));
}
overlay_pass::run(cmd, viewport, target, views, render_pass);
}
};
}

View File

@ -431,7 +431,7 @@ void VKGSRender::flip(const rsx::display_flip_info_t& info)
}
// Scan memory for required data. This is done early to optimize waiting for the driver image acquire below.
vk::image* image_to_flip = nullptr;
vk::image *image_to_flip = nullptr, *image_to_flip2 = nullptr;
if (info.buffer < display_buffers_count && buffer_width && buffer_height)
{
vk::present_surface_info present_info;
@ -442,6 +442,27 @@ void VKGSRender::flip(const rsx::display_flip_info_t& info)
present_info.address = rsx::get_address(display_buffers[info.buffer].offset, CELL_GCM_LOCATION_LOCAL, HERE);
image_to_flip = get_present_source(&present_info, avconfig);
if (avconfig->_3d) [[unlikely]]
{
const auto min_expected_height = rsx::apply_resolution_scale(buffer_height + 30, true);
if (image_to_flip->height() < min_expected_height)
{
// Get image for second eye
const u32 image_offset = (buffer_height + 30) * buffer_pitch + display_buffers[info.buffer].offset;
present_info.width = buffer_width;
present_info.height = buffer_height;
present_info.address = rsx::get_address(image_offset, CELL_GCM_LOCATION_LOCAL, HERE);
image_to_flip2 = get_present_source(&present_info, avconfig);
}
else
{
// Account for possible insets
buffer_height = std::min<u32>(image_to_flip->height() - min_expected_height, rsx::apply_resolution_scale(buffer_height, true));
}
}
buffer_width = present_info.width;
buffer_height = present_info.height;
}
@ -526,7 +547,7 @@ void VKGSRender::flip(const rsx::display_flip_info_t& info)
VkRenderPass single_target_pass = VK_NULL_HANDLE;
vk::framebuffer_holder* direct_fbo = nullptr;
vk::viewable_image* calibration_src = nullptr;
rsx::simple_array<vk::viewable_image*> calibration_src;
if (!image_to_flip || aspect_ratio.width < csize.width || aspect_ratio.height < csize.height)
{
@ -540,13 +561,19 @@ void VKGSRender::flip(const rsx::display_flip_info_t& info)
if (image_to_flip)
{
if (!g_cfg.video.full_rgb_range_output || !rsx::fcmp(avconfig->gamma, 1.f)) [[unlikely]]
if (!g_cfg.video.full_rgb_range_output || !rsx::fcmp(avconfig->gamma, 1.f) || avconfig->_3d) [[unlikely]]
{
calibration_src = dynamic_cast<vk::viewable_image*>(image_to_flip);
verify("Image handle not viewable!" HERE), calibration_src;
calibration_src.push_back(dynamic_cast<vk::viewable_image*>(image_to_flip));
verify("Image not viewable" HERE), calibration_src.front();
if (image_to_flip2)
{
calibration_src.push_back(dynamic_cast<vk::viewable_image*>(image_to_flip2));
verify("Image not viewable" HERE), calibration_src.back();
}
}
if (!calibration_src) [[likely]]
if (calibration_src.empty()) [[likely]]
{
vk::copy_scaled_image(*m_current_command_buffer, image_to_flip->value, target_image, image_to_flip->current_layout, target_layout,
{ 0, 0, static_cast<s32>(buffer_width), static_cast<s32>(buffer_height) }, aspect_ratio, 1, VK_IMAGE_ASPECT_COLOR_BIT, false);
@ -564,7 +591,7 @@ void VKGSRender::flip(const rsx::display_flip_info_t& info)
direct_fbo->add_ref();
image_to_flip->push_layout(*m_current_command_buffer, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
m_video_output_pass->run(*m_current_command_buffer, areau(aspect_ratio), direct_fbo, calibration_src, avconfig->gamma, !g_cfg.video.full_rgb_range_output, single_target_pass);
m_video_output_pass->run(*m_current_command_buffer, areau(aspect_ratio), direct_fbo, calibration_src, avconfig->gamma, !g_cfg.video.full_rgb_range_output, avconfig->_3d, single_target_pass);
image_to_flip->pop_layout(*m_current_command_buffer);
direct_fbo->release();