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 alternate 3D display modes #13582

Merged
merged 11 commits into from Apr 7, 2023
2 changes: 1 addition & 1 deletion rpcs3/Emu/Cell/Modules/cellAvconfExt.cpp
Expand Up @@ -437,7 +437,7 @@ error_code cellVideoOutGetScreenSize(u32 videoOut, vm::ptr<f32> screenSize)
return CELL_VIDEO_OUT_ERROR_UNSUPPORTED_VIDEO_OUT;
}

if (g_cfg.video.enable_3d)
if (g_cfg.video.stereo_render_mode != stereo_render_mode_options::disabled)
{
// Return Playstation 3D display value
// Some games call this function when 3D is enabled
Expand Down
8 changes: 4 additions & 4 deletions rpcs3/Emu/Cell/Modules/cellVideoOut.cpp
Expand Up @@ -181,7 +181,7 @@ error_code cellVideoOutConfigure(u32 videoOut, vm::ptr<CellVideoOutConfiguration

CellVideoOutResolution res;
if (_IntGetResolutionInfo(config->resolutionId, &res) != CELL_OK ||
(config->resolutionId >= CELL_VIDEO_OUT_RESOLUTION_720_3D_FRAME_PACKING && !g_cfg.video.enable_3d))
(config->resolutionId >= CELL_VIDEO_OUT_RESOLUTION_720_3D_FRAME_PACKING && g_cfg.video.stereo_render_mode == stereo_render_mode_options::disabled))
{
// Resolution not supported
cellSysutil.error("Unusual resolution requested: 0x%x", config->resolutionId);
Expand All @@ -190,7 +190,7 @@ error_code cellVideoOutConfigure(u32 videoOut, vm::ptr<CellVideoOutConfiguration

auto& conf = g_fxo->get<rsx::avconf>();
conf.resolution_id = config->resolutionId;
conf._3d = config->resolutionId >= CELL_VIDEO_OUT_RESOLUTION_720_3D_FRAME_PACKING;
conf.stereo_mode = (config->resolutionId >= CELL_VIDEO_OUT_RESOLUTION_720_3D_FRAME_PACKING) ? g_cfg.video.stereo_render_mode.get() : stereo_render_mode_options::disabled;
conf.aspect = config->aspect;
conf.format = config->format;
conf.scanline_pitch = config->pitch;
Expand Down Expand Up @@ -301,7 +301,7 @@ error_code cellVideoOutGetDeviceInfo(u32 videoOut, u32 deviceIndex, vm::ptr<Cell
info->availableModes[0].resolutionId = ::at32(g_video_out_resolution_id, g_cfg.video.resolution);
info->availableModes[0].scanMode = CELL_VIDEO_OUT_SCAN_MODE_PROGRESSIVE;

if (g_cfg.video.enable_3d && g_cfg.video.resolution == video_resolution::_720)
if (g_cfg.video.stereo_render_mode != stereo_render_mode_options::disabled && g_cfg.video.resolution == video_resolution::_720)
{
// Register 3D-capable display mode
info->availableModes[1] = info->availableModes[0];
Expand Down Expand Up @@ -346,7 +346,7 @@ error_code cellVideoOutGetResolutionAvailability(u32 videoOut, u32 resolutionId,
return not_an_error(1);
}

if (g_cfg.video.enable_3d && g_cfg.video.resolution == video_resolution::_720)
if ((g_cfg.video.stereo_render_mode != stereo_render_mode_options::disabled) && g_cfg.video.resolution == video_resolution::_720)
{
switch (resolutionId)
{
Expand Down
59 changes: 49 additions & 10 deletions rpcs3/Emu/RSX/GL/GLOverlays.cpp
Expand Up @@ -467,30 +467,69 @@ namespace gl
"layout(location=0) in vec2 tc0;\n"
"layout(location=0) out vec4 ocol;\n"
"\n"
"#define STEREO_MODE_DISABLED 0\n"
"#define STEREO_MODE_ANAGLYPH 1\n"
"#define STEREO_MODE_SIDE_BY_SIDE 2\n"
"#define STEREO_MODE_OVER_UNDER 3\n"
"\n"
"vec2 sbs_single_matrix = vec2(2.0,0.4898f);\n"
"vec2 sbs_multi_matrix = vec2(2.0,1.0);\n"
"vec2 ou_single_matrix = vec2(1.0,0.9796f);\n"
"vec2 ou_multi_matrix = vec2(1.0,2.0);\n"
"\n"
"uniform float gamma;\n"
"uniform int limit_range;\n"
"uniform int stereo;\n"
"uniform int stereo_display_mode;\n"
"uniform int stereo_image_count;\n"
"\n"
"vec4 read_source()\n"
"{\n"
" if (stereo == 0) return texture(fs0, tc0);\n"
" if (stereo_display_mode == STEREO_MODE_DISABLED) return texture(fs0, tc0);\n"
"\n"
" vec4 left, right;\n"
" if (stereo_image_count == 2)\n"
" if (stereo_image_count == 1)\n"
" {\n"
" left = texture(fs0, tc0);\n"
" right = texture(fs1, tc0);\n"
" switch (stereo_display_mode)\n"
" {\n"
" case STEREO_MODE_ANAGLYPH:\n"
" left = texture(fs0, tc0 * vec2(1.f, 0.4898f));\n"
" right = texture(fs0, (tc0 * vec2(1.f, 0.4898f)) + vec2(0.f, 0.510204f));\n"
" return vec4(left.r, right.g, right.b, 1.f);\n"
" case STEREO_MODE_SIDE_BY_SIDE:\n"
" if (tc0.x < 0.5) return texture(fs0, tc0* sbs_single_matrix);\n"
" else return texture(fs0, (tc0* sbs_single_matrix) + vec2(-1.f, 0.510204f));\n"
" case STEREO_MODE_OVER_UNDER:\n"
" if (tc0.y < 0.5) return texture(fs0, tc0* ou_single_matrix);\n"
" else return texture(fs0, (tc0* ou_single_matrix) + vec2(0.f, 0.020408f) );\n"
" default:\n" // undefined behavior
" return texture(fs0,tc0);\n"
" }\n"
" }\n"
" else if (stereo_image_count == 2)\n"
" {\n"
" switch (stereo_display_mode)\n"
" {\n"
" case STEREO_MODE_ANAGLYPH:\n"
" left = texture(fs0, tc0);\n"
" right = texture(fs1, tc0);\n"
" return vec4(left.r, right.g, right.b, 1.f);\n"
" case STEREO_MODE_SIDE_BY_SIDE:\n"
" if (tc0.x < 0.5) return texture(fs0,(tc0 * sbs_multi_matrix));\n"
" else return texture(fs1,(tc0 * sbs_multi_matrix) + vec2(-1.f,0.f));\n"
" case STEREO_MODE_OVER_UNDER:\n"
" if (tc0.y < 0.5) return texture(fs0,(tc0 * ou_multi_matrix));\n"
" else return texture(fs1,(tc0 * ou_multi_matrix) + vec2(0.f,-1.f));\n"
" default:\n" // undefined behavior
" return texture(fs0,tc0);\n"
" }\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"
" return vec4(left.r, right.g, right.b, 1.);\n"
" }\n"
"\n"
" return vec4(left.r, right.g, right.b, 1.);\n"
"}\n"
"\n"
"void main()\n"
Expand All @@ -506,7 +545,7 @@ namespace gl
m_input_filter = gl::filter::linear;
}

void video_out_calibration_pass::run(gl::command_context& cmd, const areau& viewport, const rsx::simple_array<GLuint>& source, f32 gamma, bool limited_rgb, bool _3d, gl::filter input_filter)
void video_out_calibration_pass::run(gl::command_context& cmd, const areau& viewport, const rsx::simple_array<GLuint>& source, f32 gamma, bool limited_rgb, stereo_render_mode_options stereo_mode, gl::filter input_filter)
{
if (m_input_filter != input_filter)
{
Expand All @@ -516,7 +555,7 @@ namespace gl
}
program_handle.uniforms["gamma"] = gamma;
program_handle.uniforms["limit_range"] = limited_rgb + 0;
program_handle.uniforms["stereo"] = _3d + 0;
program_handle.uniforms["stereo_display_mode"] = static_cast<u8>(stereo_mode);
program_handle.uniforms["stereo_image_count"] = (source[1] == GL_NONE? 1 : 2);

saved_sampler_state saved(31, m_sampler);
Expand Down
2 changes: 1 addition & 1 deletion rpcs3/Emu/RSX/GL/GLOverlays.h
Expand Up @@ -93,7 +93,7 @@ namespace gl
{
video_out_calibration_pass();

void run(gl::command_context& cmd, const areau& viewport, const rsx::simple_array<GLuint>& source, f32 gamma, bool limited_rgb, bool _3d, gl::filter input_filter);
void run(gl::command_context& cmd, const areau& viewport, const rsx::simple_array<GLuint>& source, f32 gamma, bool limited_rgb, stereo_render_mode_options stereo_mode, gl::filter input_filter);
};

struct rp_ssbo_to_generic_texture : public overlay_pass
Expand Down
8 changes: 4 additions & 4 deletions rpcs3/Emu/RSX/GL/GLPresent.cpp
Expand Up @@ -149,7 +149,7 @@ void GLGSRender::flip(const rsx::display_flip_info_t& info)
if (!buffer_pitch)
buffer_pitch = buffer_width * avconfig.get_bpp();

const u32 video_frame_height = (!avconfig._3d ? avconfig.resolution_y : (avconfig.resolution_y - 30) / 2);
const u32 video_frame_height = (avconfig.stereo_mode == stereo_render_mode_options::disabled? avconfig.resolution_y : ((avconfig.resolution_y - 30) / 2));
buffer_width = std::min(buffer_width, avconfig.resolution_x);
buffer_height = std::min(buffer_height, video_frame_height);
}
Expand Down Expand Up @@ -181,7 +181,7 @@ void GLGSRender::flip(const rsx::display_flip_info_t& info)
const auto image_to_flip_ = get_present_source(&present_info, avconfig);
image_to_flip = image_to_flip_->id();

if (avconfig._3d) [[unlikely]]
if (avconfig.stereo_mode != stereo_render_mode_options::disabled) [[unlikely]]
{
const auto [unused, min_expected_height] = rsx::apply_resolution_scale<true>(RSX_SURFACE_DIMENSION_IGNORED, buffer_height + 30);
if (image_to_flip_->height() < min_expected_height)
Expand Down Expand Up @@ -269,7 +269,7 @@ void GLGSRender::flip(const rsx::display_flip_info_t& info)
// TODO: Implement FSR for OpenGL and remove this fallback to bilinear
const gl::filter filter = g_cfg.video.output_scaling == output_scaling_mode::nearest ? gl::filter::nearest : gl::filter::linear;

if (use_full_rgb_range_output && rsx::fcmp(avconfig.gamma, 1.f) && !avconfig._3d)
if (use_full_rgb_range_output && rsx::fcmp(avconfig.gamma, 1.f) && avconfig.stereo_mode == stereo_render_mode_options::disabled)
{
// Blit source image to the screen
m_flip_fbo.recreate();
Expand All @@ -286,7 +286,7 @@ void GLGSRender::flip(const rsx::display_flip_info_t& info)
const rsx::simple_array<GLuint> images{ image_to_flip, image_to_flip2 };

gl::screen.bind();
m_video_output_pass.run(cmd, areau(aspect_ratio), images, gamma, limited_range, avconfig._3d, filter);
m_video_output_pass.run(cmd, areau(aspect_ratio), images, gamma, limited_range, avconfig.stereo_mode, filter);
}
}

Expand Down
58 changes: 49 additions & 9 deletions rpcs3/Emu/RSX/VK/VKOverlays.cpp
Expand Up @@ -893,33 +893,73 @@ namespace vk
"layout(location=0) in vec2 tc0;\n"
"layout(location=0) out vec4 ocol;\n"
"\n"
"#define STEREO_MODE_DISABLED 0\n"
"#define STEREO_MODE_ANAGLYPH 1\n"
"#define STEREO_MODE_SIDE_BY_SIDE 2\n"
"#define STEREO_MODE_OVER_UNDER 3\n"
"\n"
"vec2 sbs_single_matrix = vec2(2.0,0.4898f);\n"
"vec2 sbs_multi_matrix = vec2(2.0,1.0);\n"
"vec2 ou_single_matrix = vec2(1.0,0.9796f);\n"
"vec2 ou_multi_matrix = vec2(1.0,2.0);\n"
"\n"
"layout(push_constant) uniform static_data\n"
"{\n"
" float gamma;\n"
" int limit_range;\n"
" int stereo;\n"
" int stereo_display_mode;\n"
" int stereo_image_count;\n"
"};\n"
"\n"
"vec4 read_source()\n"
"{\n"
" if (stereo == 0) return texture(fs0, tc0);\n"
" if (stereo_display_mode == STEREO_MODE_DISABLED) return texture(fs0, tc0);\n"
"\n"
" vec4 left, right;\n"
" if (stereo_image_count == 2)\n"
" if (stereo_image_count == 1)\n"
" {\n"
" left = texture(fs0, tc0);\n"
" right = texture(fs1, tc0);\n"
" switch (stereo_display_mode)\n"
" {\n"
" case STEREO_MODE_ANAGLYPH:\n"
" left = texture(fs0, tc0 * vec2(1.f, 0.4898f));\n"
" right = texture(fs0, (tc0 * vec2(1.f, 0.4898f)) + vec2(0.f, 0.510204f));\n"
" return vec4(left.r, right.g, right.b, 1.f);\n"
" case STEREO_MODE_SIDE_BY_SIDE:\n"
" if (tc0.x < 0.5) return texture(fs0, tc0* sbs_single_matrix);\n"
" else return texture(fs0, (tc0* sbs_single_matrix) + vec2(-1.f, 0.510204f));\n"
" case STEREO_MODE_OVER_UNDER:\n"
" if (tc0.y < 0.5) return texture(fs0, tc0* ou_single_matrix);\n"
" else return texture(fs0, (tc0* ou_single_matrix) + vec2(0.f, 0.020408f) );\n"
" default:\n" // undefined behavior
" return texture(fs0,tc0);\n"
" }\n"
" }\n"
" else if (stereo_image_count == 2)\n"
" {\n"
" switch (stereo_display_mode)\n"
" {\n"
" case STEREO_MODE_ANAGLYPH:\n"
" left = texture(fs0, tc0);\n"
" right = texture(fs1, tc0);\n"
" return vec4(left.r, right.g, right.b, 1.f);\n"
" case STEREO_MODE_SIDE_BY_SIDE:\n"
" if (tc0.x < 0.5) return texture(fs0,(tc0 * sbs_multi_matrix));\n"
" else return texture(fs1,(tc0 * sbs_multi_matrix) + vec2(-1.f,0.f));\n"
" case STEREO_MODE_OVER_UNDER:\n"
" if (tc0.y < 0.5) return texture(fs0,(tc0 * ou_multi_matrix));\n"
" else return texture(fs1,(tc0 * ou_multi_matrix) + vec2(0.f,-1.f));\n"
" default:\n" // undefined behavior
" return texture(fs0,tc0);\n"
" }\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"
" return vec4(left.r, right.g, right.b, 1.);\n"
" }\n"
"\n"
" return vec4(left.r, right.g, right.b, 1.);\n"
"}\n"
"\n"
"void main()\n"
Expand Down Expand Up @@ -955,11 +995,11 @@ namespace vk
}

void video_out_calibration_pass::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)
const rsx::simple_array<vk::viewable_image*>& src, f32 gamma, bool limited_rgb, stereo_render_mode_options stereo_mode, VkRenderPass render_pass)
{
config.gamma = gamma;
config.limit_range = limited_rgb? 1 : 0;
config.stereo = _3d? 1 : 0;
config.stereo_display_mode = static_cast<u8>(stereo_mode);
config.stereo_image_count = std::min(::size32(src), 2u);

std::vector<vk::image_view*> views;
Expand Down
4 changes: 2 additions & 2 deletions rpcs3/Emu/RSX/VK/VKOverlays.h
Expand Up @@ -211,7 +211,7 @@ namespace vk
{
float gamma;
int limit_range;
int stereo;
int stereo_display_mode;
int stereo_image_count;
};

Expand All @@ -226,7 +226,7 @@ namespace vk
void update_uniforms(vk::command_buffer& cmd, vk::glsl::program* /*program*/) override;

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);
const rsx::simple_array<vk::viewable_image*>& src, f32 gamma, bool limited_rgb, stereo_render_mode_options stereo_mode, VkRenderPass render_pass);
};

// TODO: Replace with a proper manager
Expand Down
10 changes: 5 additions & 5 deletions rpcs3/Emu/RSX/VK/VKPresent.cpp
Expand Up @@ -460,7 +460,7 @@ void VKGSRender::flip(const rsx::display_flip_info_t& info)
if (!buffer_pitch)
buffer_pitch = buffer_width * avconfig.get_bpp();

const u32 video_frame_height = (!avconfig._3d? avconfig.resolution_y : (avconfig.resolution_y - 30) / 2);
const u32 video_frame_height = (avconfig.stereo_mode == stereo_render_mode_options::disabled? avconfig.resolution_y : ((avconfig.resolution_y - 30) / 2));
buffer_width = std::min(buffer_width, avconfig.resolution_x);
buffer_height = std::min(buffer_height, video_frame_height);
}
Expand All @@ -484,7 +484,7 @@ void VKGSRender::flip(const rsx::display_flip_info_t& info)

