diff --git a/rpcs3/Emu/RSX/Common/TextureUtils.cpp b/rpcs3/Emu/RSX/Common/TextureUtils.cpp index e31b094fc5..4719d6f118 100644 --- a/rpcs3/Emu/RSX/Common/TextureUtils.cpp +++ b/rpcs3/Emu/RSX/Common/TextureUtils.cpp @@ -896,4 +896,57 @@ u32 get_remap_encoding(const std::pair, std::array>& re encode |= (remap.second[2] << 12); encode |= (remap.second[3] << 14); return encode; +} + +std::pair 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 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); + } } \ No newline at end of file diff --git a/rpcs3/Emu/RSX/Common/TextureUtils.h b/rpcs3/Emu/RSX/Common/TextureUtils.h index a6ca6703b4..14a9b78791 100644 --- a/rpcs3/Emu/RSX/Common/TextureUtils.h +++ b/rpcs3/Emu/RSX/Common/TextureUtils.h @@ -146,3 +146,9 @@ u32 get_format_packed_pitch(u32 format, u16 width, bool border = false, bool swi * Reverse encoding */ u32 get_remap_encoding(const std::pair, std::array>& remap); + +/** + * Get gcm texel layout. Returns + */ +std::pair get_compatible_gcm_format(rsx::surface_color_format format); +std::pair get_compatible_gcm_format(rsx::surface_depth_format format); diff --git a/rpcs3/Emu/RSX/Common/surface_store.h b/rpcs3/Emu/RSX/Common/surface_store.h index 108acf573a..d567145933 100644 --- a/rpcs3/Emu/RSX/Common/surface_store.h +++ b/rpcs3/Emu/RSX/Common/surface_store.h @@ -311,7 +311,7 @@ namespace rsx if (ignore) continue; - this_address = surface->memory_tag_samples[0].first; + this_address = surface->base_addr; verify(HERE), this_address; } @@ -363,6 +363,7 @@ namespace rsx surface_storage_type new_surface_storage; surface_type old_surface = nullptr; surface_type new_surface = nullptr; + bool do_intersection_test = true; bool store = true; address_range *storage_bounds; @@ -404,10 +405,13 @@ namespace rsx { // 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); + 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); + primary_storage->erase(It); } } @@ -428,10 +432,9 @@ namespace rsx new_surface_storage = std::move(surface); Traits::notify_surface_reused(new_surface_storage); - if (old_surface) + if (old_surface_storage) { // Exchange this surface with the invalidated one - Traits::notify_surface_invalidated(old_surface_storage); surface = std::move(old_surface_storage); } else @@ -449,10 +452,9 @@ namespace rsx } // 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 - Traits::notify_surface_invalidated(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); } - 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 - auto aliased_surface = secondary_storage->find(address); - if (aliased_surface != secondary_storage->end()) + if (Traits::surface_is_pitch_compatible(aliased_surface->second, pitch)) { - if (Traits::surface_is_pitch_compatible(aliased_surface->second, pitch)) - { - old_surface = Traits::get(aliased_surface->second); - split_surface_region(command_list, address, old_surface, (u16)width, (u16)height, bpp, antialias); - } + auto surface = Traits::get(aliased_surface->second); + split_surface_region(command_list, address, surface, (u16)width, (u16)height, bpp, antialias); - Traits::notify_surface_invalidated(aliased_surface->second); - invalidated_resources.push_back(std::move(aliased_surface->second)); - secondary_storage->erase(aliased_surface); + if (!old_surface || old_surface->last_use_tag < surface->last_use_tag) + { + // 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 - if (old_surface && old_surface->last_use_tag >= write_tag) + if (old_surface) { - 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) + if (old_surface->last_use_tag < new_surface->last_use_tag) { - do_intersection_test = false; - new_surface->set_old_contents(old_surface); + // Can happen if aliasing occurs; a probable condition due to memory splitting + // 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); } - 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; } @@ -831,7 +843,7 @@ namespace rsx return result; } - void on_write(u32 address = 0) + void on_write(bool color, bool z, u32 address = 0) { if (!address) { @@ -839,14 +851,17 @@ namespace rsx { if (m_invalidate_on_write) { - for (int i = m_bound_render_targets_config.first, count = 0; - count < m_bound_render_targets_config.second; - ++i, ++count) + if (color) { - 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(); } @@ -860,33 +875,39 @@ namespace rsx } // Tag all available surfaces - for (int i = m_bound_render_targets_config.first, count = 0; - count < m_bound_render_targets_config.second; - ++i, ++count) + if (color) { - 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); } } else { - for (int i = m_bound_render_targets_config.first, count = 0; - count < m_bound_render_targets_config.second; - ++i, ++count) + if (color) { - 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); } diff --git a/rpcs3/Emu/RSX/Common/surface_utils.h b/rpcs3/Emu/RSX/Common/surface_utils.h index 7960a6155e..8bc96c217c 100644 --- a/rpcs3/Emu/RSX/Common/surface_utils.h +++ b/rpcs3/Emu/RSX/Common/surface_utils.h @@ -6,6 +6,8 @@ #include "TextureUtils.h" #include "../rsx_utils.h" +#define ENABLE_SURFACE_CACHE_DEBUG 0 + namespace rsx { enum surface_state_flags : u32 @@ -128,7 +130,13 @@ namespace rsx struct render_target_descriptor { u64 last_use_tag = 0; // tag indicating when this block was last confirmed to have been written to - std::array, 5> memory_tag_samples; + u64 base_addr = 0; + +#if (ENABLE_SURFACE_CACHE_DEBUG) + u64 memory_hash = 0; +#else + std::array, 3> memory_tag_samples; +#endif std::vector> old_contents; @@ -286,27 +294,102 @@ namespace rsx 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(vm::g_sudo_addr + base_addr); + + auto col = row_length; + u64 result = 0; + + while (num_rows--) { - // TODO - // Should RCB or mem-sync (inherit previous mem) to init memory - LOG_TODO(RSX, "Resource used before memory initialization"); + while (col--) + { + result ^= *ptr++; + } + + ptr += padding; + col = row_length; } - // Tags are tested in an X pattern - for (const auto &tag : memory_tag_samples) - { - if (!tag.first) - break; + return result; + } - if (tag.second != *reinterpret_cast(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(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(vm::g_sudo_addr + e.first)) return false; } return true; } +#endif 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(vm::g_sudo_addr + tag.first); - } - } - void on_write(u64 write_tag = 0, rsx::surface_state_flags resolve_flags = surface_state_flags::require_resolve) { if (write_tag) @@ -516,7 +554,7 @@ namespace rsx rsx::address_range get_memory_range() const { 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 diff --git a/rpcs3/Emu/RSX/Common/texture_cache.h b/rpcs3/Emu/RSX/Common/texture_cache.h index 71e0fa25db..146f2d43ea 100644 --- a/rpcs3/Emu/RSX/Common/texture_cache.h +++ b/rpcs3/Emu/RSX/Common/texture_cache.h @@ -1609,8 +1609,6 @@ namespace rsx return; } - section.surface->read_barrier(cmd); - // How much of this slice to read? int rebased = int(section.dst_y) - slice_begin; const auto src_x = section.src_x; @@ -2444,8 +2442,6 @@ namespace rsx if (src_is_render_target) { - src_subres.surface->read_barrier(cmd); - const auto surf = src_subres.surface; const auto bpp = surf->get_bpp(); if (bpp != src_bpp) @@ -2460,9 +2456,6 @@ namespace rsx 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(); if (bpp != dst_bpp) { diff --git a/rpcs3/Emu/RSX/GL/GLGSRender.cpp b/rpcs3/Emu/RSX/GL/GLGSRender.cpp index 53bc6fbe79..278f5d4376 100644 --- a/rpcs3/Emu/RSX/GL/GLGSRender.cpp +++ b/rpcs3/Emu/RSX/GL/GLGSRender.cpp @@ -626,7 +626,7 @@ void GLGSRender::end() } } 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_index_ring_buffer->notify(); @@ -1152,7 +1152,7 @@ void GLGSRender::clear_surface(u32 arg) if (require_mem_load) ds->write_barrier(cmd); // 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 (require_mem_load) rtt.second->write_barrier(cmd); - m_rtts.on_write(address); + m_rtts.on_write(true, false, address); } } diff --git a/rpcs3/Emu/RSX/VK/VKGSRender.cpp b/rpcs3/Emu/RSX/VK/VKGSRender.cpp index 16509a9d78..fd81810347 100644 --- a/rpcs3/Emu/RSX/VK/VKGSRender.cpp +++ b/rpcs3/Emu/RSX/VK/VKGSRender.cpp @@ -122,51 +122,6 @@ namespace vk } } - std::pair 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) { switch (op) @@ -1778,7 +1733,7 @@ void VKGSRender::end() close_render_pass(); 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(); } @@ -2079,7 +2034,7 @@ void VKGSRender::clear_surface(u32 mask) if (const auto address = rtt.first) { 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 (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); - m_rtts.on_write(address); + m_rtts.on_write(false, true); 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(); } -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); - - 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) @@ -2948,7 +2890,7 @@ void VKGSRender::prepare_rtts(rsx::framebuffer_creation_context context) 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) { 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; - 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; swap_bytes = info.second; } diff --git a/rpcs3/Emu/RSX/VK/VKGSRender.h b/rpcs3/Emu/RSX/VK/VKGSRender.h index 328c1ff27f..501d919b5e 100644 --- a/rpcs3/Emu/RSX/VK/VKGSRender.h +++ b/rpcs3/Emu/RSX/VK/VKGSRender.h @@ -458,8 +458,6 @@ private: public: void init_buffers(rsx::framebuffer_creation_context context, bool skip_reading = false); - void read_buffers(); - void write_buffers(); void set_viewport(); void set_scissor(bool clip_viewport); void bind_viewport(); diff --git a/rpcs3/Emu/RSX/VK/VKHelpers.cpp b/rpcs3/Emu/RSX/VK/VKHelpers.cpp index b975dd780e..9d577770e7 100644 --- a/rpcs3/Emu/RSX/VK/VKHelpers.cpp +++ b/rpcs3/Emu/RSX/VK/VKHelpers.cpp @@ -19,6 +19,10 @@ namespace vk std::unordered_map> g_typeless_textures; std::unordered_map> g_compute_tasks; + // General purpose upload heap + // TODO: Clean this up and integrate cleanly with VKGSRender + data_heap g_upload_heap; + // Garbage collection std::vector> g_deleted_typeless_textures; @@ -219,6 +223,16 @@ namespace vk 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() { g_submit_mutex.lock(); @@ -241,6 +255,8 @@ namespace vk { vk::reset_compute_tasks(); vk::reset_resolve_resources(); + + g_upload_heap.reset_allocation_stats(); } void destroy_global_resources() @@ -254,6 +270,7 @@ namespace vk g_null_texture.reset(); g_null_image_view.reset(); g_scratch_buffer.reset(); + g_upload_heap.destroy(); g_typeless_textures.clear(); g_deleted_typeless_textures.clear(); diff --git a/rpcs3/Emu/RSX/VK/VKHelpers.h b/rpcs3/Emu/RSX/VK/VKHelpers.h index ceac8c6a53..caeaaec3c7 100644 --- a/rpcs3/Emu/RSX/VK/VKHelpers.h +++ b/rpcs3/Emu/RSX/VK/VKHelpers.h @@ -118,6 +118,7 @@ namespace vk image_view* null_image_view(vk::command_buffer&); image* get_typeless_helper(VkFormat format, u32 requested_width, u32 requested_height); buffer* get_scratch_buffer(); + data_heap* get_upload_heap(); memory_type_mapping get_memory_mapping(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, const std::vector& 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 void change_image_layout(VkCommandBuffer cmd, VkImage image, VkImageLayout current_layout, VkImageLayout new_layout, const VkImageSubresourceRange& range); diff --git a/rpcs3/Emu/RSX/VK/VKTexture.cpp b/rpcs3/Emu/RSX/VK/VKTexture.cpp index a4bfcd2239..87ab340fac 100644 --- a/rpcs3/Emu/RSX/VK/VKTexture.cpp +++ b/rpcs3/Emu/RSX/VK/VKTexture.cpp @@ -510,7 +510,7 @@ namespace vk void copy_mipmaped_image_using_buffer(VkCommandBuffer cmd, vk::image* dst_image, const std::vector& 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 block_in_pixel = get_format_block_size_in_texel(format); @@ -518,7 +518,8 @@ namespace vk 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; //Map with extra padding bytes in case of realignment @@ -527,7 +528,7 @@ namespace vk VkBuffer buffer_handle = upload_heap.heap->value; gsl::span mapped{ (gsl::byte*)mapped_buffer, ::narrow(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(); VkBufferImageCopy copy_info = {};