diff --git a/rpcs3/Emu/RSX/Common/surface_store.h b/rpcs3/Emu/RSX/Common/surface_store.h index 1fcee2b66a..4236581fd7 100644 --- a/rpcs3/Emu/RSX/Common/surface_store.h +++ b/rpcs3/Emu/RSX/Common/surface_store.h @@ -25,52 +25,9 @@ namespace rsx size_t get_packed_pitch(surface_color_format format, u32 width); } - /** - * Helper for surface (ie color and depth stencil render target) management. - * It handles surface creation and storage. Backend should only retrieve pointer to surface. - * It provides 2 methods get_texture_from_*_if_applicable that should be used when an app - * wants to sample a previous surface. - * Please note that the backend is still responsible for creating framebuffer/descriptors - * and need to inform surface_store everytime surface format/size/addresses change. - * - * Since it's a template it requires a trait with the followings: - * - type surface_storage_type which is a structure containing texture. - * - type surface_type which is a pointer to storage_type or a reference. - * - type command_list_type that can be void for backend without command list - * - type download_buffer_object used by issue_download_command and map_downloaded_buffer functions to handle sync - * - * - a member function static surface_type(const surface_storage_type&) that returns underlying surface pointer from a storage type. - * - 2 member functions static surface_storage_type create_new_surface(u32 address, Surface_color_format/Surface_depth_format format, size_t width, size_t height,...) - * used to create a new surface_storage_type holding surface from passed parameters. - * - a member function static prepare_rtt_for_drawing(command_list, surface_type) that makes a sampleable surface a color render target one. - * - a member function static prepare_rtt_for_drawing(command_list, surface_type) that makes a render target surface a sampleable one. - * - a member function static prepare_ds_for_drawing that does the same for depth stencil surface. - * - a member function static prepare_ds_for_sampling that does the same for depth stencil surface. - * - a member function static bool rtt_has_format_width_height(const surface_storage_type&, Surface_color_format surface_color_format, size_t width, size_t height) - * that checks if the given surface has the given format and size - * - a member function static bool ds_has_format_width_height that does the same for ds - * - a member function static download_buffer_object issue_download_command(surface_type, Surface_color_format color_format, size_t width, size_t height,...) - * that generates command to download the given surface to some mappable buffer. - * - a member function static issue_depth_download_command that does the same for depth surface - * - a member function static issue_stencil_download_command that does the same for stencil surface - * - a member function gsl::span map_downloaded_buffer(download_buffer_object, ...) that maps a download_buffer_object - * - a member function static unmap_downloaded_buffer that unmaps it. - */ template struct surface_store { - template - void copy_pitched_src_to_dst(gsl::span dest, gsl::span src, size_t src_pitch_in_bytes, size_t width, size_t height) - { - for (unsigned row = 0; row < height; row++) - { - for (unsigned col = 0; col < width; col++) - dest[col] = src[col]; - src = src.subspan(src_pitch_in_bytes / sizeof(U)); - dest = dest.subspan(width); - } - } - constexpr u32 get_aa_factor_u(surface_antialiasing aa_mode) { return (aa_mode == surface_antialiasing::center_1_sample)? 1 : 2; @@ -92,7 +49,6 @@ namespace rsx using surface_storage_type = typename Traits::surface_storage_type; using surface_type = typename Traits::surface_type; using command_list_type = typename Traits::command_list_type; - using download_buffer_object = typename Traits::download_buffer_object; using surface_overlap_info = surface_overlap_info_t; protected: @@ -122,7 +78,6 @@ namespace rsx template void split_surface_region(command_list_type cmd, u32 address, surface_type prev_surface, u16 width, u16 height, u8 bpp, rsx::surface_antialiasing aa) { -#ifndef INCOMPLETE_SURFACE_CACHE_IMPL auto insert_new_surface = [&]( u32 new_address, deferred_clipped_region& region, @@ -226,13 +181,11 @@ namespace rsx insert_new_surface(baseaddr, copy, m_render_targets_storage); } } -#endif } template void intersect_surface_region(command_list_type cmd, u32 address, surface_type new_surface, surface_type prev_surface) { -#ifndef INCOMPLETE_SURFACE_CACHE_IMPL auto scan_list = [&new_surface, address](const rsx::address_range& mem_range, u64 timestamp_check, std::unordered_map& data) -> std::vector> { @@ -372,7 +325,154 @@ namespace rsx new_surface->set_old_contents_region(region, true); break; } -#endif + } + + template + surface_type bind_surface_address( + command_list_type command_list, + u32 address, + format_type format, + surface_antialiasing antialias, + size_t width, size_t height, size_t pitch, + u8 bpp, + Args&&... extra_params) + { + surface_storage_type old_surface_storage; + surface_storage_type new_surface_storage; + surface_type old_surface = nullptr; + surface_type new_surface = nullptr; + bool store = true; + + address_range *storage_bounds; + std::unordered_map *primary_storage, *secondary_storage; + if constexpr (depth) + { + primary_storage = &m_depth_stencil_storage; + secondary_storage = &m_render_targets_storage; + storage_bounds = &m_depth_stencil_memory_range; + } + else + { + primary_storage = &m_render_targets_storage; + secondary_storage = &m_depth_stencil_storage; + storage_bounds = &m_render_targets_memory_range; + } + + // Check if render target already exists + auto It = primary_storage->find(address); + if (It != primary_storage->end()) + { + surface_storage_type &surface = It->second; + const bool pitch_compatible = Traits::surface_is_pitch_compatible(surface, pitch); + + if (pitch_compatible) + { + // Preserve memory outside the area to be inherited if needed + split_surface_region(command_list, address, Traits::get(surface), (u16)width, (u16)height, bpp, antialias); + } + + if (Traits::surface_matches_properties(surface, format, width, height, antialias)) + { + if (pitch_compatible) + Traits::notify_surface_persist(surface); + else + Traits::invalidate_surface_contents(command_list, Traits::get(surface), address, pitch); + + Traits::prepare_surface_for_drawing(command_list, Traits::get(surface)); + new_surface = Traits::get(surface); + store = false; + } + else + { + old_surface = Traits::get(surface); + old_surface_storage = std::move(surface); + primary_storage->erase(It); + } + } + + if (!new_surface) + { + // Range test + const auto aa_factor_v = get_aa_factor_v(antialias); + rsx::address_range range = rsx::address_range::start_length(address, u32(pitch * height * aa_factor_v)); + *storage_bounds = range.get_min_max(*storage_bounds); + + // Search invalidated resources for a suitable surface + for (auto It = invalidated_resources.begin(); It != invalidated_resources.end(); It++) + { + auto &surface = *It; + if (Traits::surface_matches_properties(surface, format, width, height, antialias, true)) + { + new_surface_storage = std::move(surface); + Traits::notify_surface_reused(new_surface_storage); + + if (old_surface) + { + // Exchange this surface with the invalidated one + Traits::notify_surface_invalidated(old_surface_storage); + surface = std::move(old_surface_storage); + } + else + { + // Iterator is now empty - erase it + invalidated_resources.erase(It); + } + + new_surface = Traits::get(new_surface_storage); + Traits::invalidate_surface_contents(command_list, new_surface, address, pitch); + Traits::prepare_surface_for_drawing(command_list, new_surface); + break; + } + } + } + + // Check for stale storage + if (old_surface != nullptr && new_surface == nullptr) + { + // This was already determined to be invalid and is excluded from testing above + Traits::notify_surface_invalidated(old_surface_storage); + invalidated_resources.push_back(std::move(old_surface_storage)); + } + + if (!new_surface) + { + verify(HERE), store; + new_surface_storage = Traits::create_new_surface(address, format, width, height, pitch, antialias, std::forward(extra_params)...); + new_surface = Traits::get(new_surface_storage); + } + + if (!old_surface) + { + // Remove and preserve if possible any overlapping/replaced surface from the other pool + auto aliased_surface = secondary_storage->find(address); + if (aliased_surface != secondary_storage->end()) + { + old_surface = Traits::get(aliased_surface->second); + + Traits::notify_surface_invalidated(aliased_surface->second); + invalidated_resources.push_back(std::move(aliased_surface->second)); + secondary_storage->erase(aliased_surface); + } + } + + // Check if old_surface is 'new' and avoid intersection + if (old_surface && old_surface->last_use_tag >= write_tag) + { + new_surface->set_old_contents(old_surface); + } + else + { + intersect_surface_region(command_list, address, new_surface, old_surface); + } + + if (store) + { + // New surface was found among invalidated surfaces or created from scratch + (*primary_storage)[address] = std::move(new_surface_storage); + } + + verify(HERE), new_surface->get_spp() == get_format_sample_count(antialias); + return new_surface; } protected: @@ -390,135 +490,10 @@ namespace rsx size_t width, size_t height, size_t pitch, Args&&... extra_params) { - // TODO: Fix corner cases - // This doesn't take overlapping surface(s) into account. - surface_storage_type old_surface_storage; - surface_storage_type new_surface_storage; - surface_type old_surface = nullptr; - surface_type new_surface = nullptr; - bool store = true; - - // Check if render target already exists - auto It = m_render_targets_storage.find(address); - if (It != m_render_targets_storage.end()) - { - surface_storage_type &rtt = It->second; - const bool pitch_compatible = Traits::surface_is_pitch_compatible(rtt, pitch); - - if (pitch_compatible) - { - // Preserve memory outside the area to be inherited if needed - const u8 bpp = get_format_block_size_in_bytes(color_format); - split_surface_region(command_list, address, Traits::get(rtt), (u16)width, (u16)height, bpp, antialias); - } - - if (Traits::rtt_has_format_width_height(rtt, color_format, width, height)) - { - if (pitch_compatible) - Traits::notify_surface_persist(rtt); - else - Traits::invalidate_surface_contents(command_list, Traits::get(rtt), address, pitch); - - Traits::prepare_rtt_for_drawing(command_list, Traits::get(rtt)); - new_surface = Traits::get(rtt); - store = false; - } - else - { - old_surface = Traits::get(rtt); - old_surface_storage = std::move(rtt); - m_render_targets_storage.erase(address); - } - } - - if (!new_surface) - { - // Range test - const auto aa_factor_v = get_aa_factor_v(antialias); - rsx::address_range range = rsx::address_range::start_length(address, u32(pitch * height * aa_factor_v)); - m_render_targets_memory_range = range.get_min_max(m_render_targets_memory_range); - - // Search invalidated resources for a suitable surface - for (auto It = invalidated_resources.begin(); It != invalidated_resources.end(); It++) - { - auto &rtt = *It; - if (Traits::rtt_has_format_width_height(rtt, color_format, width, height, true)) - { - new_surface_storage = std::move(rtt); -#ifndef INCOMPLETE_SURFACE_CACHE_IMPL - Traits::notify_surface_reused(new_surface_storage); -#endif - if (old_surface) - { - // Exchange this surface with the invalidated one - Traits::notify_surface_invalidated(old_surface_storage); - rtt = std::move(old_surface_storage); - } - else - { - // rtt is now empty - erase it - invalidated_resources.erase(It); - } - - new_surface = Traits::get(new_surface_storage); - Traits::invalidate_surface_contents(command_list, new_surface, address, pitch); - Traits::prepare_rtt_for_drawing(command_list, new_surface); - break; - } - } - } - - // Check for stale storage - if (old_surface != nullptr && new_surface == nullptr) - { - // This was already determined to be invalid and is excluded from testing above - Traits::notify_surface_invalidated(old_surface_storage); - invalidated_resources.push_back(std::move(old_surface_storage)); - } - - if (!new_surface) - { - verify(HERE), store; - new_surface_storage = Traits::create_new_surface(address, color_format, width, height, pitch, std::forward(extra_params)...); - new_surface = Traits::get(new_surface_storage); - } - - if (!old_surface) - { - // Remove and preserve if possible any overlapping/replaced depth surface - auto aliased_depth_surface = m_depth_stencil_storage.find(address); - if (aliased_depth_surface != m_depth_stencil_storage.end()) - { - old_surface = Traits::get(aliased_depth_surface->second); - - Traits::notify_surface_invalidated(aliased_depth_surface->second); - invalidated_resources.push_back(std::move(aliased_depth_surface->second)); - m_depth_stencil_storage.erase(aliased_depth_surface); - } - } - -#ifndef INCOMPLETE_SURFACE_CACHE_IMPL - // TODO: This can be done better after refactoring - new_surface->set_aa_mode(antialias); - - // Check if old_surface is 'new' and avoid intersection - if (old_surface && old_surface->last_use_tag >= write_tag) - { - new_surface->set_old_contents(old_surface); - } - else -#endif - { - intersect_surface_region(command_list, address, new_surface, old_surface); - } - - if (store) - { - // New surface was found among invalidated surfaces - m_render_targets_storage[address] = std::move(new_surface_storage); - } - - return new_surface; + return bind_surface_address( + command_list, address, color_format, antialias, + width, height, pitch, get_format_block_size_in_bytes(color_format), + std::forward(extra_params)...); } template @@ -530,127 +505,11 @@ namespace rsx size_t width, size_t height, size_t pitch, Args&&... extra_params) { - surface_storage_type old_surface_storage; - surface_storage_type new_surface_storage; - surface_type old_surface = nullptr; - surface_type new_surface = nullptr; - bool store = true; - - auto It = m_depth_stencil_storage.find(address); - if (It != m_depth_stencil_storage.end()) - { - surface_storage_type &ds = It->second; - const bool pitch_compatible = Traits::surface_is_pitch_compatible(ds, pitch); - - if (pitch_compatible) - { - const u8 bpp = (depth_format == rsx::surface_depth_format::z16)? 2 : 4; - split_surface_region(command_list, address, Traits::get(ds), (u16)width, (u16)height, bpp, antialias); - } - - if (Traits::ds_has_format_width_height(ds, depth_format, width, height)) - { - if (pitch_compatible) - Traits::notify_surface_persist(ds); - else - Traits::invalidate_surface_contents(command_list, Traits::get(ds), address, pitch); - - Traits::prepare_ds_for_drawing(command_list, Traits::get(ds)); - new_surface = Traits::get(ds); - store = false; - } - else - { - old_surface = Traits::get(ds); - old_surface_storage = std::move(ds); - m_depth_stencil_storage.erase(address); - } - } - - if (!new_surface) - { - // Range test - const auto aa_factor_v = get_aa_factor_v(antialias); - rsx::address_range range = rsx::address_range::start_length(address, u32(pitch * height * aa_factor_v)); - m_depth_stencil_memory_range = range.get_min_max(m_depth_stencil_memory_range); - - //Search invalidated resources for a suitable surface - for (auto It = invalidated_resources.begin(); It != invalidated_resources.end(); It++) - { - auto &ds = *It; - if (Traits::ds_has_format_width_height(ds, depth_format, width, height, true)) - { - new_surface_storage = std::move(ds); -#ifndef INCOMPLETE_SURFACE_CACHE_IMPL - Traits::notify_surface_reused(new_surface_storage); -#endif - if (old_surface) - { - //Exchange this surface with the invalidated one - Traits::notify_surface_invalidated(old_surface_storage); - ds = std::move(old_surface_storage); - } - else - invalidated_resources.erase(It); - - new_surface = Traits::get(new_surface_storage); - Traits::prepare_ds_for_drawing(command_list, new_surface); - Traits::invalidate_surface_contents(command_list, new_surface, address, pitch); - break; - } - } - } - - if (old_surface != nullptr && new_surface == nullptr) - { - // This was already determined to be invalid and is excluded from testing above - Traits::notify_surface_invalidated(old_surface_storage); - invalidated_resources.push_back(std::move(old_surface_storage)); - } - - if (!new_surface) - { - verify(HERE), store; - new_surface_storage = Traits::create_new_surface(address, depth_format, width, height, pitch, std::forward(extra_params)...); - new_surface = Traits::get(new_surface_storage); - } - - if (!old_surface) - { - // Remove and preserve if possible any overlapping/replaced color surface - auto aliased_rtt_surface = m_render_targets_storage.find(address); - if (aliased_rtt_surface != m_render_targets_storage.end()) - { - old_surface = Traits::get(aliased_rtt_surface->second); - - Traits::notify_surface_invalidated(aliased_rtt_surface->second); - invalidated_resources.push_back(std::move(aliased_rtt_surface->second)); - m_render_targets_storage.erase(aliased_rtt_surface); - } - } - -#ifndef INCOMPLETE_SURFACE_CACHE_IMPL - // TODO: Forward this to the management functions - new_surface->set_aa_mode(antialias); - - // Check if old_surface is 'new' and avoid intersection - if (old_surface && old_surface->last_use_tag >= write_tag) - { - new_surface->set_old_contents(old_surface); - } - else -#endif - { - intersect_surface_region(command_list, address, new_surface, old_surface); - } - - if (store) - { - // New surface was found among invalidated surfaces - m_depth_stencil_storage[address] = std::move(new_surface_storage); - } - - return new_surface; + return bind_surface_address( + command_list, address, depth_format, antialias, + width, height, pitch, + depth_format == rsx::surface_depth_format::z16? 2 : 4, + std::forward(extra_params)...); } public: /** @@ -679,7 +538,7 @@ namespace rsx ++i, ++count) { auto &rtt = m_bound_render_targets[i]; - Traits::prepare_rtt_for_sampling(command_list, std::get<1>(rtt)); + Traits::prepare_surface_for_sampling(command_list, std::get<1>(rtt)); rtt = std::make_pair(0, nullptr); } @@ -708,40 +567,20 @@ namespace rsx // Same for depth buffer if (std::get<1>(m_bound_depth_stencil) != nullptr) - Traits::prepare_ds_for_sampling(command_list, std::get<1>(m_bound_depth_stencil)); + { + Traits::prepare_surface_for_sampling(command_list, std::get<1>(m_bound_depth_stencil)); + } - m_bound_depth_stencil = std::make_pair(0, nullptr); - - if (!address_z) - return; - - m_bound_depth_stencil = std::make_pair(address_z, - bind_address_as_depth_stencil(command_list, address_z, depth_format, antialias, - clip_width, clip_height, zeta_pitch, std::forward(extra_params)...)); - } - - /** - * Search for given address in stored color surface - * Return an empty surface_type otherwise. - */ - surface_type get_texture_from_render_target_if_applicable(u32 address) - { - auto It = m_render_targets_storage.find(address); - if (It != m_render_targets_storage.end()) - return Traits::get(It->second); - return surface_type(); - } - - /** - * Search for given address in stored depth stencil surface - * Return an empty surface_type otherwise. - */ - surface_type get_texture_from_depth_stencil_if_applicable(u32 address) - { - auto It = m_depth_stencil_storage.find(address); - if (It != m_depth_stencil_storage.end()) - return Traits::get(It->second); - return surface_type(); + if (LIKELY(address_z)) + { + m_bound_depth_stencil = std::make_pair(address_z, + bind_address_as_depth_stencil(command_list, address_z, depth_format, antialias, + clip_width, clip_height, zeta_pitch, std::forward(extra_params)...)); + } + else + { + m_bound_depth_stencil = std::make_pair(0, nullptr); + } } surface_type get_surface_at(u32 address) @@ -757,138 +596,22 @@ namespace rsx fmt::throw_exception("Unreachable" HERE); } - /** - * Get bound color surface raw data. - */ - template - std::array, 4> get_render_targets_data( - surface_color_format color_format, size_t width, size_t height, - Args&& ...args - ) + surface_type get_color_surface_at(u32 address) { - std::array download_data = {}; + auto It = m_render_targets_storage.find(address); + if (It != m_render_targets_storage.end()) + return Traits::get(It->second); - // Issue download commands - for (int i = 0; i < 4; i++) - { - if (std::get<0>(m_bound_render_targets[i]) == 0) - continue; - - surface_type surface_resource = std::get<1>(m_bound_render_targets[i]); - download_data[i] = std::move( - Traits::issue_download_command(surface_resource, color_format, width, height, std::forward(args)...) - ); - } - - std::array, 4> result = {}; - - // Sync and copy data - for (int i = 0; i < 4; i++) - { - if (std::get<0>(m_bound_render_targets[i]) == 0) - continue; - - gsl::span raw_src = Traits::map_downloaded_buffer(download_data[i], std::forward(args)...); - - size_t src_pitch = utility::get_aligned_pitch(color_format, ::narrow(width)); - size_t dst_pitch = utility::get_packed_pitch(color_format, ::narrow(width)); - - result[i].resize(dst_pitch * height); - - // Note: MSVC + GSL doesn't support span -> span for non const span atm - // thus manual conversion - switch (color_format) - { - case surface_color_format::a8b8g8r8: - case surface_color_format::x8b8g8r8_o8b8g8r8: - case surface_color_format::x8b8g8r8_z8b8g8r8: - case surface_color_format::a8r8g8b8: - case surface_color_format::x8r8g8b8_o8r8g8b8: - case surface_color_format::x8r8g8b8_z8r8g8b8: - case surface_color_format::x32: - { - gsl::span> dst_span{ (be_t*)result[i].data(), ::narrow(dst_pitch * height / sizeof(be_t)) }; - copy_pitched_src_to_dst(dst_span, as_const_span(raw_src), src_pitch, width, height); - break; - } - case surface_color_format::b8: - { - gsl::span dst_span{ (u8*)result[i].data(), ::narrow(dst_pitch * height / sizeof(u8)) }; - copy_pitched_src_to_dst(dst_span, as_const_span(raw_src), src_pitch, width, height); - break; - } - case surface_color_format::g8b8: - case surface_color_format::r5g6b5: - case surface_color_format::x1r5g5b5_o1r5g5b5: - case surface_color_format::x1r5g5b5_z1r5g5b5: - { - gsl::span> dst_span{ (be_t*)result[i].data(), ::narrow(dst_pitch * height / sizeof(be_t)) }; - copy_pitched_src_to_dst(dst_span, as_const_span(raw_src), src_pitch, width, height); - break; - } - // Note : may require some big endian swap - case surface_color_format::w32z32y32x32: - { - gsl::span dst_span{ (u128*)result[i].data(), ::narrow(dst_pitch * height / sizeof(u128)) }; - copy_pitched_src_to_dst(dst_span, as_const_span(raw_src), src_pitch, width, height); - break; - } - case surface_color_format::w16z16y16x16: - { - gsl::span dst_span{ (u64*)result[i].data(), ::narrow(dst_pitch * height / sizeof(u64)) }; - copy_pitched_src_to_dst(dst_span, as_const_span(raw_src), src_pitch, width, height); - break; - } - - } - Traits::unmap_downloaded_buffer(download_data[i], std::forward(args)...); - } - return result; + return nullptr; } - /** - * Get bound color surface raw data. - */ - template - std::array, 2> get_depth_stencil_data( - surface_depth_format depth_format, size_t width, size_t height, - Args&& ...args - ) + surface_type get_depth_stencil_surface_at(u32 address) { - std::array, 2> result = {}; - if (std::get<0>(m_bound_depth_stencil) == 0) - return result; - size_t row_pitch = align(width * 4, 256); + auto It = m_depth_stencil_storage.find(address); + if (It != m_depth_stencil_storage.end()) + return Traits::get(It->second); - download_buffer_object stencil_data = {}; - download_buffer_object depth_data = Traits::issue_depth_download_command(std::get<1>(m_bound_depth_stencil), depth_format, width, height, std::forward(args)...); - if (depth_format == surface_depth_format::z24s8) - stencil_data = std::move(Traits::issue_stencil_download_command(std::get<1>(m_bound_depth_stencil), width, height, std::forward(args)...)); - - gsl::span depth_buffer_raw_src = Traits::map_downloaded_buffer(depth_data, std::forward(args)...); - if (depth_format == surface_depth_format::z16) - { - result[0].resize(width * height * 2); - gsl::span dest{ (u16*)result[0].data(), ::narrow(width * height) }; - copy_pitched_src_to_dst(dest, as_const_span(depth_buffer_raw_src), row_pitch, width, height); - } - if (depth_format == surface_depth_format::z24s8) - { - result[0].resize(width * height * 4); - gsl::span dest{ (u32*)result[0].data(), ::narrow(width * height) }; - copy_pitched_src_to_dst(dest, as_const_span(depth_buffer_raw_src), row_pitch, width, height); - } - Traits::unmap_downloaded_buffer(depth_data, std::forward(args)...); - - if (depth_format == surface_depth_format::z16) - return result; - - gsl::span stencil_buffer_raw_src = Traits::map_downloaded_buffer(stencil_data, std::forward(args)...); - result[1].resize(width * height); - gsl::span dest{ (u8*)result[1].data(), ::narrow(width * height) }; - copy_pitched_src_to_dst(dest, as_const_span(stencil_buffer_raw_src), align(width, 256), width, height); - Traits::unmap_downloaded_buffer(stencil_data, std::forward(args)...); - return result; + return nullptr; } /** diff --git a/rpcs3/Emu/RSX/Common/surface_utils.h b/rpcs3/Emu/RSX/Common/surface_utils.h index 5c72dd33c6..aa82644fa4 100644 --- a/rpcs3/Emu/RSX/Common/surface_utils.h +++ b/rpcs3/Emu/RSX/Common/surface_utils.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include "Utilities/types.h" #include "Utilities/geometry.h" @@ -214,6 +214,26 @@ namespace rsx } } + void set_spp(u8 count) + { + switch (count) + { + case 1: + samples_x = samples_y = spp = 1; + break; + case 2: + samples_x = spp = 2; + samples_y = 1; + break; + case 4: + samples_x = samples_y = 2; + spp = 4; + break; + default: + fmt::throw_exception("Unexpected sample count 0x%x", count); + } + } + void set_format(rsx::surface_color_format format) { format_info.gcm_color_format = format; diff --git a/rpcs3/Emu/RSX/GL/GLGSRender.cpp b/rpcs3/Emu/RSX/GL/GLGSRender.cpp index e964f8fad4..57e233bb67 100644 --- a/rpcs3/Emu/RSX/GL/GLGSRender.cpp +++ b/rpcs3/Emu/RSX/GL/GLGSRender.cpp @@ -1655,7 +1655,7 @@ void GLGSRender::flip(int buffer, bool emu_flip) const u32 absolute_address = rsx::get_address(display_buffers[buffer].offset, CELL_GCM_LOCATION_LOCAL); GLuint image = GL_NONE; - if (auto render_target_texture = m_rtts.get_texture_from_render_target_if_applicable(absolute_address)) + if (auto render_target_texture = m_rtts.get_color_surface_at(absolute_address)) { if (render_target_texture->last_use_tag == m_rtts.write_tag) { diff --git a/rpcs3/Emu/RSX/GL/GLRenderTargets.cpp b/rpcs3/Emu/RSX/GL/GLRenderTargets.cpp index 30bd47042f..faaa732768 100644 --- a/rpcs3/Emu/RSX/GL/GLRenderTargets.cpp +++ b/rpcs3/Emu/RSX/GL/GLRenderTargets.cpp @@ -454,23 +454,19 @@ void GLGSRender::init_buffers(rsx::framebuffer_creation_context context, bool sk if (m_gl_texture_cache.get_ro_tex_invalidate_intr()) { - //Invalidate cached sampler state + // Invalidate cached sampler state m_samplers_dirty.store(true); } } std::array, 4> GLGSRender::copy_render_targets_to_memory() { - int clip_w = rsx::method_registers.surface_clip_width(); - int clip_h = rsx::method_registers.surface_clip_height(); - return m_rtts.get_render_targets_data(rsx::method_registers.surface_color(), clip_w, clip_h); + return {}; } std::array, 2> GLGSRender::copy_depth_stencil_buffer_to_memory() { - int clip_w = rsx::method_registers.surface_clip_width(); - int clip_h = rsx::method_registers.surface_clip_height(); - return m_rtts.get_depth_stencil_data(rsx::method_registers.surface_depth_fmt(), clip_w, clip_h); + return {}; } void GLGSRender::read_buffers() diff --git a/rpcs3/Emu/RSX/GL/GLRenderTargets.h b/rpcs3/Emu/RSX/GL/GLRenderTargets.h index 1d12e4428b..c1da2b8f0e 100644 --- a/rpcs3/Emu/RSX/GL/GLRenderTargets.h +++ b/rpcs3/Emu/RSX/GL/GLRenderTargets.h @@ -76,11 +76,6 @@ namespace gl rsx_pitch = pitch; } - u16 get_rsx_pitch() const override - { - return rsx_pitch; - } - bool is_depth_surface() const override { switch (get_internal_format()) @@ -144,7 +139,8 @@ struct gl_render_target_traits std::unique_ptr create_new_surface( u32 address, rsx::surface_color_format surface_color_format, - size_t width, size_t height, size_t pitch + size_t width, size_t height, size_t pitch, + rsx::surface_antialiasing antialias ) { auto format = rsx::internals::surface_color_format_to_gl(surface_color_format); @@ -155,6 +151,7 @@ struct gl_render_target_traits result->set_native_pitch((u16)width * format.channel_count * format.channel_size); result->set_surface_dimensions((u16)width, (u16)height, (u16)pitch); result->set_format(surface_color_format); + result->set_aa_mode(antialias); std::array native_layout = { (GLenum)format.swizzle.a, (GLenum)format.swizzle.r, (GLenum)format.swizzle.g, (GLenum)format.swizzle.b }; result->set_native_component_layout(native_layout); @@ -170,7 +167,8 @@ struct gl_render_target_traits std::unique_ptr create_new_surface( u32 address, rsx::surface_depth_format surface_depth_format, - size_t width, size_t height, size_t pitch + size_t width, size_t height, size_t pitch, + rsx::surface_antialiasing antialias ) { auto format = rsx::internals::surface_depth_format_to_gl(surface_depth_format); @@ -186,6 +184,7 @@ struct gl_render_target_traits result->set_surface_dimensions((u16)width, (u16)height, (u16)pitch); result->set_native_component_layout(native_layout); result->set_format(surface_depth_format); + result->set_aa_mode(antialias); result->memory_usage_flags = rsx::surface_usage_flags::attachment; result->state_flags = rsx::surface_state_flags::erase_bkgnd; @@ -213,6 +212,7 @@ struct gl_render_target_traits sink->state_flags = rsx::surface_state_flags::erase_bkgnd; sink->format_info = ref->format_info; + sink->set_spp(ref->get_spp()); sink->set_native_pitch(prev.width * ref->get_bpp()); sink->set_surface_dimensions(prev.width, prev.height, ref->get_rsx_pitch()); sink->set_native_component_layout(ref->get_native_component_layout()); @@ -231,25 +231,23 @@ struct gl_render_target_traits } static - bool is_compatible_surface(const gl::render_target* surface, const gl::render_target* ref, u16 width, u16 height, u8 /*sample_count*/) + bool is_compatible_surface(const gl::render_target* surface, const gl::render_target* ref, u16 width, u16 height, u8 sample_count) { return (surface->get_internal_format() == ref->get_internal_format() && + surface->get_spp() == sample_count && surface->get_surface_width(rsx::surface_metrics::pixels) >= width && surface->get_surface_height(rsx::surface_metrics::pixels) >= height); } - static void prepare_rtt_for_drawing(gl::command_context&, gl::render_target* rtt) + static + void prepare_surface_for_drawing(gl::command_context&, gl::render_target* surface) { - rtt->memory_usage_flags |= rsx::surface_usage_flags::attachment; + surface->memory_usage_flags |= rsx::surface_usage_flags::attachment; } - static void prepare_ds_for_drawing(gl::command_context&, gl::render_target* ds) - { - ds->memory_usage_flags |= rsx::surface_usage_flags::attachment; - } - - static void prepare_rtt_for_sampling(gl::command_context&, gl::render_target*) {} - static void prepare_ds_for_sampling(gl::command_context&, gl::render_target*) {} + static + void prepare_surface_for_sampling(gl::command_context&, gl::render_target*) + {} static bool surface_is_pitch_compatible(const std::unique_ptr &surface, size_t pitch) @@ -291,63 +289,47 @@ struct gl_render_target_traits } static - bool rtt_has_format_width_height(const std::unique_ptr &rtt, rsx::surface_color_format format, size_t width, size_t height, bool check_refs=false) + bool int_surface_matches_properties( + const std::unique_ptr &surface, + gl::texture::internal_format format, + size_t width, size_t height, + rsx::surface_antialiasing antialias, + bool check_refs = false) { - if (check_refs && rtt->has_refs()) + if (check_refs && surface->has_refs()) return false; + return surface->get_internal_format() == format && + surface->get_spp() == get_format_sample_count(antialias) && + surface->matches_dimensions((u16)width, (u16)height); + } + + static + bool surface_matches_properties( + const std::unique_ptr &surface, + rsx::surface_color_format format, + size_t width, size_t height, + rsx::surface_antialiasing antialias, + bool check_refs=false) + { const auto internal_fmt = rsx::internals::sized_internal_format(format); - return rtt->get_internal_format() == internal_fmt && rtt->matches_dimensions((u16)width, (u16)height); + return int_surface_matches_properties(surface, internal_fmt, width, height, antialias, check_refs); } static - bool ds_has_format_width_height(const std::unique_ptr &ds, rsx::surface_depth_format format, size_t width, size_t height, bool check_refs=false) + bool surface_matches_properties( + const std::unique_ptr &surface, + rsx::surface_depth_format format, + size_t width, size_t height, + rsx::surface_antialiasing antialias, + bool check_refs = false) { - if (check_refs && ds->has_refs()) - return false; - const auto internal_fmt = rsx::internals::surface_depth_format_to_gl(format).internal_format; - return ds->get_internal_format() == internal_fmt && ds->matches_dimensions((u16)width, (u16)height); - } - - // Note : pbo breaks fbo here so use classic texture copy - static std::vector issue_download_command(gl::render_target* color_buffer, rsx::surface_color_format color_format, size_t width, size_t height) - { - auto pixel_format = rsx::internals::surface_color_format_to_gl(color_format); - std::vector result(width * height * pixel_format.channel_count * pixel_format.channel_size); - glBindTexture(GL_TEXTURE_2D, color_buffer->id()); - glGetTexImage(GL_TEXTURE_2D, 0, (GLenum)pixel_format.format, (GLenum)pixel_format.type, result.data()); - return result; - } - - static std::vector issue_depth_download_command(gl::render_target* depth_stencil_buffer, rsx::surface_depth_format depth_format, size_t width, size_t height) - { - std::vector result(width * height * 4); - - auto pixel_format = rsx::internals::surface_depth_format_to_gl(depth_format); - glBindTexture(GL_TEXTURE_2D, depth_stencil_buffer->id()); - glGetTexImage(GL_TEXTURE_2D, 0, (GLenum)pixel_format.format, (GLenum)pixel_format.type, result.data()); - return result; - } - - static std::vector issue_stencil_download_command(gl::render_target*, size_t width, size_t height) - { - std::vector result(width * height * 4); - return result; + return int_surface_matches_properties(surface, internal_fmt, width, height, antialias, check_refs); } static - gsl::span map_downloaded_buffer(const std::vector &buffer) - { - return{ reinterpret_cast(buffer.data()), ::narrow(buffer.size()) }; - } - - static - void unmap_downloaded_buffer(const std::vector &) - { - } - - static gl::render_target* get(const std::unique_ptr &in) + gl::render_target* get(const std::unique_ptr &in) { return in.get(); } diff --git a/rpcs3/Emu/RSX/VK/VKGSRender.cpp b/rpcs3/Emu/RSX/VK/VKGSRender.cpp index 872d18efcb..3d9614570d 100644 --- a/rpcs3/Emu/RSX/VK/VKGSRender.cpp +++ b/rpcs3/Emu/RSX/VK/VKGSRender.cpp @@ -3142,7 +3142,7 @@ void VKGSRender::flip(int buffer, bool emu_flip) { const u32 absolute_address = rsx::get_address(display_buffers[buffer].offset, CELL_GCM_LOCATION_LOCAL); - if (auto render_target_texture = m_rtts.get_texture_from_render_target_if_applicable(absolute_address)) + if (auto render_target_texture = m_rtts.get_color_surface_at(absolute_address)) { if (render_target_texture->last_use_tag == m_rtts.write_tag) { diff --git a/rpcs3/Emu/RSX/VK/VKRenderTargets.h b/rpcs3/Emu/RSX/VK/VKRenderTargets.h index 296b422e27..4468a75281 100644 --- a/rpcs3/Emu/RSX/VK/VKRenderTargets.h +++ b/rpcs3/Emu/RSX/VK/VKRenderTargets.h @@ -161,6 +161,7 @@ namespace rsx u32 address, surface_color_format format, size_t width, size_t height, size_t pitch, + rsx::surface_antialiasing antialias, vk::render_device &device, vk::command_buffer& cmd) { auto fmt = vk::get_compatible_surface_format(format); @@ -181,6 +182,7 @@ namespace rsx change_image_layout(cmd, rtt.get(), VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, vk::get_image_subresource_range(0, 0, 1, 1, VK_IMAGE_ASPECT_COLOR_BIT)); rtt->set_format(format); + rtt->set_aa_mode(antialias); rtt->memory_usage_flags = rsx::surface_usage_flags::attachment; rtt->state_flags = rsx::surface_state_flags::erase_bkgnd; rtt->native_component_map = fmt.second; @@ -198,6 +200,7 @@ namespace rsx u32 address, surface_depth_format format, size_t width, size_t height, size_t pitch, + rsx::surface_antialiasing antialias, vk::render_device &device, vk::command_buffer& cmd) { VkFormat requested_format = vk::get_compatible_depth_surface_format(device.get_formats_support(), format); @@ -222,6 +225,7 @@ namespace rsx ds->set_format(format); + ds->set_aa_mode(antialias); ds->memory_usage_flags= rsx::surface_usage_flags::attachment; ds->state_flags = rsx::surface_state_flags::erase_bkgnd; ds->native_component_map = { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_R }; @@ -264,6 +268,7 @@ namespace rsx ref->info.flags); sink->add_ref(); + sink->set_spp(ref->get_spp()); sink->format_info = ref->format_info; sink->memory_usage_flags = rsx::surface_usage_flags::storage; sink->state_flags = rsx::surface_state_flags::erase_bkgnd; @@ -284,33 +289,30 @@ namespace rsx sink->last_use_tag = ref->last_use_tag; } - static bool is_compatible_surface(const vk::render_target* surface, const vk::render_target* ref, u16 width, u16 height, u8 /*sample_count*/) + static bool is_compatible_surface(const vk::render_target* surface, const vk::render_target* ref, u16 width, u16 height, u8 sample_count) { return (surface->format() == ref->format() && + surface->get_spp() == sample_count && surface->get_surface_width() >= width && surface->get_surface_height() >= height); } - static void prepare_rtt_for_drawing(vk::command_buffer& cmd, vk::render_target *surface) + static void prepare_surface_for_drawing(vk::command_buffer& cmd, vk::render_target *surface) { - surface->change_layout(cmd, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); + if (surface->aspect() == VK_IMAGE_ASPECT_COLOR_BIT) + { + surface->change_layout(cmd, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); + } + else + { + surface->change_layout(cmd, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); + } + surface->frame_tag = 0; surface->memory_usage_flags |= rsx::surface_usage_flags::attachment; } - static void prepare_rtt_for_sampling(vk::command_buffer& cmd, vk::render_target *surface) - { - surface->change_layout(cmd, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); - } - - static void prepare_ds_for_drawing(vk::command_buffer& cmd, vk::render_target *surface) - { - surface->change_layout(cmd, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); - surface->frame_tag = 0; - surface->memory_usage_flags |= rsx::surface_usage_flags::attachment; - } - - static void prepare_ds_for_sampling(vk::command_buffer& cmd, vk::render_target *surface) + static void prepare_surface_for_sampling(vk::command_buffer& cmd, vk::render_target *surface) { surface->change_layout(cmd, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); } @@ -352,63 +354,45 @@ namespace rsx surface->add_ref(); } - static bool rtt_has_format_width_height(const std::unique_ptr &rtt, surface_color_format format, size_t width, size_t height, bool check_refs=false) + static bool int_surface_matches_properties( + const std::unique_ptr &surface, + VkFormat format, + size_t width, size_t height, + rsx::surface_antialiasing antialias, + bool check_refs) { - if (check_refs && rtt->has_refs()) // Surface may still have read refs from data 'copy' - return false; - - VkFormat fmt = vk::get_compatible_surface_format(format).first; - - if (rtt->info.format == fmt && - rtt->matches_dimensions((u16)width, (u16)height)) - return true; - - return false; - } - - static bool ds_has_format_width_height(const std::unique_ptr &ds, surface_depth_format format, size_t width, size_t height, bool check_refs=false) - { - if (check_refs && ds->has_refs()) //Surface may still have read refs from data 'copy' - return false; - - if (ds->matches_dimensions((u16)width, (u16)height)) + if (check_refs && surface->has_refs()) { - //Check format - switch (ds->info.format) - { - case VK_FORMAT_D16_UNORM: - return format == surface_depth_format::z16; - case VK_FORMAT_D24_UNORM_S8_UINT: - case VK_FORMAT_D32_SFLOAT_S8_UINT: - return format == surface_depth_format::z24s8; - } + // Surface may still have read refs from data 'copy' + return false; } - return false; + return (surface->info.format == format && + surface->get_spp() == get_format_sample_count(antialias) && + surface->matches_dimensions((u16)width, (u16)height)); } - static download_buffer_object issue_download_command(surface_type, surface_color_format, size_t /*width*/, size_t /*height*/, ...) + static bool surface_matches_properties( + const std::unique_ptr &surface, + surface_color_format format, + size_t width, size_t height, + rsx::surface_antialiasing antialias, + bool check_refs = false) { - return nullptr; + VkFormat vk_format = vk::get_compatible_surface_format(format).first; + return int_surface_matches_properties(surface, vk_format, width, height, antialias, check_refs); } - static download_buffer_object issue_depth_download_command(surface_type, surface_depth_format, size_t /*width*/, size_t /*height*/, ...) - { - return nullptr; - } - - static download_buffer_object issue_stencil_download_command(surface_type, surface_depth_format, size_t /*width*/, size_t /*height*/, ...) - { - return nullptr; - } - - gsl::span map_downloaded_buffer(download_buffer_object, ...) - { - return {}; - } - - static void unmap_downloaded_buffer(download_buffer_object, ...) + static bool surface_matches_properties( + const std::unique_ptr &surface, + surface_depth_format format, + size_t width, size_t height, + rsx::surface_antialiasing antialias, + bool check_refs = false) { + auto device = vk::get_current_renderer(); + VkFormat vk_format = vk::get_compatible_depth_surface_format(device->get_formats_support(), format); + return int_surface_matches_properties(surface, vk_format, width, height, antialias, check_refs); } static vk::render_target *get(const std::unique_ptr &tex)