mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-04-21 12:05:23 +00:00
vk: Implement display output format correction
This commit is contained in:
parent
2369266b8a
commit
acd3fd0c3e
4 changed files with 111 additions and 39 deletions
|
@ -304,6 +304,7 @@ namespace vk
|
|||
u32 width;
|
||||
u32 height;
|
||||
u32 pitch;
|
||||
u8 eye;
|
||||
};
|
||||
|
||||
struct draw_call_t
|
||||
|
|
|
@ -15,6 +15,23 @@
|
|||
extern atomic_t<bool> g_user_asked_for_screenshot;
|
||||
extern atomic_t<recording_mode> g_recording_mode;
|
||||
|
||||
namespace
|
||||
{
|
||||
VkFormat RSX_display_format_to_vk_format(u8 format)
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
default:
|
||||
rsx_log.error("Unhandled video output format 0x%x", static_cast<s32>(format));
|
||||
[[fallthrough]];
|
||||
case CELL_VIDEO_OUT_BUFFER_COLOR_FORMAT_X8R8G8B8:
|
||||
return VK_FORMAT_B8G8R8A8_UNORM;
|
||||
case CELL_VIDEO_OUT_BUFFER_COLOR_FORMAT_X8B8G8R8:
|
||||
return VK_FORMAT_R8G8B8A8_UNORM;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VKGSRender::reinitialize_swapchain()
|
||||
{
|
||||
m_swapchain_dims.width = m_frame->client_width();
|
||||
|
@ -277,10 +294,13 @@ void VKGSRender::frame_context_cleanup(vk::frame_context_t *ctx)
|
|||
vk::advance_completed_frame_counter();
|
||||
}
|
||||
|
||||
vk::viewable_image* VKGSRender::get_present_source(vk::present_surface_info* info, const rsx::avconf& avconfig)
|
||||
vk::viewable_image* VKGSRender::get_present_source(/* inout */ vk::present_surface_info* info, const rsx::avconf& avconfig)
|
||||
{
|
||||
vk::viewable_image* image_to_flip = nullptr;
|
||||
|
||||
// @FIXME: This entire function needs to be rewritten to go through the texture cache's "upload_texture" routine.
|
||||
// That method is not a 1:1 replacement due to handling of insets that is done differently here.
|
||||
|
||||
// Check the surface store first
|
||||
const auto format_bpp = rsx::get_format_block_size_in_bytes(info->format);
|
||||
const auto overlap_info = m_rtts.get_merged_texture_memory_region(*m_current_command_buffer,
|
||||
|
@ -333,7 +353,12 @@ vk::viewable_image* VKGSRender::get_present_source(vk::present_surface_info* inf
|
|||
image_to_flip = dynamic_cast<vk::viewable_image*>(surface->get_raw_texture());
|
||||
}
|
||||
|
||||
if (!image_to_flip)
|
||||
// The correct output format is determined by the AV configuration set in CellVideoOutConfigure by the game.
|
||||
// 99.9% of the time, this will match the backbuffer fbo format used in rendering/compositing the output.
|
||||
// But in some cases, let's just say some devs are creative.
|
||||
const auto expected_format = RSX_display_format_to_vk_format(avconfig.format);
|
||||
|
||||
if (!image_to_flip) [[ unlikely ]]
|
||||
{
|
||||
// Read from cell
|
||||
const auto range = utils::address_range::start_length(info->address, info->pitch * info->height);
|
||||
|
@ -354,22 +379,35 @@ vk::viewable_image* VKGSRender::get_present_source(vk::present_surface_info* inf
|
|||
flush_command_queue();
|
||||
}
|
||||
|
||||
VkFormat format;
|
||||
switch (avconfig.format)
|
||||
{
|
||||
default:
|
||||
rsx_log.error("Unhandled video output format 0x%x", avconfig.format);
|
||||
[[fallthrough]];
|
||||
case CELL_VIDEO_OUT_BUFFER_COLOR_FORMAT_X8R8G8B8:
|
||||
format = VK_FORMAT_B8G8R8A8_UNORM;
|
||||
break;
|
||||
case CELL_VIDEO_OUT_BUFFER_COLOR_FORMAT_X8B8G8R8:
|
||||
format = VK_FORMAT_R8G8B8A8_UNORM;
|
||||
break;
|
||||
}
|
||||
|
||||
m_texture_cache.invalidate_range(*m_current_command_buffer, range, rsx::invalidation_cause::read);
|
||||
image_to_flip = m_texture_cache.upload_image_simple(*m_current_command_buffer, format, info->address, info->width, info->height, info->pitch);
|
||||
image_to_flip = m_texture_cache.upload_image_simple(*m_current_command_buffer, expected_format, info->address, info->width, info->height, info->pitch);
|
||||
}
|
||||
else if (image_to_flip->format() != expected_format)
|
||||
{
|
||||
// Devs are being creative. Force-cast this to the proper pixel layout.
|
||||
auto dst_img = m_texture_cache.create_temporary_subresource_storage(
|
||||
RSX_FORMAT_CLASS_COLOR, expected_format, info->width, info->height, 1, 1, 1,
|
||||
VK_IMAGE_TYPE_2D, 0, VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
|
||||
|
||||
if (dst_img)
|
||||
{
|
||||
const areai src_rect = { 0, 0, static_cast<int>(info->width), static_cast<int>(info->height) };
|
||||
const areai dst_rect = src_rect;
|
||||
|
||||
dst_img->change_layout(*m_current_command_buffer, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
|
||||
|
||||
if (vk::formats_are_bitcast_compatible(dst_img.get(), image_to_flip))
|
||||
{
|
||||
vk::copy_image(*m_current_command_buffer, image_to_flip, dst_img.get(), src_rect, dst_rect, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
vk::copy_image_typeless(*m_current_command_buffer, image_to_flip, dst_img.get(), src_rect, dst_rect, 1);
|
||||
}
|
||||
|
||||
image_to_flip = dst_img.get();
|
||||
m_texture_cache.dispose_reusable_image(dst_img);
|
||||
}
|
||||
}
|
||||
|
||||
return image_to_flip;
|
||||
|
@ -471,13 +509,15 @@ void VKGSRender::flip(const rsx::display_flip_info_t& info)
|
|||
vk::viewable_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;
|
||||
present_info.width = buffer_width;
|
||||
present_info.height = buffer_height;
|
||||
present_info.pitch = buffer_pitch;
|
||||
present_info.format = av_format;
|
||||
present_info.address = rsx::get_address(display_buffers[info.buffer].offset, CELL_GCM_LOCATION_LOCAL);
|
||||
|
||||
vk::present_surface_info present_info
|
||||
{
|
||||
.address = rsx::get_address(display_buffers[info.buffer].offset, CELL_GCM_LOCATION_LOCAL),
|
||||
.format = av_format,
|
||||
.width = buffer_width,
|
||||
.height = buffer_height,
|
||||
.pitch = buffer_pitch,
|
||||
.eye = 0
|
||||
};
|
||||
image_to_flip = get_present_source(&present_info, avconfig);
|
||||
|
||||
if (avconfig.stereo_mode != stereo_render_mode_options::disabled) [[unlikely]]
|
||||
|
@ -490,6 +530,7 @@ void VKGSRender::flip(const rsx::display_flip_info_t& info)
|
|||
present_info.width = buffer_width;
|
||||
present_info.height = buffer_height;
|
||||
present_info.address = rsx::get_address(image_offset, CELL_GCM_LOCATION_LOCAL);
|
||||
present_info.eye = 1;
|
||||
|
||||
image_to_flip2 = get_present_source(&present_info, avconfig);
|
||||
}
|
||||
|
|
|
@ -576,6 +576,38 @@ namespace vk
|
|||
return {};
|
||||
}
|
||||
|
||||
std::unique_ptr<vk::viewable_image> texture_cache::create_temporary_subresource_storage(
|
||||
rsx::format_class format_class, VkFormat format,
|
||||
u16 width, u16 height, u16 depth, u16 layers, u8 mips,
|
||||
VkImageType image_type, VkFlags image_flags, VkFlags usage_flags)
|
||||
{
|
||||
auto image = find_cached_image(format, width, height, depth, mips, image_type, image_flags, usage_flags, VK_SHARING_MODE_EXCLUSIVE);
|
||||
|
||||
if (!image)
|
||||
{
|
||||
image = std::make_unique<vk::viewable_image>(*vk::get_current_renderer(), m_memory_types.device_local, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
|
||||
image_type,
|
||||
format,
|
||||
width, height, depth, mips, layers, VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_LAYOUT_UNDEFINED,
|
||||
VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, image_flags | VK_IMAGE_CREATE_ALLOW_NULL_RPCS3,
|
||||
VMM_ALLOCATION_POOL_TEXTURE_CACHE, format_class);
|
||||
|
||||
if (!image->value)
|
||||
{
|
||||
// OOM, bail
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
void texture_cache::dispose_reusable_image(std::unique_ptr<vk::viewable_image>& image)
|
||||
{
|
||||
auto disposable = vk::disposable_t::make(new cached_image_reference_t(this, image));
|
||||
vk::get_resource_manager()->dispose(disposable);
|
||||
}
|
||||
|
||||
vk::image_view* texture_cache::create_temporary_subresource_view_impl(vk::command_buffer& cmd, vk::image* source, VkImageType image_type, VkImageViewType view_type,
|
||||
u32 gcm_format, u16 x, u16 y, u16 w, u16 h, u16 d, u8 mips, const rsx::texture_channel_remap_t& remap_vector, bool copy)
|
||||
{
|
||||
|
@ -584,22 +616,13 @@ namespace vk
|
|||
const VkFormat dst_format = vk::get_compatible_sampler_format(m_formats_support, gcm_format);
|
||||
const u16 layers = (view_type == VK_IMAGE_VIEW_TYPE_CUBE) ? 6 : 1;
|
||||
|
||||
auto image = find_cached_image(dst_format, w, h, d, mips, image_type, image_flags, usage_flags, VK_SHARING_MODE_EXCLUSIVE);
|
||||
// Provision
|
||||
auto image = create_temporary_subresource_storage(rsx::classify_format(gcm_format), dst_format, w, h, d, layers, mips, image_type, image_flags, usage_flags);
|
||||
|
||||
// OOM?
|
||||
if (!image)
|
||||
{
|
||||
image = std::make_unique<vk::viewable_image>(*vk::get_current_renderer(), m_memory_types.device_local, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
|
||||
image_type,
|
||||
dst_format,
|
||||
w, h, d, mips, layers, VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_LAYOUT_UNDEFINED,
|
||||
VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, image_flags | VK_IMAGE_CREATE_ALLOW_NULL_RPCS3,
|
||||
VMM_ALLOCATION_POOL_TEXTURE_CACHE, rsx::classify_format(gcm_format));
|
||||
|
||||
if (!image->value)
|
||||
{
|
||||
// OOM, bail
|
||||
return nullptr;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// This method is almost exclusively used to work on framebuffer resources
|
||||
|
@ -1449,9 +1472,9 @@ namespace vk
|
|||
|
||||
vk::change_image_layout(cmd, image.get(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
|
||||
|
||||
// Fully dispose immediately. These immages aren't really reusable right now.
|
||||
auto result = image.get();
|
||||
auto disposable = vk::disposable_t::make(new cached_image_reference_t(this, image));
|
||||
vk::get_resource_manager()->dispose(disposable);
|
||||
vk::get_resource_manager()->dispose(image);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -504,6 +504,13 @@ namespace vk
|
|||
|
||||
void destroy() override;
|
||||
|
||||
std::unique_ptr<vk::viewable_image> create_temporary_subresource_storage(
|
||||
rsx::format_class format_class, VkFormat format,
|
||||
u16 width, u16 height, u16 depth, u16 layers, u8 mips,
|
||||
VkImageType image_type, VkFlags image_flags, VkFlags usage_flags);
|
||||
|
||||
void dispose_reusable_image(std::unique_ptr<vk::viewable_image>& tex);
|
||||
|
||||
bool is_depth_texture(u32 rsx_address, u32 rsx_size) override;
|
||||
|
||||
void on_frame_end() override;
|
||||
|
|
Loading…
Add table
Reference in a new issue