rsx: Refactoring and cleanup after d3d12 separation

- Remove deprecated functionality
- Refactor to share code between common routines
This commit is contained in:
kd-11 2019-05-21 20:56:48 +03:00 committed by kd-11
parent db5d56a22d
commit 655eff29e8
7 changed files with 298 additions and 593 deletions

View file

@ -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<const gsl::byte> map_downloaded_buffer(download_buffer_object, ...) that maps a download_buffer_object
* - a member function static unmap_downloaded_buffer that unmaps it.
*/
template<typename Traits>
struct surface_store
{
template<typename T, typename U>
void copy_pitched_src_to_dst(gsl::span<T> dest, gsl::span<const U> 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<surface_type>;
protected:
@ -122,7 +78,6 @@ namespace rsx
template <bool is_depth_surface>
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<surface_type>& region,
@ -226,13 +181,11 @@ namespace rsx
insert_new_surface(baseaddr, copy, m_render_targets_storage);
}
}
#endif
}
template <bool is_depth_surface>
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<u32, surface_storage_type>& data) -> std::vector<std::pair<u32, surface_type>>
{
@ -372,7 +325,154 @@ namespace rsx
new_surface->set_old_contents_region(region, true);
break;
}
#endif
}
template <bool depth, typename format_type, typename ...Args>
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<u32, surface_storage_type> *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<depth>(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<Args>(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<depth>(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<false>(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<Args>(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<false>(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<false>(
command_list, address, color_format, antialias,
width, height, pitch, get_format_block_size_in_bytes(color_format),
std::forward<Args>(extra_params)...);
}
template <typename ...Args>
@ -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<true>(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<Args>(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<true>(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<true>(
command_list, address, depth_format, antialias,
width, height, pitch,
depth_format == rsx::surface_depth_format::z16? 2 : 4,
std::forward<Args>(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));
m_bound_depth_stencil = std::make_pair(0, nullptr);
if (!address_z)
return;
{
Traits::prepare_surface_for_sampling(command_list, std::get<1>(m_bound_depth_stencil));
}
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<Args>(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)
else
{
auto It = m_render_targets_storage.find(address);
if (It != m_render_targets_storage.end())
return Traits::get(It->second);
return surface_type();
m_bound_depth_stencil = std::make_pair(0, nullptr);
}
/**
* 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();
}
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 <typename... Args>
std::array<std::vector<gsl::byte>, 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_buffer_object, 4> 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&&>(args)...)
);
return nullptr;
}
std::array<std::vector<gsl::byte>, 4> result = {};
// Sync and copy data
for (int i = 0; i < 4; i++)
surface_type get_depth_stencil_surface_at(u32 address)
{
if (std::get<0>(m_bound_render_targets[i]) == 0)
continue;
auto It = m_depth_stencil_storage.find(address);
if (It != m_depth_stencil_storage.end())
return Traits::get(It->second);
gsl::span<const gsl::byte> raw_src = Traits::map_downloaded_buffer(download_data[i], std::forward<Args&&>(args)...);
size_t src_pitch = utility::get_aligned_pitch(color_format, ::narrow<u32>(width));
size_t dst_pitch = utility::get_packed_pitch(color_format, ::narrow<u32>(width));
result[i].resize(dst_pitch * height);
// Note: MSVC + GSL doesn't support span<byte> -> span<T> 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<be_t<u32>> dst_span{ (be_t<u32>*)result[i].data(), ::narrow<int>(dst_pitch * height / sizeof(be_t<u32>)) };
copy_pitched_src_to_dst(dst_span, as_const_span<const u32>(raw_src), src_pitch, width, height);
break;
}
case surface_color_format::b8:
{
gsl::span<u8> dst_span{ (u8*)result[i].data(), ::narrow<int>(dst_pitch * height / sizeof(u8)) };
copy_pitched_src_to_dst(dst_span, as_const_span<const u8>(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<be_t<u16>> dst_span{ (be_t<u16>*)result[i].data(), ::narrow<int>(dst_pitch * height / sizeof(be_t<u16>)) };
copy_pitched_src_to_dst(dst_span, as_const_span<const u16>(raw_src), src_pitch, width, height);
break;
}
// Note : may require some big endian swap
case surface_color_format::w32z32y32x32:
{
gsl::span<u128> dst_span{ (u128*)result[i].data(), ::narrow<int>(dst_pitch * height / sizeof(u128)) };
copy_pitched_src_to_dst(dst_span, as_const_span<const u128>(raw_src), src_pitch, width, height);
break;
}
case surface_color_format::w16z16y16x16:
{
gsl::span<u64> dst_span{ (u64*)result[i].data(), ::narrow<int>(dst_pitch * height / sizeof(u64)) };
copy_pitched_src_to_dst(dst_span, as_const_span<const u64>(raw_src), src_pitch, width, height);
break;
}
}
Traits::unmap_downloaded_buffer(download_data[i], std::forward<Args&&>(args)...);
}
return result;
}
/**
* Get bound color surface raw data.
*/
template <typename... Args>
std::array<std::vector<gsl::byte>, 2> get_depth_stencil_data(
surface_depth_format depth_format, size_t width, size_t height,
Args&& ...args
)
{
std::array<std::vector<gsl::byte>, 2> result = {};
if (std::get<0>(m_bound_depth_stencil) == 0)
return result;
size_t row_pitch = align(width * 4, 256);
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&&>(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&&>(args)...));
gsl::span<const gsl::byte> depth_buffer_raw_src = Traits::map_downloaded_buffer(depth_data, std::forward<Args&&>(args)...);
if (depth_format == surface_depth_format::z16)
{
result[0].resize(width * height * 2);
gsl::span<u16> dest{ (u16*)result[0].data(), ::narrow<int>(width * height) };
copy_pitched_src_to_dst(dest, as_const_span<const u16>(depth_buffer_raw_src), row_pitch, width, height);
}
if (depth_format == surface_depth_format::z24s8)
{
result[0].resize(width * height * 4);
gsl::span<u32> dest{ (u32*)result[0].data(), ::narrow<int>(width * height) };
copy_pitched_src_to_dst(dest, as_const_span<const u32>(depth_buffer_raw_src), row_pitch, width, height);
}
Traits::unmap_downloaded_buffer(depth_data, std::forward<Args&&>(args)...);
if (depth_format == surface_depth_format::z16)
return result;
gsl::span<const gsl::byte> stencil_buffer_raw_src = Traits::map_downloaded_buffer(stencil_data, std::forward<Args&&>(args)...);
result[1].resize(width * height);
gsl::span<u8> dest{ (u8*)result[1].data(), ::narrow<int>(width * height) };
copy_pitched_src_to_dst(dest, as_const_span<const u8>(stencil_buffer_raw_src), align(width, 256), width, height);
Traits::unmap_downloaded_buffer(stencil_data, std::forward<Args&&>(args)...);
return result;
return nullptr;
}
/**

View file

@ -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;

View file

@ -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)
{

View file

@ -461,16 +461,12 @@ void GLGSRender::init_buffers(rsx::framebuffer_creation_context context, bool sk
std::array<std::vector<gsl::byte>, 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<std::vector<gsl::byte>, 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()

View file

@ -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<gl::render_target> 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<GLenum, 4> 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<gl::render_target> 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<gl::render_target> &surface, size_t pitch)
@ -291,63 +289,47 @@ struct gl_render_target_traits
}
static
bool rtt_has_format_width_height(const std::unique_ptr<gl::render_target> &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<gl::render_target> &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<gl::render_target> &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<gl::render_target> &ds, rsx::surface_depth_format format, size_t width, size_t height, bool check_refs=false)
bool surface_matches_properties(
const std::unique_ptr<gl::render_target> &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<u8> 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<u8> 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<u8> issue_depth_download_command(gl::render_target* depth_stencil_buffer, rsx::surface_depth_format depth_format, size_t width, size_t height)
{
std::vector<u8> 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<u8> issue_stencil_download_command(gl::render_target*, size_t width, size_t height)
{
std::vector<u8> result(width * height * 4);
return result;
return int_surface_matches_properties(surface, internal_fmt, width, height, antialias, check_refs);
}
static
gsl::span<const gsl::byte> map_downloaded_buffer(const std::vector<u8> &buffer)
{
return{ reinterpret_cast<const gsl::byte*>(buffer.data()), ::narrow<int>(buffer.size()) };
}
static
void unmap_downloaded_buffer(const std::vector<u8> &)
{
}
static gl::render_target* get(const std::unique_ptr<gl::render_target> &in)
gl::render_target* get(const std::unique_ptr<gl::render_target> &in)
{
return in.get();
}

View file

@ -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)
{

View file

@ -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)
{
if (surface->aspect() == VK_IMAGE_ASPECT_COLOR_BIT)
{
surface->change_layout(cmd, VK_IMAGE_LAYOUT_COLOR_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)
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_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<vk::render_target> &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<vk::render_target> &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;
if (check_refs && surface->has_refs())
{
// Surface may still have read refs from data 'copy'
return false;
}
static bool ds_has_format_width_height(const std::unique_ptr<vk::render_target> &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))
{
//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;
}
return (surface->info.format == format &&
surface->get_spp() == get_format_sample_count(antialias) &&
surface->matches_dimensions((u16)width, (u16)height));
}
return false;
static bool surface_matches_properties(
const std::unique_ptr<vk::render_target> &surface,
surface_color_format format,
size_t width, size_t height,
rsx::surface_antialiasing antialias,
bool check_refs = false)
{
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_download_command(surface_type, surface_color_format, size_t /*width*/, size_t /*height*/, ...)
{
return nullptr;
}
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<const gsl::byte> map_downloaded_buffer(download_buffer_object, ...)
{
return {};
}
static void unmap_downloaded_buffer(download_buffer_object, ...)
static bool surface_matches_properties(
const std::unique_ptr<vk::render_target> &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<vk::render_target> &tex)