rsx: Surface cache restructuring

- Further improve aliased data preservation by unconditionally scanning.
  Its is possible for cache aliasing to occur when doing memory split.
- Also sets up for RCB/RDB implementation
This commit is contained in:
kd-11 2019-08-06 14:46:21 +03:00 committed by kd-11
parent 5817e2a359
commit dfe709d464
11 changed files with 256 additions and 186 deletions

View file

@ -896,4 +896,57 @@ u32 get_remap_encoding(const std::pair<std::array<u8, 4>, std::array<u8, 4>>& re
encode |= (remap.second[2] << 12); encode |= (remap.second[2] << 12);
encode |= (remap.second[3] << 14); encode |= (remap.second[3] << 14);
return encode; return encode;
}
std::pair<u32, bool> get_compatible_gcm_format(rsx::surface_color_format format)
{
switch (format)
{
case rsx::surface_color_format::r5g6b5:
return{ CELL_GCM_TEXTURE_R5G6B5, false };
case rsx::surface_color_format::x8r8g8b8_z8r8g8b8:
case rsx::surface_color_format::x8r8g8b8_o8r8g8b8:
case rsx::surface_color_format::a8r8g8b8:
return{ CELL_GCM_TEXTURE_A8R8G8B8, true }; //verified
case rsx::surface_color_format::x8b8g8r8_o8b8g8r8:
case rsx::surface_color_format::x8b8g8r8_z8b8g8r8:
case rsx::surface_color_format::a8b8g8r8:
return{ CELL_GCM_TEXTURE_A8R8G8B8, false };
case rsx::surface_color_format::w16z16y16x16:
return{ CELL_GCM_TEXTURE_W16_Z16_Y16_X16_FLOAT, true };
case rsx::surface_color_format::w32z32y32x32:
return{ CELL_GCM_TEXTURE_W32_Z32_Y32_X32_FLOAT, true };
case rsx::surface_color_format::x1r5g5b5_o1r5g5b5:
case rsx::surface_color_format::x1r5g5b5_z1r5g5b5:
return{ CELL_GCM_TEXTURE_A1R5G5B5, false };
case rsx::surface_color_format::b8:
return{ CELL_GCM_TEXTURE_B8, false };
case rsx::surface_color_format::g8b8:
return{ CELL_GCM_TEXTURE_G8B8, true };
case rsx::surface_color_format::x32:
return{ CELL_GCM_TEXTURE_X32_FLOAT, true }; //verified
default:
fmt::throw_exception("Unhandled surface format 0x%x", (u32)format);
}
}
std::pair<u32, bool> get_compatible_gcm_format(rsx::surface_depth_format format)
{
switch (format)
{
case rsx::surface_depth_format::z16:
return{ CELL_GCM_TEXTURE_DEPTH16, true };
case rsx::surface_depth_format::z24s8:
return{ CELL_GCM_TEXTURE_DEPTH24_D8, true };
default:
ASSUME(0);
}
} }

View file

