From 6e3406b3f5372cb4fa707e990c34431c231c0e83 Mon Sep 17 00:00:00 2001 From: kd-11 Date: Tue, 7 Jan 2020 19:07:09 +0300 Subject: [PATCH] video: Allow selection of 3D stereo resolutions --- rpcs3/Emu/Cell/Modules/cellAvconfExt.cpp | 8 ++ rpcs3/Emu/Cell/Modules/cellVideoOut.cpp | 153 +++++++++++++++-------- rpcs3/Emu/RSX/GL/GLPresent.cpp | 3 +- rpcs3/Emu/RSX/VK/VKPresent.cpp | 3 +- rpcs3/Emu/RSX/rsx_utils.h | 1 + rpcs3/Emu/system_config.h | 1 + 6 files changed, 116 insertions(+), 53 deletions(-) diff --git a/rpcs3/Emu/Cell/Modules/cellAvconfExt.cpp b/rpcs3/Emu/Cell/Modules/cellAvconfExt.cpp index 1a58df1f45..572c292b37 100644 --- a/rpcs3/Emu/Cell/Modules/cellAvconfExt.cpp +++ b/rpcs3/Emu/Cell/Modules/cellAvconfExt.cpp @@ -300,6 +300,14 @@ error_code cellVideoOutGetScreenSize(u32 videoOut, vm::ptr screenSize) return CELL_VIDEO_OUT_ERROR_UNSUPPORTED_VIDEO_OUT; } + if (g_cfg.video.enable_3d) + { + // Return Playstation 3D display value + // Some games call this function when 3D is enabled + *screenSize = 24.f; + return CELL_OK; + } + // TODO: Use virtual screen size #ifdef _WIN32 // HDC screen = GetDC(NULL); diff --git a/rpcs3/Emu/Cell/Modules/cellVideoOut.cpp b/rpcs3/Emu/Cell/Modules/cellVideoOut.cpp index 664ae79a70..ff6d97ed07 100644 --- a/rpcs3/Emu/Cell/Modules/cellVideoOut.cpp +++ b/rpcs3/Emu/Cell/Modules/cellVideoOut.cpp @@ -8,6 +8,7 @@ LOG_CHANNEL(cellSysutil); +// NOTE: Unused in this module, but used by gs_frame to determine window size const extern std::unordered_map, value_hash> g_video_out_resolution_map { { video_resolution::_1080, { 1920, 1080 } }, @@ -62,6 +63,41 @@ void fmt_class_string::format(std::string& out, u64 arg) error_code cellVideoOutGetNumberOfDevice(u32 videoOut); +error_code _IntGetResolutionInfo(u8 resolution_id, CellVideoOutResolution* resolution) +{ + // NOTE: Some resolution IDs that return values on hw have unknown resolution enumerants + switch (resolution_id) + { + case CELL_VIDEO_OUT_RESOLUTION_1080: *resolution = { 0x780, 0x438 }; break; + case CELL_VIDEO_OUT_RESOLUTION_720: *resolution = { 0x500, 0x2d0 }; break; + case CELL_VIDEO_OUT_RESOLUTION_480: *resolution = { 0x2d0, 0x1e0 }; break; + case CELL_VIDEO_OUT_RESOLUTION_576: *resolution = { 0x2d0, 0x240 }; break; + case CELL_VIDEO_OUT_RESOLUTION_1600x1080: *resolution = { 0x640, 0x438 }; break; + case CELL_VIDEO_OUT_RESOLUTION_1440x1080: *resolution = { 0x5a0, 0x438 }; break; + case CELL_VIDEO_OUT_RESOLUTION_1280x1080: *resolution = { 0x500, 0x438 }; break; + case CELL_VIDEO_OUT_RESOLUTION_960x1080: *resolution = { 0x3c0, 0x438 }; break; + case 0x64: *resolution = { 0x550, 0x300 }; break; + case CELL_VIDEO_OUT_RESOLUTION_720_3D_FRAME_PACKING: *resolution = { 0x500, 0x5be }; break; + case 0x82: *resolution = { 0x780, 0x438 }; break; + case 0x83: *resolution = { 0x780, 0x89d }; break; + case CELL_VIDEO_OUT_RESOLUTION_640x720_3D_FRAME_PACKING: *resolution = { 0x280, 0x5be }; break; + case CELL_VIDEO_OUT_RESOLUTION_800x720_3D_FRAME_PACKING: *resolution = { 0x320, 0x5be }; break; + case CELL_VIDEO_OUT_RESOLUTION_960x720_3D_FRAME_PACKING: *resolution = { 0x3c0, 0x5be }; break; + case CELL_VIDEO_OUT_RESOLUTION_1024x720_3D_FRAME_PACKING: *resolution = { 0x400, 0x5be }; break; + case CELL_VIDEO_OUT_RESOLUTION_720_DUALVIEW_FRAME_PACKING: *resolution = { 0x500, 0x5be }; break; + case 0x92: *resolution = { 0x780, 0x438 }; break; + case CELL_VIDEO_OUT_RESOLUTION_640x720_DUALVIEW_FRAME_PACKING: *resolution = { 0x280, 0x5be }; break; + case CELL_VIDEO_OUT_RESOLUTION_800x720_DUALVIEW_FRAME_PACKING: *resolution = { 0x320, 0x5be }; break; + case CELL_VIDEO_OUT_RESOLUTION_960x720_DUALVIEW_FRAME_PACKING: *resolution = { 0x3c0, 0x5be }; break; + case CELL_VIDEO_OUT_RESOLUTION_1024x720_DUALVIEW_FRAME_PACKING: *resolution = { 0x400, 0x5be }; break; + case 0xa1: *resolution = { 0x780, 0x438 }; break; + + default: return CELL_VIDEO_OUT_ERROR_ILLEGAL_PARAMETER; + } + + return CELL_OK; +} + error_code cellVideoOutGetState(u32 videoOut, u32 deviceIndex, vm::ptr state) { cellSysutil.trace("cellVideoOutGetState(videoOut=%d, deviceIndex=%d, state=*0x%x)", videoOut, deviceIndex, state); @@ -90,6 +126,7 @@ error_code cellVideoOutGetState(u32 videoOut, u32 deviceIndex, vm::ptrdisplayMode.conversion = CELL_VIDEO_OUT_DISPLAY_CONVERSION_NONE; state->displayMode.aspect = conf->state? conf->aspect : g_video_out_aspect_id.at(g_cfg.video.aspect_ratio); state->displayMode.refreshRates = CELL_VIDEO_OUT_REFRESH_RATE_59_94HZ; + return CELL_OK; } @@ -110,36 +147,15 @@ error_code cellVideoOutGetResolution(u32 resolutionId, vm::ptr config, vm::ptr option, u32 waitForEvent) @@ -161,34 +177,23 @@ error_code cellVideoOutConfigure(u32 videoOut, vm::ptrresolutionId) - { - found = true; - res = ares.first; - break; - } - } - - if (!found) + CellVideoOutResolution res; + if (_IntGetResolutionInfo(config->resolutionId, &res) != CELL_OK || + (config->resolutionId >= CELL_VIDEO_OUT_RESOLUTION_720_3D_FRAME_PACKING && !g_cfg.video.enable_3d)) { + // Resolution not supported cellSysutil.error("Unusual resolution requested: 0x%x", config->resolutionId); return CELL_VIDEO_OUT_ERROR_UNSUPPORTED_DISPLAY_MODE; } - auto& res_info = g_video_out_resolution_map.at(res); - auto conf = g_fxo->get(); conf->resolution_id = config->resolutionId; + conf->_3d = config->resolutionId >= CELL_VIDEO_OUT_RESOLUTION_720_3D_FRAME_PACKING; conf->aspect = config->aspect; conf->format = config->format; conf->scanline_pitch = config->pitch; - conf->resolution_x = u32(res_info.first); - conf->resolution_y = u32(res_info.second); + conf->resolution_x = res.width; + conf->resolution_y = res.height; conf->state = 1; if (conf->aspect == CELL_VIDEO_OUT_ASPECT_AUTO) @@ -197,6 +202,8 @@ error_code cellVideoOutConfigure(u32 videoOut, vm::ptraspect = g_video_out_aspect_id.at(g_cfg.video.aspect_ratio); } + cellSysutil.notice("Selected video resolution 0x%x", config->resolutionId); + return CELL_OK; } @@ -215,7 +222,8 @@ error_code cellVideoOutGetConfiguration(u32 videoOut, vm::ptrget(); conf->state) + { + if (auto conf = g_fxo->get(); conf->state) { config->resolutionId = conf->resolution_id; config->format = conf->format; @@ -227,10 +235,15 @@ error_code cellVideoOutGetConfiguration(u32 videoOut, vm::ptrresolutionId = g_video_out_resolution_id.at(g_cfg.video.resolution); config->format = CELL_VIDEO_OUT_BUFFER_COLOR_FORMAT_X8R8G8B8; config->aspect = g_video_out_aspect_id.at(g_cfg.video.aspect_ratio); - config->pitch = 4 * g_video_out_resolution_map.at(g_cfg.video.resolution).first; + + CellVideoOutResolution res; + verify("Invalid video configuration" HERE), _IntGetResolutionInfo(config->resolutionId, &res) == CELL_OK; + + config->pitch = 4 * res.width; } return CELL_OK; + } case CELL_VIDEO_OUT_SECONDARY: @@ -277,6 +290,16 @@ error_code cellVideoOutGetDeviceInfo(u32 videoOut, u32 deviceIndex, vm::ptravailableModes[0].refreshRates = CELL_VIDEO_OUT_REFRESH_RATE_60HZ | CELL_VIDEO_OUT_REFRESH_RATE_59_94HZ; info->availableModes[0].resolutionId = g_video_out_resolution_id.at(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) + { + // Register 3D-capable display mode + info->availableModes[1] = info->availableModes[0]; + info->availableModes[1].conversion = CELL_VIDEO_OUT_DISPLAY_CONVERSION_TO_720_3D_FRAME_PACKING; + info->availableModes[1].resolutionId = CELL_VIDEO_OUT_RESOLUTION_720_3D_FRAME_PACKING; + info->availableModeCount++; + } + return CELL_OK; } @@ -299,10 +322,38 @@ error_code cellVideoOutGetResolutionAvailability(u32 videoOut, u32 resolutionId, switch (videoOut) { - case CELL_VIDEO_OUT_PRIMARY: return not_an_error( - resolutionId == g_video_out_resolution_id.at(g_cfg.video.resolution) + 0u - && (aspect == CELL_VIDEO_OUT_ASPECT_AUTO || aspect == g_video_out_aspect_id.at(g_cfg.video.aspect_ratio) + 0u) - ); + case CELL_VIDEO_OUT_PRIMARY: + { + // NOTE: Result is boolean + if (aspect != CELL_VIDEO_OUT_ASPECT_AUTO && aspect != static_cast(g_video_out_aspect_id.at(g_cfg.video.aspect_ratio))) + { + return not_an_error(0); + } + + if (resolutionId == static_cast(g_video_out_resolution_id.at(g_cfg.video.resolution))) + { + // Perfect match + return not_an_error(1); + } + + if (g_cfg.video.enable_3d && g_cfg.video.resolution == video_resolution::_720) + { + switch (resolutionId) + { + case CELL_VIDEO_OUT_RESOLUTION_720_3D_FRAME_PACKING: + case CELL_VIDEO_OUT_RESOLUTION_1024x720_3D_FRAME_PACKING: + case CELL_VIDEO_OUT_RESOLUTION_960x720_3D_FRAME_PACKING: + case CELL_VIDEO_OUT_RESOLUTION_800x720_3D_FRAME_PACKING: + case CELL_VIDEO_OUT_RESOLUTION_640x720_3D_FRAME_PACKING: + return not_an_error(1); + default: + break; + } + } + + return not_an_error(0); + } + case CELL_VIDEO_OUT_SECONDARY: return not_an_error(0); } diff --git a/rpcs3/Emu/RSX/GL/GLPresent.cpp b/rpcs3/Emu/RSX/GL/GLPresent.cpp index a7b121287f..22d49e2a17 100644 --- a/rpcs3/Emu/RSX/GL/GLPresent.cpp +++ b/rpcs3/Emu/RSX/GL/GLPresent.cpp @@ -104,8 +104,9 @@ 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); buffer_width = std::min(buffer_width, avconfig->resolution_x); - buffer_height = std::min(buffer_height, avconfig->resolution_y); + buffer_height = std::min(buffer_height, video_frame_height); } else { diff --git a/rpcs3/Emu/RSX/VK/VKPresent.cpp b/rpcs3/Emu/RSX/VK/VKPresent.cpp index 2878b491da..7d98b063b5 100644 --- a/rpcs3/Emu/RSX/VK/VKPresent.cpp +++ b/rpcs3/Emu/RSX/VK/VKPresent.cpp @@ -419,8 +419,9 @@ 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); buffer_width = std::min(buffer_width, avconfig->resolution_x); - buffer_height = std::min(buffer_height, avconfig->resolution_y); + buffer_height = std::min(buffer_height, video_frame_height); } else { diff --git a/rpcs3/Emu/RSX/rsx_utils.h b/rpcs3/Emu/RSX/rsx_utils.h index 2bb7ab150a..29cce939a2 100644 --- a/rpcs3/Emu/RSX/rsx_utils.h +++ b/rpcs3/Emu/RSX/rsx_utils.h @@ -142,6 +142,7 @@ namespace rsx struct avconf { + bool _3d = false; // Stereo 3D off u8 format = 0; // XRGB u8 aspect = 0; // AUTO u8 resolution_id = 2; // 720p diff --git a/rpcs3/Emu/system_config.h b/rpcs3/Emu/system_config.h index 36eac3566f..126fd21766 100644 --- a/rpcs3/Emu/system_config.h +++ b/rpcs3/Emu/system_config.h @@ -125,6 +125,7 @@ struct cfg_root : cfg::node cfg::_bool disable_native_float16{ this, "Disable native float16 support", 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::_int<1, 8> consequtive_frames_to_draw{ this, "Consecutive Frames To Draw", 1 }; cfg::_int<1, 8> consequtive_frames_to_skip{ this, "Consecutive Frames To Skip", 1 }; cfg::_int<50, 800> resolution_scale_percent{ this, "Resolution Scale", 100 };