image_to_flip = get_present_source(&present_info, avconfig);

if (avconfig._3d) [[unlikely]]
if (avconfig.stereo_mode != stereo_render_mode_options::disabled) [[unlikely]]
{
const auto [unused, min_expected_height] = rsx::apply_resolution_scale<true>(RSX_SURFACE_DIMENSION_IGNORED, buffer_height + 30);
if (image_to_flip->height() < min_expected_height)
Expand Down Expand Up @@ -617,12 +617,12 @@ void VKGSRender::flip(const rsx::display_flip_info_t& info)
{
const bool use_full_rgb_range_output = g_cfg.video.full_rgb_range_output.get();

if (!use_full_rgb_range_output || !rsx::fcmp(avconfig.gamma, 1.f) || avconfig._3d) [[unlikely]]
if (!use_full_rgb_range_output || !rsx::fcmp(avconfig.gamma, 1.f) || avconfig.stereo_mode != stereo_render_mode_options::disabled) [[unlikely]]
{
if (image_to_flip) calibration_src.push_back(image_to_flip);
if (image_to_flip2) calibration_src.push_back(image_to_flip2);

if (m_output_scaling == output_scaling_mode::fsr && !avconfig._3d) // 3D will be implemented later
if (m_output_scaling == output_scaling_mode::fsr && avconfig.stereo_mode == stereo_render_mode_options::disabled) // 3D will be implemented later
{
// Run upscaling pass before the rest of the output effects pipeline
// This can be done with all upscalers but we already get bilinear upscaling for free if we just out the filters directly
Expand Down Expand Up @@ -653,7 +653,7 @@ void VKGSRender::flip(const rsx::display_flip_info_t& info)

vk::get_overlay_pass<vk::video_out_calibration_pass>()->run(
*m_current_command_buffer, areau(aspect_ratio), direct_fbo, calibration_src,
avconfig.gamma, !use_full_rgb_range_output, avconfig._3d, single_target_pass);
avconfig.gamma, !use_full_rgb_range_output, avconfig.stereo_mode, single_target_pass);

direct_fbo->release();
}
Expand Down
2 changes: 1 addition & 1 deletion rpcs3/Emu/RSX/rsx_utils.h
Expand Up @@ -153,7 +153,7 @@ namespace rsx

struct avconf
{
bool _3d = false; // Stereo 3D off
stereo_render_mode_options stereo_mode = stereo_render_mode_options::disabled; // Stereo 3D display mode
u8 format = 0; // XRGB
u8 aspect = 0; // AUTO
u8 resolution_id = 2; // 720p
Expand Down
2 changes: 1 addition & 1 deletion rpcs3/Emu/system_config.h
Expand Up @@ -160,7 +160,7 @@ struct cfg_root : cfg::node
cfg::_bool strict_texture_flushing{ this, "Strict Texture Flushing", false };
cfg::_bool multithreaded_rsx{ this, "Multithreaded RSX", false };
cfg::_bool relaxed_zcull_sync{ this, "Relaxed ZCULL Sync", false };
cfg::_bool enable_3d{ this, "Enable 3D", false };
cfg::_enum<stereo_render_mode_options> stereo_render_mode{ this, "3D Display Mode", stereo_render_mode_options::disabled };
cfg::_bool debug_program_analyser{ this, "Debug Program Analyser", false };
cfg::_bool precise_zpass_count{ this, "Accurate ZCULL stats", true };
cfg::_int<1, 8> consecutive_frames_to_draw{ this, "Consecutive Frames To Draw", 1, true};
Expand Down
17 changes: 17 additions & 0 deletions rpcs3/Emu/system_config_types.cpp
Expand Up @@ -632,6 +632,23 @@ void fmt_class_string<vk_exclusive_fs_mode>::format(std::string& out, u64 arg)
});
}

template <>
void fmt_class_string<stereo_render_mode_options>::format(std::string& out, u64 arg)
{
format_enum(out, arg, [](stereo_render_mode_options value)
{
switch (value)
{
case stereo_render_mode_options::disabled: return "Disabled";
case stereo_render_mode_options::anaglyph: return "Anaglyph";
case stereo_render_mode_options::side_by_side: return "Side-by-Side";
case stereo_render_mode_options::over_under: return "Over-Under";
}

return unknown;
});
}

template <>
void fmt_class_string<output_scaling_mode>::format(std::string& out, u64 arg)
{
Expand Down
8 changes: 8 additions & 0 deletions rpcs3/Emu/system_config_types.h
Expand Up @@ -312,3 +312,11 @@ enum class output_scaling_mode
bilinear,
fsr
};

enum class stereo_render_mode_options
{
disabled,
anaglyph,
side_by_side,
over_under
};