@ -146,3 +146,9 @@ u32 get_format_packed_pitch(u32 format, u16 width, bool border = false, bool swi
* Reverse encoding * Reverse encoding
*/ */
u32 get_remap_encoding(const std::pair<std::array<u8, 4>, std::array<u8, 4>>& remap); u32 get_remap_encoding(const std::pair<std::array<u8, 4>, std::array<u8, 4>>& remap);
/**
* Get gcm texel layout. Returns <format, byteswapped>
*/
std::pair<u32, bool> get_compatible_gcm_format(rsx::surface_color_format format);
std::pair<u32, bool> get_compatible_gcm_format(rsx::surface_depth_format format);

View file

@ -311,7 +311,7 @@ namespace rsx
if (ignore) continue; if (ignore) continue;
this_address = surface->memory_tag_samples[0].first; this_address = surface->base_addr;
verify(HERE), this_address; verify(HERE), this_address;
} }
@ -363,6 +363,7 @@ namespace rsx
surface_storage_type new_surface_storage; surface_storage_type new_surface_storage;
surface_type old_surface = nullptr; surface_type old_surface = nullptr;
surface_type new_surface = nullptr; surface_type new_surface = nullptr;
bool do_intersection_test = true;
bool store = true; bool store = true;
address_range *storage_bounds; address_range *storage_bounds;
@ -404,10 +405,13 @@ namespace rsx
{ {
// Preserve memory outside the area to be inherited if needed // 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); split_surface_region<depth>(command_list, address, Traits::get(surface), (u16)width, (u16)height, bpp, antialias);
old_surface = Traits::get(surface);
} }
old_surface = Traits::get(surface); // This will be unconditionally moved to invalidated list shortly
Traits::notify_surface_invalidated(surface);
old_surface_storage = std::move(surface); old_surface_storage = std::move(surface);
primary_storage->erase(It); primary_storage->erase(It);
} }
} }
@ -428,10 +432,9 @@ namespace rsx
new_surface_storage = std::move(surface); new_surface_storage = std::move(surface);
Traits::notify_surface_reused(new_surface_storage); Traits::notify_surface_reused(new_surface_storage);
if (old_surface) if (old_surface_storage)
{ {
// Exchange this surface with the invalidated one // Exchange this surface with the invalidated one
Traits::notify_surface_invalidated(old_surface_storage);
surface = std::move(old_surface_storage); surface = std::move(old_surface_storage);
} }
else else
@ -449,10 +452,9 @@ namespace rsx
} }
// Check for stale storage // Check for stale storage
if (old_surface != nullptr && new_surface == nullptr) if (old_surface_storage)
{ {
// This was already determined to be invalid and is excluded from testing above // 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)); invalidated_resources.push_back(std::move(old_surface_storage));
} }
@ -463,36 +465,46 @@ namespace rsx
new_surface = Traits::get(new_surface_storage); 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())
{ {
// Remove and preserve if possible any overlapping/replaced surface from the other pool if (Traits::surface_is_pitch_compatible(aliased_surface->second, pitch))
auto aliased_surface = secondary_storage->find(address);
if (aliased_surface != secondary_storage->end())
{ {
if (Traits::surface_is_pitch_compatible(aliased_surface->second, pitch)) auto surface = Traits::get(aliased_surface->second);
{ split_surface_region<!depth>(command_list, address, surface, (u16)width, (u16)height, bpp, antialias);
old_surface = Traits::get(aliased_surface->second);
split_surface_region<!depth>(command_list, address, old_surface, (u16)width, (u16)height, bpp, antialias);
}
Traits::notify_surface_invalidated(aliased_surface->second); if (!old_surface || old_surface->last_use_tag < surface->last_use_tag)
invalidated_resources.push_back(std::move(aliased_surface->second)); {
secondary_storage->erase(aliased_surface); // TODO: This can leak data outside inherited bounds
old_surface = surface;
}
} }
Traits::notify_surface_invalidated(aliased_surface->second);
invalidated_resources.push_back(std::move(aliased_surface->second));
secondary_storage->erase(aliased_surface);
} }
bool do_intersection_test = true;
// Check if old_surface is 'new' and hopefully avoid intersection // Check if old_surface is 'new' and hopefully avoid intersection
if (old_surface && old_surface->last_use_tag >= write_tag) if (old_surface)
{ {
const auto new_area = new_surface->get_normalized_memory_area(); if (old_surface->last_use_tag < new_surface->last_use_tag)
const auto old_area = old_surface->get_normalized_memory_area();
if (new_area.x2 <= old_area.x2 && new_area.y2 <= old_area.y2)
{ {
do_intersection_test = false; // Can happen if aliasing occurs; a probable condition due to memory splitting
new_surface->set_old_contents(old_surface); // This is highly unlikely but is possible in theory
old_surface = nullptr;
}
else if (old_surface->last_use_tag >= write_tag)
{
const auto new_area = new_surface->get_normalized_memory_area();
const auto old_area = old_surface->get_normalized_memory_area();
if (new_area.x2 <= old_area.x2 && new_area.y2 <= old_area.y2)
{
do_intersection_test = false;
new_surface->set_old_contents(old_surface);
}
} }
} }
@ -507,7 +519,7 @@ namespace rsx
(*primary_storage)[address] = std::move(new_surface_storage); (*primary_storage)[address] = std::move(new_surface_storage);
} }
verify(HERE), new_surface->get_spp() == get_format_sample_count(antialias); verify(HERE), !old_surface_storage, new_surface->get_spp() == get_format_sample_count(antialias);
return new_surface; return new_surface;
} }
@ -831,7 +843,7 @@ namespace rsx
return result; return result;
} }
void on_write(u32 address = 0) void on_write(bool color, bool z, u32 address = 0)
{ {
if (!address) if (!address)
{ {
@ -839,14 +851,17 @@ namespace rsx
{ {
if (m_invalidate_on_write) if (m_invalidate_on_write)
{ {
for (int i = m_bound_render_targets_config.first, count = 0; if (color)
count < m_bound_render_targets_config.second;
++i, ++count)
{ {
m_bound_render_targets[i].second->on_invalidate_children(); for (int i = m_bound_render_targets_config.first, count = 0;
count < m_bound_render_targets_config.second;
++i, ++count)
{
m_bound_render_targets[i].second->on_invalidate_children();
}
} }
if (m_bound_depth_stencil.first) if (z && m_bound_depth_stencil.first)
{ {
m_bound_depth_stencil.second->on_invalidate_children(); m_bound_depth_stencil.second->on_invalidate_children();
} }
@ -860,33 +875,39 @@ namespace rsx
} }
// Tag all available surfaces // Tag all available surfaces
for (int i = m_bound_render_targets_config.first, count = 0; if (color)
count < m_bound_render_targets_config.second;
++i, ++count)
{ {
m_bound_render_targets[i].second->on_write(write_tag); for (int i = m_bound_render_targets_config.first, count = 0;
count < m_bound_render_targets_config.second;
++i, ++count)
{
m_bound_render_targets[i].second->on_write(write_tag);
}
} }
if (m_bound_depth_stencil.first) if (z && m_bound_depth_stencil.first)
{ {
m_bound_depth_stencil.second->on_write(write_tag); m_bound_depth_stencil.second->on_write(write_tag);
} }
} }
else else
{ {
for (int i = m_bound_render_targets_config.first, count = 0; if (color)
count < m_bound_render_targets_config.second;
++i, ++count)
{ {
if (m_bound_render_targets[i].first != address) for (int i = m_bound_render_targets_config.first, count = 0;
count < m_bound_render_targets_config.second;
++i, ++count)
{ {
continue; if (m_bound_render_targets[i].first != address)
} {
continue;
}
m_bound_render_targets[i].second->on_write(write_tag); m_bound_render_targets[i].second->on_write(write_tag);
}
} }
if (m_bound_depth_stencil.first == address) if (z && m_bound_depth_stencil.first == address)
{ {
m_bound_depth_stencil.second->on_write(write_tag); m_bound_depth_stencil.second->on_write(write_tag);
} }

View file

@ -6,6 +6,8 @@
#include "TextureUtils.h" #include "TextureUtils.h"
#include "../rsx_utils.h" #include "../rsx_utils.h"
#define ENABLE_SURFACE_CACHE_DEBUG 0
namespace rsx namespace rsx
{ {
enum surface_state_flags : u32 enum surface_state_flags : u32
@ -128,7 +130,13 @@ namespace rsx
struct render_target_descriptor struct render_target_descriptor
{ {
u64 last_use_tag = 0; // tag indicating when this block was last confirmed to have been written to u64 last_use_tag = 0; // tag indicating when this block was last confirmed to have been written to
std::array<std::pair<u32, u64>, 5> memory_tag_samples; u64 base_addr = 0;
#if (ENABLE_SURFACE_CACHE_DEBUG)
u64 memory_hash = 0;
#else
std::array<std::pair<u32, u64>, 3> memory_tag_samples;
#endif
std::vector<deferred_clipped_region<image_storage_type>> old_contents; std::vector<deferred_clipped_region<image_storage_type>> old_contents;
@ -286,27 +294,102 @@ namespace rsx
return (state_flags != rsx::surface_state_flags::ready) || !old_contents.empty(); return (state_flags != rsx::surface_state_flags::ready) || !old_contents.empty();
} }
bool test() const #if (ENABLE_SURFACE_CACHE_DEBUG)
u64 hash_block() const
{ {
if (dirty()) const auto padding = (rsx_pitch - native_pitch) / 8;
const auto row_length = (native_pitch) / 8;
auto num_rows = (surface_height * samples_y);
auto ptr = reinterpret_cast<u64*>(vm::g_sudo_addr + base_addr);
auto col = row_length;
u64 result = 0;
while (num_rows--)
{ {
// TODO while (col--)
// Should RCB or mem-sync (inherit previous mem) to init memory {
LOG_TODO(RSX, "Resource used before memory initialization"); result ^= *ptr++;
}
ptr += padding;
col = row_length;
} }
// Tags are tested in an X pattern return result;
for (const auto &tag : memory_tag_samples) }
{
if (!tag.first)
break;
if (tag.second != *reinterpret_cast<u64*>(vm::g_sudo_addr + tag.first)) void queue_tag(u32 address)
{
base_addr = address;
}
void sync_tag()
{
memory_hash = hash_block();
}
void shuffle_tag()
{
memory_hash = ~memory_hash;
}
bool test() const
{
return hash_block() == memory_hash;
}
#else
void queue_tag(u32 address)
{
base_addr = address;
const u32 size_x = (native_pitch > 8)? (native_pitch - 8) : 0u;
const u32 size_y = u32(surface_height * samples_y) - 1u;
const position2u samples[] =
{
// NOTE: Sorted by probability to catch dirty flag
{0, 0},
{size_x, size_y},
{size_x / 2, size_y / 2},
// Auxilliary, highly unlikely to ever catch anything
// NOTE: Currently unused as length of samples is truncated to 3
{size_x, 0},
{0, size_y},
};
for (int n = 0; n < memory_tag_samples.size(); ++n)
{
const auto sample_offset = (samples[n].y * rsx_pitch) + samples[n].x;
memory_tag_samples[n].first = (sample_offset + base_addr);
}
}
void sync_tag()
{
for (auto &e : memory_tag_samples)
{
e.second = *reinterpret_cast<u64*>(vm::g_sudo_addr + e.first);
}
}
void shuffle_tag()
{
memory_tag_samples[0].second = memory_tag_samples[0].second;
}
bool test()
{
for (auto &e : memory_tag_samples)
{
if (e.second != *reinterpret_cast<u64*>(vm::g_sudo_addr + e.first))
return false; return false;
} }
return true; return true;
} }
#endif
void clear_rw_barrier() void clear_rw_barrier()
{ {
@ -415,51 +498,6 @@ namespace rsx
} }
} }
void queue_tag(u32 address)
{
for (unsigned i = 0; i < memory_tag_samples.size(); ++i)
{
if (LIKELY(i))
memory_tag_samples[i].first = 0;
else
memory_tag_samples[i].first = address; // Top left
}
const u32 pitch = get_native_pitch();
if (UNLIKELY(pitch < 16))
{
// Not enough area to gather samples if pitch is too small
return;
}
// Top right corner
memory_tag_samples[1].first = address + pitch - 8;
if (const u32 h = get_surface_height(); h > 1)
{
// Last row
const u32 pitch2 = get_rsx_pitch();
const u32 last_row_offset = pitch2 * (h - 1);
memory_tag_samples[2].first = address + last_row_offset; // Bottom left corner
memory_tag_samples[3].first = address + last_row_offset + pitch - 8; // Bottom right corner
// Centroid
const u32 center_row_offset = pitch2 * (h / 2);
memory_tag_samples[4].first = address + center_row_offset + pitch / 2;
}
}
void sync_tag()
{
for (auto &tag : memory_tag_samples)
{
if (!tag.first)
break;
tag.second = *reinterpret_cast<u64*>(vm::g_sudo_addr + tag.first);
}
}
void on_write(u64 write_tag = 0, rsx::surface_state_flags resolve_flags = surface_state_flags::require_resolve) void on_write(u64 write_tag = 0, rsx::surface_state_flags resolve_flags = surface_state_flags::require_resolve)
{ {
if (write_tag) if (write_tag)
@ -516,7 +554,7 @@ namespace rsx
rsx::address_range get_memory_range() const rsx::address_range get_memory_range() const
{ {
const u32 internal_height = get_surface_height(rsx::surface_metrics::samples); const u32 internal_height = get_surface_height(rsx::surface_metrics::samples);
return rsx::address_range::start_length(memory_tag_samples[0].first, internal_height * get_rsx_pitch()); return rsx::address_range::start_length(base_addr, internal_height * get_rsx_pitch());
} }
template <typename T> template <typename T>

View file

@ -1609,8 +1609,6 @@ namespace rsx
return; return;
} }
section.surface->read_barrier(cmd);
// How much of this slice to read? // How much of this slice to read?
int rebased = int(section.dst_y) - slice_begin; int rebased = int(section.dst_y) - slice_begin;
const auto src_x = section.src_x; const auto src_x = section.src_x;
@ -2444,8 +2442,6 @@ namespace rsx
if (src_is_render_target) if (src_is_render_target)
{ {
src_subres.surface->read_barrier(cmd);
const auto surf = src_subres.surface; const auto surf = src_subres.surface;
const auto bpp = surf->get_bpp(); const auto bpp = surf->get_bpp();
if (bpp != src_bpp) if (bpp != src_bpp)
@ -2460,9 +2456,6 @@ namespace rsx
if (dst_is_render_target) if (dst_is_render_target)
{ {
// Full barrier is required in case of partial transfers
dst_subres.surface->read_barrier(cmd);
auto bpp = dst_subres.surface->get_bpp(); auto bpp = dst_subres.surface->get_bpp();
if (bpp != dst_bpp) if (bpp != dst_bpp)
{ {

View file

@ -626,7 +626,7 @@ void GLGSRender::end()
} }
} while (rsx::method_registers.current_draw_clause.next()); } while (rsx::method_registers.current_draw_clause.next());
m_rtts.on_write(); m_rtts.on_write(rsx::method_registers.color_write_enabled(), rsx::method_registers.depth_write_enabled());
m_attrib_ring_buffer->notify(); m_attrib_ring_buffer->notify();
m_index_ring_buffer->notify(); m_index_ring_buffer->notify();
@ -1152,7 +1152,7 @@ void GLGSRender::clear_surface(u32 arg)
if (require_mem_load) ds->write_barrier(cmd); if (require_mem_load) ds->write_barrier(cmd);
// Memory has been initialized // Memory has been initialized
m_rtts.on_write(std::get<0>(m_rtts.m_bound_depth_stencil)); m_rtts.on_write(false, true);
} }
} }
@ -1189,7 +1189,7 @@ void GLGSRender::clear_surface(u32 arg)
if (const auto address = rtt.first) if (const auto address = rtt.first)
{ {
if (require_mem_load) rtt.second->write_barrier(cmd); if (require_mem_load) rtt.second->write_barrier(cmd);
m_rtts.on_write(address); m_rtts.on_write(true, false, address);
} }
} }

View file

@ -122,51 +122,6 @@ namespace vk
} }
} }
std::pair<u32, bool> get_compatible_gcm_format(rsx::surface_color_format color_format)
{
switch (color_format)
{
case rsx::surface_color_format::r5g6b5:
return{ CELL_GCM_TEXTURE_R5G6B5, false };
case rsx::surface_color_format::a8r8g8b8:
return{ CELL_GCM_TEXTURE_A8R8G8B8, true }; //verified
case rsx::surface_color_format::a8b8g8r8:
return{ CELL_GCM_TEXTURE_A8R8G8B8, false };
case rsx::surface_color_format::x8b8g8r8_o8b8g8r8:
case rsx::surface_color_format::x8b8g8r8_z8b8g8r8:
return{ CELL_GCM_TEXTURE_A8R8G8B8, true };
case rsx::surface_color_format::x8r8g8b8_z8r8g8b8:
case rsx::surface_color_format::x8r8g8b8_o8r8g8b8:
return{ CELL_GCM_TEXTURE_A8R8G8B8, false };
case rsx::surface_color_format::w16z16y16x16:
return{ CELL_GCM_TEXTURE_W16_Z16_Y16_X16_FLOAT, true };
case rsx::surface_color_format::w32z32y32x32:
return{ CELL_GCM_TEXTURE_W32_Z32_Y32_X32_FLOAT, true };
case rsx::surface_color_format::x1r5g5b5_o1r5g5b5:
case rsx::surface_color_format::x1r5g5b5_z1r5g5b5:
return{ CELL_GCM_TEXTURE_A1R5G5B5, false };
case rsx::surface_color_format::b8:
return{ CELL_GCM_TEXTURE_B8, false };
case rsx::surface_color_format::g8b8:
return{ CELL_GCM_TEXTURE_G8B8, true };
case rsx::surface_color_format::x32:
return{ CELL_GCM_TEXTURE_X32_FLOAT, true }; //verified
default:
return{ CELL_GCM_TEXTURE_A8R8G8B8, false };
}
}
VkLogicOp get_logic_op(rsx::logic_op op) VkLogicOp get_logic_op(rsx::logic_op op)
{ {
switch (op) switch (op)
@ -1778,7 +1733,7 @@ void VKGSRender::end()
close_render_pass(); close_render_pass();
vk::leave_uninterruptible(); vk::leave_uninterruptible();
m_rtts.on_write(); m_rtts.on_write(rsx::method_registers.color_write_enabled(), rsx::method_registers.depth_write_enabled());
rsx::thread::end(); rsx::thread::end();
} }
@ -2079,7 +2034,7 @@ void VKGSRender::clear_surface(u32 mask)
if (const auto address = rtt.first) if (const auto address = rtt.first)
{ {
if (require_mem_load) rtt.second->write_barrier(*m_current_command_buffer); if (require_mem_load) rtt.second->write_barrier(*m_current_command_buffer);
m_rtts.on_write(address); m_rtts.on_write(true, false, address);
} }
} }
} }
@ -2088,10 +2043,10 @@ void VKGSRender::clear_surface(u32 mask)
if (depth_stencil_mask) if (depth_stencil_mask)
{ {
if (const auto address = m_rtts.m_bound_depth_stencil.first) if (m_rtts.m_bound_depth_stencil.first)
{ {
if (require_mem_load) m_rtts.m_bound_depth_stencil.second->write_barrier(*m_current_command_buffer); if (require_mem_load) m_rtts.m_bound_depth_stencil.second->write_barrier(*m_current_command_buffer);
m_rtts.on_write(address); m_rtts.on_write(false, true);
clear_descriptors.push_back({ (VkImageAspectFlags)depth_stencil_mask, 0, depth_stencil_clear_values }); clear_descriptors.push_back({ (VkImageAspectFlags)depth_stencil_mask, 0, depth_stencil_clear_values });
} }
} }
@ -2762,22 +2717,9 @@ void VKGSRender::update_vertex_env(u32 id, const vk::vertex_upload_info& vertex_
m_vertex_layout_ring_info.unmap(); m_vertex_layout_ring_info.unmap();
} }
void VKGSRender::init_buffers(rsx::framebuffer_creation_context context, bool skip_reading) void VKGSRender::init_buffers(rsx::framebuffer_creation_context context, bool)
{ {
prepare_rtts(context); prepare_rtts(context);
if (!skip_reading)
{
read_buffers();
}
}
void VKGSRender::read_buffers()
{
}
void VKGSRender::write_buffers()
{
} }
void VKGSRender::close_and_submit_command_buffer(VkFence fence, VkSemaphore wait_semaphore, VkSemaphore signal_semaphore, VkPipelineStageFlags pipeline_stage_flags) void VKGSRender::close_and_submit_command_buffer(VkFence fence, VkSemaphore wait_semaphore, VkSemaphore signal_semaphore, VkPipelineStageFlags pipeline_stage_flags)
@ -2948,7 +2890,7 @@ void VKGSRender::prepare_rtts(rsx::framebuffer_creation_context context)
flush_command_queue(); flush_command_queue();
} }
const auto color_fmt_info = vk::get_compatible_gcm_format(layout.color_format); const auto color_fmt_info = get_compatible_gcm_format(layout.color_format);
for (u8 index : m_draw_buffers) for (u8 index : m_draw_buffers)
{ {
if (!m_surface_info[index].address || !m_surface_info[index].pitch) continue; if (!m_surface_info[index].address || !m_surface_info[index].pitch) continue;
@ -3003,7 +2945,7 @@ void VKGSRender::prepare_rtts(rsx::framebuffer_creation_context context)
{ {
if (!g_cfg.video.write_color_buffers) continue; if (!g_cfg.video.write_color_buffers) continue;
auto info = vk::get_compatible_gcm_format(surface->get_surface_color_format()); auto info = get_compatible_gcm_format(surface->get_surface_color_format());
gcm_format = info.first; gcm_format = info.first;
swap_bytes = info.second; swap_bytes = info.second;
} }

View file

@ -458,8 +458,6 @@ private:
public: public:
void init_buffers(rsx::framebuffer_creation_context context, bool skip_reading = false); void init_buffers(rsx::framebuffer_creation_context context, bool skip_reading = false);
void read_buffers();
void write_buffers();
void set_viewport(); void set_viewport();
void set_scissor(bool clip_viewport); void set_scissor(bool clip_viewport);
void bind_viewport(); void bind_viewport();

View file

@ -19,6 +19,10 @@ namespace vk
std::unordered_map<u32, std::unique_ptr<image>> g_typeless_textures; std::unordered_map<u32, std::unique_ptr<image>> g_typeless_textures;
std::unordered_map<u32, std::unique_ptr<vk::compute_task>> g_compute_tasks; std::unordered_map<u32, std::unique_ptr<vk::compute_task>> g_compute_tasks;
// General purpose upload heap
// TODO: Clean this up and integrate cleanly with VKGSRender
data_heap g_upload_heap;
// Garbage collection // Garbage collection
std::vector<std::unique_ptr<image>> g_deleted_typeless_textures; std::vector<std::unique_ptr<image>> g_deleted_typeless_textures;
@ -219,6 +223,16 @@ namespace vk
return g_scratch_buffer.get(); return g_scratch_buffer.get();
} }
data_heap* get_upload_heap()
{
if (!g_upload_heap.heap)
{
g_upload_heap.create(VK_BUFFER_USAGE_TRANSFER_SRC_BIT, 64 * 0x100000, "auxilliary upload heap");
}
return &g_upload_heap;
}
void acquire_global_submit_lock() void acquire_global_submit_lock()
{ {
g_submit_mutex.lock(); g_submit_mutex.lock();
@ -241,6 +255,8 @@ namespace vk
{ {
vk::reset_compute_tasks(); vk::reset_compute_tasks();
vk::reset_resolve_resources(); vk::reset_resolve_resources();
g_upload_heap.reset_allocation_stats();
} }
void destroy_global_resources() void destroy_global_resources()
@ -254,6 +270,7 @@ namespace vk
g_null_texture.reset(); g_null_texture.reset();
g_null_image_view.reset(); g_null_image_view.reset();
g_scratch_buffer.reset(); g_scratch_buffer.reset();
g_upload_heap.destroy();
g_typeless_textures.clear(); g_typeless_textures.clear();
g_deleted_typeless_textures.clear(); g_deleted_typeless_textures.clear();

View file

@ -118,6 +118,7 @@ namespace vk
image_view* null_image_view(vk::command_buffer&); image_view* null_image_view(vk::command_buffer&);
image* get_typeless_helper(VkFormat format, u32 requested_width, u32 requested_height); image* get_typeless_helper(VkFormat format, u32 requested_width, u32 requested_height);
buffer* get_scratch_buffer(); buffer* get_scratch_buffer();
data_heap* get_upload_heap();
memory_type_mapping get_memory_mapping(const physical_device& dev); memory_type_mapping get_memory_mapping(const physical_device& dev);
gpu_formats_support get_optimal_tiling_supported_formats(const physical_device& dev); gpu_formats_support get_optimal_tiling_supported_formats(const physical_device& dev);
@ -140,7 +141,7 @@ namespace vk
*/ */
void copy_mipmaped_image_using_buffer(VkCommandBuffer cmd, vk::image* dst_image, void copy_mipmaped_image_using_buffer(VkCommandBuffer cmd, vk::image* dst_image,
const std::vector<rsx_subresource_layout>& subresource_layout, int format, bool is_swizzled, u16 mipmap_count, const std::vector<rsx_subresource_layout>& subresource_layout, int format, bool is_swizzled, u16 mipmap_count,
VkImageAspectFlags flags, vk::data_heap &upload_heap); VkImageAspectFlags flags, vk::data_heap &upload_heap, u32 heap_align = 256);
//Other texture management helpers //Other texture management helpers
void change_image_layout(VkCommandBuffer cmd, VkImage image, VkImageLayout current_layout, VkImageLayout new_layout, const VkImageSubresourceRange& range); void change_image_layout(VkCommandBuffer cmd, VkImage image, VkImageLayout current_layout, VkImageLayout new_layout, const VkImageSubresourceRange& range);

View file

@ -510,7 +510,7 @@ namespace vk
void copy_mipmaped_image_using_buffer(VkCommandBuffer cmd, vk::image* dst_image, void copy_mipmaped_image_using_buffer(VkCommandBuffer cmd, vk::image* dst_image,
const std::vector<rsx_subresource_layout>& subresource_layout, int format, bool is_swizzled, u16 mipmap_count, const std::vector<rsx_subresource_layout>& subresource_layout, int format, bool is_swizzled, u16 mipmap_count,
VkImageAspectFlags flags, vk::data_heap &upload_heap) VkImageAspectFlags flags, vk::data_heap &upload_heap, u32 heap_align)
{ {
u32 mipmap_level = 0; u32 mipmap_level = 0;
u32 block_in_pixel = get_format_block_size_in_texel(format); u32 block_in_pixel = get_format_block_size_in_texel(format);
@ -518,7 +518,8 @@ namespace vk
for (const rsx_subresource_layout &layout : subresource_layout) for (const rsx_subresource_layout &layout : subresource_layout)
{ {
u32 row_pitch = align(layout.width_in_block * block_size_in_bytes, 256); u32 row_pitch = (((layout.width_in_block * block_size_in_bytes) + heap_align - 1) / heap_align) * heap_align;
if (heap_align != 256) verify(HERE), row_pitch == heap_align;
u32 image_linear_size = row_pitch * layout.height_in_block * layout.depth; u32 image_linear_size = row_pitch * layout.height_in_block * layout.depth;
//Map with extra padding bytes in case of realignment //Map with extra padding bytes in case of realignment
@ -527,7 +528,7 @@ namespace vk
VkBuffer buffer_handle = upload_heap.heap->value; VkBuffer buffer_handle = upload_heap.heap->value;
gsl::span<gsl::byte> mapped{ (gsl::byte*)mapped_buffer, ::narrow<int>(image_linear_size) }; gsl::span<gsl::byte> mapped{ (gsl::byte*)mapped_buffer, ::narrow<int>(image_linear_size) };
upload_texture_subresource(mapped, layout, format, is_swizzled, false, 256); upload_texture_subresource(mapped, layout, format, is_swizzled, false, heap_align);
upload_heap.unmap(); upload_heap.unmap();
VkBufferImageCopy copy_info = {}; VkBufferImageCopy copy_info = {};