Merge yuzu-emu#12749
This commit is contained in:
		| @@ -106,6 +106,7 @@ add_library(common STATIC | |||||||
|     precompiled_headers.h |     precompiled_headers.h | ||||||
|     quaternion.h |     quaternion.h | ||||||
|     range_map.h |     range_map.h | ||||||
|  |     range_mutex.h | ||||||
|     reader_writer_queue.h |     reader_writer_queue.h | ||||||
|     ring_buffer.h |     ring_buffer.h | ||||||
|     ${CMAKE_CURRENT_BINARY_DIR}/scm_rev.cpp |     ${CMAKE_CURRENT_BINARY_DIR}/scm_rev.cpp | ||||||
|   | |||||||
							
								
								
									
										93
									
								
								src/common/range_mutex.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										93
									
								
								src/common/range_mutex.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,93 @@ | |||||||
|  | // SPDX-FileCopyrightText: 2024 yuzu Emulator Project | ||||||
|  | // SPDX-License-Identifier: GPL-2.0-or-later | ||||||
|  |  | ||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #include <condition_variable> | ||||||
|  | #include <mutex> | ||||||
|  |  | ||||||
|  | #include "common/intrusive_list.h" | ||||||
|  |  | ||||||
|  | namespace Common { | ||||||
|  |  | ||||||
|  | class ScopedRangeLock; | ||||||
|  |  | ||||||
|  | class RangeMutex { | ||||||
|  | public: | ||||||
|  |     explicit RangeMutex() = default; | ||||||
|  |     ~RangeMutex() = default; | ||||||
|  |  | ||||||
|  | private: | ||||||
|  |     friend class ScopedRangeLock; | ||||||
|  |  | ||||||
|  |     void Lock(ScopedRangeLock& l); | ||||||
|  |     void Unlock(ScopedRangeLock& l); | ||||||
|  |     bool HasIntersectionLocked(ScopedRangeLock& l); | ||||||
|  |  | ||||||
|  | private: | ||||||
|  |     std::mutex m_mutex; | ||||||
|  |     std::condition_variable m_cv; | ||||||
|  |  | ||||||
|  |     using LockList = Common::IntrusiveListBaseTraits<ScopedRangeLock>::ListType; | ||||||
|  |     LockList m_list; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | class ScopedRangeLock : public Common::IntrusiveListBaseNode<ScopedRangeLock> { | ||||||
|  | public: | ||||||
|  |     explicit ScopedRangeLock(RangeMutex& mutex, u64 address, u64 size) | ||||||
|  |         : m_mutex(mutex), m_address(address), m_size(size) { | ||||||
|  |         if (m_size > 0) { | ||||||
|  |             m_mutex.Lock(*this); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     ~ScopedRangeLock() { | ||||||
|  |         if (m_size > 0) { | ||||||
|  |             m_mutex.Unlock(*this); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     u64 GetAddress() const { | ||||||
|  |         return m_address; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     u64 GetSize() const { | ||||||
|  |         return m_size; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | private: | ||||||
|  |     RangeMutex& m_mutex; | ||||||
|  |     const u64 m_address{}; | ||||||
|  |     const u64 m_size{}; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | inline void RangeMutex::Lock(ScopedRangeLock& l) { | ||||||
|  |     std::unique_lock lk{m_mutex}; | ||||||
|  |     m_cv.wait(lk, [&] { return !HasIntersectionLocked(l); }); | ||||||
|  |     m_list.push_back(l); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | inline void RangeMutex::Unlock(ScopedRangeLock& l) { | ||||||
|  |     { | ||||||
|  |         std::scoped_lock lk{m_mutex}; | ||||||
|  |         m_list.erase(m_list.iterator_to(l)); | ||||||
|  |     } | ||||||
|  |     m_cv.notify_all(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | inline bool RangeMutex::HasIntersectionLocked(ScopedRangeLock& l) { | ||||||
|  |     const auto cur_begin = l.GetAddress(); | ||||||
|  |     const auto cur_last = l.GetAddress() + l.GetSize() - 1; | ||||||
|  |  | ||||||
|  |     for (const auto& other : m_list) { | ||||||
|  |         const auto other_begin = other.GetAddress(); | ||||||
|  |         const auto other_last = other.GetAddress() + other.GetSize() - 1; | ||||||
|  |  | ||||||
|  |         if (cur_begin <= other_last && other_begin <= cur_last) { | ||||||
|  |             return true; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return false; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | } // namespace Common | ||||||
| @@ -10,6 +10,7 @@ | |||||||
| #include <mutex> | #include <mutex> | ||||||
|  |  | ||||||
| #include "common/common_types.h" | #include "common/common_types.h" | ||||||
|  | #include "common/range_mutex.h" | ||||||
| #include "common/scratch_buffer.h" | #include "common/scratch_buffer.h" | ||||||
| #include "common/virtual_buffer.h" | #include "common/virtual_buffer.h" | ||||||
|  |  | ||||||
| @@ -204,7 +205,7 @@ private: | |||||||
|         (1ULL << (device_virtual_bits - page_bits)) / subentries; |         (1ULL << (device_virtual_bits - page_bits)) / subentries; | ||||||
|     using CachedPages = std::array<CounterEntry, num_counter_entries>; |     using CachedPages = std::array<CounterEntry, num_counter_entries>; | ||||||
|     std::unique_ptr<CachedPages> cached_pages; |     std::unique_ptr<CachedPages> cached_pages; | ||||||
|     std::mutex counter_guard; |     Common::RangeMutex counter_guard; | ||||||
|     std::mutex mapping_guard; |     std::mutex mapping_guard; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -508,12 +508,7 @@ void DeviceMemoryManager<Traits>::UnregisterProcess(Asid asid) { | |||||||
|  |  | ||||||
| template <typename Traits> | template <typename Traits> | ||||||
| void DeviceMemoryManager<Traits>::UpdatePagesCachedCount(DAddr addr, size_t size, s32 delta) { | void DeviceMemoryManager<Traits>::UpdatePagesCachedCount(DAddr addr, size_t size, s32 delta) { | ||||||
|     std::unique_lock<std::mutex> lk(counter_guard, std::defer_lock); |     Common::ScopedRangeLock lk(counter_guard, addr, size); | ||||||
|     const auto Lock = [&] { |  | ||||||
|         if (!lk) { |  | ||||||
|             lk.lock(); |  | ||||||
|         } |  | ||||||
|     }; |  | ||||||
|     u64 uncache_begin = 0; |     u64 uncache_begin = 0; | ||||||
|     u64 cache_begin = 0; |     u64 cache_begin = 0; | ||||||
|     u64 uncache_bytes = 0; |     u64 uncache_bytes = 0; | ||||||
| @@ -548,7 +543,6 @@ void DeviceMemoryManager<Traits>::UpdatePagesCachedCount(DAddr addr, size_t size | |||||||
|             } |             } | ||||||
|             uncache_bytes += Memory::YUZU_PAGESIZE; |             uncache_bytes += Memory::YUZU_PAGESIZE; | ||||||
|         } else if (uncache_bytes > 0) { |         } else if (uncache_bytes > 0) { | ||||||
|             Lock(); |  | ||||||
|             MarkRegionCaching(memory_device_inter, uncache_begin << Memory::YUZU_PAGEBITS, |             MarkRegionCaching(memory_device_inter, uncache_begin << Memory::YUZU_PAGEBITS, | ||||||
|                               uncache_bytes, false); |                               uncache_bytes, false); | ||||||
|             uncache_bytes = 0; |             uncache_bytes = 0; | ||||||
| @@ -559,7 +553,6 @@ void DeviceMemoryManager<Traits>::UpdatePagesCachedCount(DAddr addr, size_t size | |||||||
|             } |             } | ||||||
|             cache_bytes += Memory::YUZU_PAGESIZE; |             cache_bytes += Memory::YUZU_PAGESIZE; | ||||||
|         } else if (cache_bytes > 0) { |         } else if (cache_bytes > 0) { | ||||||
|             Lock(); |  | ||||||
|             MarkRegionCaching(memory_device_inter, cache_begin << Memory::YUZU_PAGEBITS, cache_bytes, |             MarkRegionCaching(memory_device_inter, cache_begin << Memory::YUZU_PAGEBITS, cache_bytes, | ||||||
|                               true); |                               true); | ||||||
|             cache_bytes = 0; |             cache_bytes = 0; | ||||||
| @@ -567,12 +560,10 @@ void DeviceMemoryManager<Traits>::UpdatePagesCachedCount(DAddr addr, size_t size | |||||||
|         vpage++; |         vpage++; | ||||||
|     } |     } | ||||||
|     if (uncache_bytes > 0) { |     if (uncache_bytes > 0) { | ||||||
|         Lock(); |  | ||||||
|         MarkRegionCaching(memory_device_inter, uncache_begin << Memory::YUZU_PAGEBITS, uncache_bytes, |         MarkRegionCaching(memory_device_inter, uncache_begin << Memory::YUZU_PAGEBITS, uncache_bytes, | ||||||
|                           false); |                           false); | ||||||
|     } |     } | ||||||
|     if (cache_bytes > 0) { |     if (cache_bytes > 0) { | ||||||
|         Lock(); |  | ||||||
|         MarkRegionCaching(memory_device_inter, cache_begin << Memory::YUZU_PAGEBITS, cache_bytes, |         MarkRegionCaching(memory_device_inter, cache_begin << Memory::YUZU_PAGEBITS, cache_bytes, | ||||||
|                           true); |                           true); | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -1093,6 +1093,20 @@ bool Memory::InvalidateNCE(Common::ProcessAddress vaddr, size_t size) { | |||||||
|         [&] { rasterizer = true; }); |         [&] { rasterizer = true; }); | ||||||
|     if (rasterizer) { |     if (rasterizer) { | ||||||
|         impl->InvalidateGPUMemory(ptr, size); |         impl->InvalidateGPUMemory(ptr, size); | ||||||
|  |  | ||||||
|  |         const auto type = impl->current_page_table->pointers[vaddr >> YUZU_PAGEBITS].Type(); | ||||||
|  |         if (type == Common::PageType::RasterizerCachedMemory) { | ||||||
|  |             // Check if device mapped. If not, this bugged and we can unmark. | ||||||
|  |             DAddr addr{}; | ||||||
|  |             Common::ScratchBuffer<u32> buffer; | ||||||
|  |             impl->gpu_device_memory->ApplyOpOnPointer(ptr, buffer, | ||||||
|  |                                                       [&](DAddr address) { addr = address; }); | ||||||
|  |  | ||||||
|  |             if (addr == 0) { | ||||||
|  |                 LOG_ERROR(HW_Memory, "Fixing unmapped cached region {:#x}", GetInteger(vaddr)); | ||||||
|  |                 impl->RasterizerMarkRegionCached(GetInteger(vaddr), size, false); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
| #ifdef __linux__ | #ifdef __linux__ | ||||||
|   | |||||||
| @@ -1546,7 +1546,10 @@ void BufferCache<P>::ImmediateUploadMemory([[maybe_unused]] Buffer& buffer, | |||||||
|             std::span<const u8> upload_span; |             std::span<const u8> upload_span; | ||||||
|             const DAddr device_addr = buffer.CpuAddr() + copy.dst_offset; |             const DAddr device_addr = buffer.CpuAddr() + copy.dst_offset; | ||||||
|             if (IsRangeGranular(device_addr, copy.size)) { |             if (IsRangeGranular(device_addr, copy.size)) { | ||||||
|                 upload_span = std::span(device_memory.GetPointer<u8>(device_addr), copy.size); |                 auto* const ptr = device_memory.GetPointer<u8>(device_addr); | ||||||
|  |                 if (ptr != nullptr) { | ||||||
|  |                     upload_span = std::span(ptr, copy.size); | ||||||
|  |                 } | ||||||
|             } else { |             } else { | ||||||
|                 if (immediate_buffer.empty()) { |                 if (immediate_buffer.empty()) { | ||||||
|                     immediate_buffer = ImmediateBuffer(largest_copy); |                     immediate_buffer = ImmediateBuffer(largest_copy); | ||||||
|   | |||||||
| @@ -243,10 +243,12 @@ void RendererOpenGL::LoadFBToScreenInfo(const Tegra::FramebufferConfig& framebuf | |||||||
|     const u64 size_in_bytes{Tegra::Texture::CalculateSize( |     const u64 size_in_bytes{Tegra::Texture::CalculateSize( | ||||||
|         true, bytes_per_pixel, framebuffer.stride, framebuffer.height, 1, block_height_log2, 0)}; |         true, bytes_per_pixel, framebuffer.stride, framebuffer.height, 1, block_height_log2, 0)}; | ||||||
|     const u8* const host_ptr{device_memory.GetPointer<u8>(framebuffer_addr)}; |     const u8* const host_ptr{device_memory.GetPointer<u8>(framebuffer_addr)}; | ||||||
|  |     if (host_ptr != nullptr) { | ||||||
|         const std::span<const u8> input_data(host_ptr, size_in_bytes); |         const std::span<const u8> input_data(host_ptr, size_in_bytes); | ||||||
|         Tegra::Texture::UnswizzleTexture(gl_framebuffer_data, input_data, bytes_per_pixel, |         Tegra::Texture::UnswizzleTexture(gl_framebuffer_data, input_data, bytes_per_pixel, | ||||||
|                                      framebuffer.width, framebuffer.height, 1, block_height_log2, |                                          framebuffer.width, framebuffer.height, 1, | ||||||
|                                      0); |                                          block_height_log2, 0); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); |     glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); | ||||||
|     glPixelStorei(GL_UNPACK_ROW_LENGTH, static_cast<GLint>(framebuffer.stride)); |     glPixelStorei(GL_UNPACK_ROW_LENGTH, static_cast<GLint>(framebuffer.stride)); | ||||||
|   | |||||||
| @@ -230,9 +230,11 @@ void BlitScreen::Draw(const Tegra::FramebufferConfig& framebuffer, | |||||||
|         const u64 tiled_size{Tegra::Texture::CalculateSize(true, bytes_per_pixel, |         const u64 tiled_size{Tegra::Texture::CalculateSize(true, bytes_per_pixel, | ||||||
|                                                            framebuffer.stride, framebuffer.height, |                                                            framebuffer.stride, framebuffer.height, | ||||||
|                                                            1, block_height_log2, 0)}; |                                                            1, block_height_log2, 0)}; | ||||||
|  |         if (host_ptr != nullptr) { | ||||||
|             Tegra::Texture::UnswizzleTexture( |             Tegra::Texture::UnswizzleTexture( | ||||||
|                 mapped_span.subspan(image_offset, linear_size), std::span(host_ptr, tiled_size), |                 mapped_span.subspan(image_offset, linear_size), std::span(host_ptr, tiled_size), | ||||||
|                 bytes_per_pixel, framebuffer.width, framebuffer.height, 1, block_height_log2, 0); |                 bytes_per_pixel, framebuffer.width, framebuffer.height, 1, block_height_log2, 0); | ||||||
|  |         } | ||||||
|  |  | ||||||
|         const VkBufferImageCopy copy{ |         const VkBufferImageCopy copy{ | ||||||
|             .bufferOffset = image_offset, |             .bufferOffset = image_offset, | ||||||
|   | |||||||
| @@ -1064,8 +1064,6 @@ public: | |||||||
|                 } |                 } | ||||||
|             }); |             }); | ||||||
|         } |         } | ||||||
|         auto* ptr = device_memory.GetPointer<u8>(new_query->dependant_address); |  | ||||||
|         ASSERT(ptr != nullptr); |  | ||||||
|  |  | ||||||
|         new_query->dependant_manage = must_manage_dependance; |         new_query->dependant_manage = must_manage_dependance; | ||||||
|         pending_flush_queries.push_back(index); |         pending_flush_queries.push_back(index); | ||||||
| @@ -1104,10 +1102,12 @@ public: | |||||||
|                 tfb_streamer.Free(query->dependant_index); |                 tfb_streamer.Free(query->dependant_index); | ||||||
|             } else { |             } else { | ||||||
|                 u8* pointer = device_memory.GetPointer<u8>(query->dependant_address); |                 u8* pointer = device_memory.GetPointer<u8>(query->dependant_address); | ||||||
|  |                 if (pointer != nullptr) { | ||||||
|                     u32 result; |                     u32 result; | ||||||
|                     std::memcpy(&result, pointer, sizeof(u32)); |                     std::memcpy(&result, pointer, sizeof(u32)); | ||||||
|                     num_vertices = static_cast<u64>(result) / query->stride; |                     num_vertices = static_cast<u64>(result) / query->stride; | ||||||
|                 } |                 } | ||||||
|  |             } | ||||||
|             query->value = [&]() -> u64 { |             query->value = [&]() -> u64 { | ||||||
|                 switch (query->topology) { |                 switch (query->topology) { | ||||||
|                 case Maxwell3D::Regs::PrimitiveTopology::Points: |                 case Maxwell3D::Regs::PrimitiveTopology::Points: | ||||||
| @@ -1360,7 +1360,9 @@ bool QueryCacheRuntime::HostConditionalRenderingCompareValues(VideoCommon::Looku | |||||||
|     const auto check_value = [&](DAddr address) { |     const auto check_value = [&](DAddr address) { | ||||||
|         u8* ptr = impl->device_memory.GetPointer<u8>(address); |         u8* ptr = impl->device_memory.GetPointer<u8>(address); | ||||||
|         u64 value{}; |         u64 value{}; | ||||||
|  |         if (ptr != nullptr) { | ||||||
|             std::memcpy(&value, ptr, sizeof(value)); |             std::memcpy(&value, ptr, sizeof(value)); | ||||||
|  |         } | ||||||
|         return value == 0; |         return value == 0; | ||||||
|     }; |     }; | ||||||
|     std::array<VideoCommon::LookupData*, 2> objects{&object_1, &object_2}; |     std::array<VideoCommon::LookupData*, 2> objects{&object_1, &object_2}; | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user